]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
- call parking improvements (part of the siptransfer branch)
authorOlle Johansson <oej@edvina.net>
Tue, 18 Apr 2006 15:09:01 +0000 (15:09 +0000)
committerOlle Johansson <oej@edvina.net>
Tue, 18 Apr 2006 15:09:01 +0000 (15:09 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@21157 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index 1806c67c5ca0bde0bd560706acc6c58a312eb817..364b278767284d39adc83bc6c9910e66c55e55f8 100644 (file)
@@ -5505,16 +5505,17 @@ static int transmit_sip_request(struct sip_pvt *p,struct sip_request *req)
        return send_request(p, req, 0, p->ocseq);
 }
 
-/*! \brief Notify a transferring party of the status of transfer
- */
-static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message)
+/*! \brief Notify a transferring party of the status of transfer */
+static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate)
 {
        struct sip_request req;
-       char tmp[50];
+       char tmp[BUFSIZ/2];
+
        reqprep(&req, p, SIP_NOTIFY, 0, 1);
        snprintf(tmp, sizeof(tmp), "refer;id=%d", cseq);
        add_header(&req, "Event", tmp);
-       add_header(&req, "Subscription-state", "terminated;reason=noresource");
+       if (terminate)
+               add_header(&req, "Subscription-state", "terminated;reason=noresource");
        add_header(&req, "Content-Type", "message/sipfrag;version=2.0");
        add_header(&req, "Allow", ALLOWED_METHODS);
        add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
@@ -5523,6 +5524,11 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
        add_header_contentLength(&req, strlen(tmp));
        add_line(&req, tmp);
 
+
+       snprintf(tmp, sizeof(tmp), "SIP/2.0 %s\r\n", message);
+       add_header_contentLength(&req, strlen(tmp));
+       add_line(&req, tmp);
+
        
        if (!p->initreq.headers)
                initialize_initreq(p, &req);
@@ -10566,85 +10572,124 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
 /*! \brief Park SIP call support function */
 static void *sip_park_thread(void *stuff)
 {
-       struct ast_channel *chan1, *chan2;
+       struct ast_channel *transferee, *transferer;    /* Chan1: The transferee, Chan2: The transferer */
        struct sip_dual *d;
        struct sip_request req;
        int ext;
        int res;
+
        d = stuff;
-       chan1 = d->chan1;
-       chan2 = d->chan2;
+       transferee = d->chan1;
+       transferer = d->chan2;
        copy_request(&req, &d->req);
        free(d);
-       ast_channel_lock(chan1);
-       ast_do_masquerade(chan1);
-       ast_channel_unlock(chan1);
-       res = ast_park_call(chan1, chan2, 0, &ext);
-       /* Then hangup */
-       ast_hangup(chan2);
-       if (option_debug > 1)
-               ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext);
+       ast_channel_lock(transferee);
+       if (ast_do_masquerade(transferee)) {
+               ast_log(LOG_WARNING, "Masquerade failed.\n");
+               transmit_response(transferer->tech_pvt, "503 Internal error", &req);
+               ast_channel_unlock(transferee);
+               return NULL;
+       } 
+       ast_channel_unlock(transferee);
+
+       res = ast_park_call(transferee, transferer, 0, &ext);
+
+#ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
+       if (!res) {
+               transmit_message_with_text(transferer->tech_pvt, "Unable to park call.\n");
+       } else {
+               /* Then tell the transferer what happened */
+               sprintf(buf, "Call parked on extension '%d'", ext);
+               transmit_message_with_text(transferer->tech_pvt, buf);
+       }
+#endif
+
+       /* Any way back to the current call??? */
+       transmit_response(transferer->tech_pvt, "202 Accepted", &req);
+       if (!res)       {
+               /* Transfer succeeded */
+               transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "200 OK", 1);
+               transferer->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+               ast_hangup(transferer); /* This will cause a BYE */
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "SIP Call parked on extension '%d'\n", ext);
+       } else {
+               transmit_notify_with_sipfrag(transferer->tech_pvt, d->seqno, "503 Service Unavailable", 1);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "SIP Call parked failed \n");
+               /* Do not hangup call */
+       }
        return NULL;
 }
 
 /*! \brief Park a call */
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req)
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno)
 {
        struct sip_dual *d;
-       struct ast_channel *chan1m, *chan2m;
+       struct ast_channel *transferee, *transferer;
+               /* Chan2m: The transferer, chan1m: The transferee */
        pthread_t th;
-       chan1m = ast_channel_alloc(0);
-       chan2m = ast_channel_alloc(0);
-       if ((!chan2m) || (!chan1m)) {
-               if (chan1m) {
-                       chan1m->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
-                       ast_hangup(chan1m);
+
+       transferee = ast_channel_alloc(0);
+       transferer = ast_channel_alloc(0);
+       if ((!transferer) || (!transferee)) {
+               if (transferee) {
+                       transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+                       ast_hangup(transferee);
                }
-               if (chan2m) {
-                       chan2m->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
-                       ast_hangup(chan2m);
+               if (transferer) {
+                       transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+                       ast_hangup(transferer);
                }
                return -1;
        }
-       ast_string_field_build(chan1m, name, "Parking/%s", chan1->name);
+       ast_string_field_build(transferee, name,  "Parking/%s", chan1->name);
+
        /* Make formats okay */
-       chan1m->readformat = chan1->readformat;
-       chan1m->writeformat = chan1->writeformat;
-       ast_channel_masquerade(chan1m, chan1);
+       transferee->readformat = chan1->readformat;
+       transferee->writeformat = chan1->writeformat;
+       ast_channel_masquerade(transferee, chan1);
+
        /* Setup the extensions and such */
-       ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context));
-       ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten));
-       chan1m->priority = chan1->priority;
+       ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
+       ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
+       transferee->priority = chan1->priority;
                
        /* We make a clone of the peer channel too, so we can play
           back the announcement */
-       ast_string_field_build(chan2m, name, "SIPPeer/%s",chan2->name);
+       ast_string_field_build(transferer, name, "SIPPeer/%s", chan2->name);
+
        /* Make formats okay */
-       chan2m->readformat = chan2->readformat;
-       chan2m->writeformat = chan2->writeformat;
-       ast_channel_masquerade(chan2m, chan2);
+       transferer->readformat = chan2->readformat;
+       transferer->writeformat = chan2->writeformat;
+       ast_channel_masquerade(transferer, chan2);
+
        /* Setup the extensions and such */
-       ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context));
-       ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten));
-       chan2m->priority = chan2->priority;
-       ast_channel_lock(chan2m);
-       if (ast_do_masquerade(chan2m)) {
+       ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
+       ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
+       transferer->priority = chan2->priority;
+
+       ast_channel_lock(transferer);
+       if (ast_do_masquerade(transferer)) {
                ast_log(LOG_WARNING, "Masquerade failed :(\n");
-               ast_channel_unlock(chan2m);
-               chan2m->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
-               ast_hangup(chan2m);
+               ast_channel_unlock(transferer);
+               transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+               ast_hangup(transferer);
                return -1;
        }
-       ast_channel_unlock(chan2m);
+       ast_channel_unlock(transferer);
        if ((d = ast_calloc(1, sizeof(*d)))) {
                /* Save original request for followup */
                copy_request(&d->req, req);
-               d->chan1 = chan1m;
-               d->chan2 = chan2m;
-               if (!ast_pthread_create(&th, NULL, sip_park_thread, d))
+               d->chan1 = transferee;  /* Transferee */
+               d->chan2 = transferer;  /* Transferer */
+               d->seqno = seqno;
+               if (!ast_pthread_create(&th, NULL, sip_park_thread, d)) {
+                       free(d);
                        return 0;
+               }
                free(d);
-       }
+       } 
        return -1;
 }
 
@@ -11245,7 +11290,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
                                                            be accessible after the transfer! */
                                                        *nounlock = 1;
                                                        ast_channel_unlock(c);
-                                                       sip_park(transfer_to, c, req);
+                                                       sip_park(transfer_to, c, req, seqno);
                                                        nobye = 1;
                                                } else {
                                                        /* Must release c's lock now, because it will not longer
@@ -11262,7 +11307,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
                                ast_set_flag(&p->flags[0], SIP_GOTREFER);       
                        }
                        transmit_response(p, "202 Accepted", req);
-                       transmit_notify_with_sipfrag(p, seqno, "200 OK");
+                       transmit_notify_with_sipfrag(p, seqno, "200 OK", 1);
                        /* Always increment on a BYE */
                        if (!nobye) {
                                transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);