Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 5005)
+++ channels/chan_sip.c	(working copy)
@@ -242,7 +242,8 @@
 	XPIDF_XML,
 	DIALOG_INFO_XML,
 	CPIM_PIDF_XML,
-	PIDF_XML
+	PIDF_XML,
+	MWI_NOTIFICATION
 };
 
 static const struct cfsubscription_types {
@@ -256,7 +257,8 @@
 	{ DIALOG_INFO_XML, "dialog",   "application/dialog-info+xml", "dialog-info+xml" },
 	{ CPIM_PIDF_XML,   "presence", "application/cpim-pidf+xml",   "cpim-pidf+xml" },  /* RFC 3863 */
 	{ PIDF_XML,        "presence", "application/pidf+xml",        "pidf+xml" },       /* RFC 3863 */
-	{ XPIDF_XML,       "presence", "application/xpidf+xml",       "xpidf+xml" }       /* Pre-RFC 3863 with MS additions */
+	{ XPIDF_XML,       "presence", "application/xpidf+xml",       "xpidf+xml" },      /* Pre-RFC 3863 with MS additions */
+	{ MWI_NOTIFICATION,"message-summary", "application/simple-message-summary", "mwi" }	/* RFC 3842: Mailbox notification */
 };
 
 enum sipmethod {
@@ -727,6 +729,8 @@
 #define SIP_PAGE2_RT_FROMCONTACT	(1 << 4)
 #define SIP_PAGE2_DYNAMIC			(1 << 5)	/*!< Is this a dynamic peer? */
 
+#define SIP_PAGE2_SUBSCRIBEMWIONLY	(1 << 6)		/*!< Only issue MWI notification if subscribed */
+
 /* SIP packet flags */
 #define SIP_PKT_DEBUG				(1 << 0)    /*!< Debug this packet */
 #define SIP_PKT_WITH_TOTAG			(1 << 1)    /*!< This packet has a to-tag */
@@ -829,6 +833,7 @@
     struct cw_dsp *vad;            /*!< Voice Activation Detection dsp */
     
     struct sip_peer *peerpoke;        /*!< If this calls is to poke a peer, which one */
+    struct sip_peer *mwipeer;         /*!< If we have a MWI subscription, which peer */
     struct sip_registry *registry;        /*!< If this is a REGISTER call, to which registry */
     struct cw_rtp *rtp;            /*!< RTP Session */
     struct cw_rtp *vrtp;            /*!< Video RTP session */
@@ -987,6 +992,7 @@
     struct sockaddr_in defaddr;    /*!<  Default IP address, used until registration */
     struct cw_ha *ha;        /*!<  Access control list */
     struct cw_variable *chanvars;    /*!<  Variables to set for     channel created by user */
+    struct sip_pvt *mwipvt;    /*!< Subscription for MWI */
     int lastmsg;
 };
 
@@ -1128,6 +1134,7 @@
 static enum cw_bridge_result sip_bridge(struct cw_channel *c0, struct cw_channel *c1, int flag, struct cw_frame **fo,struct cw_channel **rc, int timeoutms); /* Function to bridge to SIP channels if T38 support enabled */
 static char *nat2str(int nat);
 static int cw_sip_ouraddrfor(struct in_addr *them, struct in_addr *us, struct sip_pvt *p);
+static int sip_send_mwi_to_peer(struct sip_peer *peer);
 
 
 /*! \brief Definition of this channel for PBX channel registration */
@@ -2491,6 +2498,9 @@
     /* Delete it, it needs to disappear */
     if (peer->call)
         sip_destroy(peer->call);
+
+    if (peer->mwipvt)		/* MWI subscription */
+        sip_destroy(peer->mwipvt);
     if (peer->chanvars)
     {
         cw_variables_destroy(peer->chanvars);
@@ -7015,7 +7025,11 @@
 
     if (sipmethod == SIP_NOTIFY && !cw_strlen_zero(p->theirtag)) {
     	/* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
-		snprintf(to, sizeof(to), "<sip:%s>;tag=%s", p->uri, p->theirtag);
+	/* Fix for double sip: on the to field */
+	char *urip = p->uri;
+	if(strncmp(p->uri, "sip:", 4) == 0)
+	    urip+=4;
+	snprintf(to, sizeof(to), "<sip:%s>;tag=%s", urip, p->theirtag);
     } else if (p->options && p->options->vxml_url) {
 	/* If there is a VXML URL append it to the SIP URL */
 	snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
@@ -9594,7 +9608,10 @@
                     }
                 }
                 if (mailbox)
+		{
                     snprintf(mailbox, mailboxlen, ",%s,", peer->mailbox);
+		    p->mwipeer = peer;
+		}
                 if (!cw_strlen_zero(peer->username))
                 {
                     cw_copy_string(p->username, peer->username, sizeof(p->username));
@@ -14003,8 +14020,22 @@
 
                 if (found)
                 {
+		    /* Only one message subscription allowed */
+		    if( p->mwipeer && p->mwipeer->mwipvt && p->mwipeer->mwipvt != p )
+			sip_destroy(p->mwipeer->mwipvt );
+		    p->mwipeer->mwipvt = p;
+		    p->subscribed = MWI_NOTIFICATION;
+		    p->expiry = atoi(get_header(req, "Expires"));
+
+		    /* If we are a renewal of existing sub, then cancel old destroy */
+		    if (p->autokillid > -1 )
+			sip_cancel_destroy(p);
+		    sip_scheddestroy(p, (p->expiry + 10)*1000);
+
                     transmit_response(p, "200 OK", req);
-                    cw_set_flag(p, SIP_NEEDDESTROY);
+		    CWOBJ_WRLOCK(p->mwipeer);
+		    sip_send_mwi_to_peer(p->mwipeer);
+		    CWOBJ_UNLOCK(p->mwipeer);
                 }
                 else
                 {
@@ -14518,40 +14549,50 @@
     /* Called with peerl lock, but releases it */
     struct sip_pvt *p;
     int newmsgs, oldmsgs;
+    int msgsummary;
 
+    time(&peer->lastmsgcheck);
+
+    /* If we need a subscription but don't have one then we return */
+    if (cw_test_flag(&peer->flags_page2, SIP_PAGE2_SUBSCRIBEMWIONLY) && !peer->mwipvt)
+	return 0;
+
     /* Check for messages */
     cw_app_messagecount(peer->mailbox, &newmsgs, &oldmsgs);
+    msgsummary = ((newmsgs > 0x7fff ? 0x7fff0000 : (newmsgs << 16)) | (oldmsgs > 0xffff ? 0xffff : oldmsgs));
     
-    time(&peer->lastmsgcheck);
-    
     /* Return now if it's the same thing we told them last time */
-    if (((newmsgs << 8) | (oldmsgs)) == peer->lastmsgssent)
+    if( msgsummary == peer->lastmsgssent)
     {
         return 0;
     }
-    
-    p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY);
-    if (!p)
-    {
-        cw_log(LOG_WARNING, "Unable to build sip pvt data for MWI\n");
-        return -1;
+    peer->lastmsgssent = msgsummary;
+
+    if(peer->mwipvt) {    
+	p = peer->mwipvt;
+    } else {
+        p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY);
+        if (!p)
+        {
+            cw_log(LOG_WARNING, "Unable to build sip pvt data for MWI\n");
+            return -1;
+        }
+        if (create_addr_from_peer(p, peer))
+        {
+            /* Maybe they're not registered, etc. */
+            sip_destroy(p);
+            return 0;
+        }
+        /* Recalculate our side, and recalculate Call ID */
+        if (cw_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip,p))
+            memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
+        build_via(p, p->via, sizeof(p->via));
+        build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
+	sip_scheddestroy(p, 15000);
     }
-    peer->lastmsgssent = ((newmsgs > 0x7fff ? 0x7fff0000 : (newmsgs << 16)) | (oldmsgs > 0xffff ? 0xffff : oldmsgs));
-    if (create_addr_from_peer(p, peer))
-    {
-        /* Maybe they're not registered, etc. */
-        sip_destroy(p);
-        return 0;
-    }
-    /* Recalculate our side, and recalculate Call ID */
-    if (cw_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip,p))
-        memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
-    build_via(p, p->via, sizeof(p->via));
-    build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
     /* Send MWI */
     cw_set_flag(p, SIP_OUTGOING);
     transmit_notify_with_mwi(p, newmsgs, oldmsgs, peer->vmexten);
-    sip_scheddestroy(p, 15000);
     return 0;
 }
 
@@ -15782,6 +15823,10 @@
         {
             cw_copy_string(peer->vmexten, v->value, sizeof(peer->vmexten));
         }
+	else if (!strcasecmp(v->name, "subscribemwi"))
+	{
+	    cw_set2_flag(&peer->flags_page2, cw_true(v->value), SIP_PAGE2_SUBSCRIBEMWIONLY);
+	}
         else if (!strcasecmp(v->name, "callgroup"))
         {
             peer->callgroup = cw_get_group(v->value);
