Fix queue URL passing (bug #3543)
[asterisk/asterisk.git] / channels / chan_local.c
index 8cc057b..288a418 100755 (executable)
@@ -12,7 +12,6 @@
  */
 
 #include <stdio.h>
-#include <pthread.h>
 #include <string.h>
 #include <asterisk/lock.h>
 #include <asterisk/channel.h>
@@ -49,12 +48,12 @@ static char *tdesc = "Local Proxy Channel Driver";
 static int capability = -1;
 
 static int usecnt =0;
-static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
+AST_MUTEX_DEFINE_STATIC(usecnt_lock);
 
 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
 
 /* Protect the interface list (of sip_pvt's) */
-static ast_mutex_t locallock = AST_MUTEX_INITIALIZER;
+AST_MUTEX_DEFINE_STATIC(locallock);
 
 static struct local_pvt {
        ast_mutex_t lock;                               /* Channel private lock */
@@ -74,22 +73,27 @@ static struct local_pvt {
 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)
 {
        struct ast_channel *other;
+retrylock:             
+       /* Recalculate outbound channel */
        if (isoutbound) {
                other = p->owner;
        } else {
                other = p->chan;
        }
-       if (!other)
-               return 0;
+       /* Set glare detection */
        p->glaredetect = 1;
-retrylock:             
        if (p->cancelqueue) {
                /* We had a glare on the hangup.  Forget all this business,
                return and destroy p.  */
                ast_mutex_unlock(&p->lock);
+               ast_mutex_destroy(&p->lock);
                free(p);
                return -1;
        }
+       if (!other) {
+               p->glaredetect = 0;
+               return 0;
+       }
        if (ast_mutex_trylock(&other->lock)) {
                /* Failed to lock.  Release main lock and try again */
                ast_mutex_unlock(&p->lock);
@@ -108,7 +112,7 @@ retrylock:
                ast_mutex_lock(&p->lock);
                goto retrylock;
        }
-       ast_queue_frame(other, f, 0);
+       ast_queue_frame(other, f);
        ast_mutex_unlock(&other->lock);
        p->glaredetect = 0;
        return 0;
@@ -117,9 +121,10 @@ retrylock:
 static int local_answer(struct ast_channel *ast)
 {
        struct local_pvt *p = ast->pvt->pvt;
-       int isoutbound = IS_OUTBOUND(ast, p);
+       int isoutbound;
        int res = -1;
        ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
        if (isoutbound) {
                /* Pass along answer since somebody answered us */
                struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
@@ -134,28 +139,28 @@ static void check_bridge(struct local_pvt *p, int isoutbound)
 {
        if (p->alreadymasqed || p->nooptimization)
                return;
-       if (isoutbound && p->chan && p->chan->bridge && p->owner) {
+       if (isoutbound && p->chan && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && p->owner && !p->owner->pvt->readq) {
                /* Masquerade bridged channel into owner */
                /* Lock everything we need, one by one, and give up if
                   we can't get everything.  Remember, we'll get another
                   chance in just a little bit */
-               if (!ast_mutex_trylock(&p->chan->bridge->lock)) {
+               if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
                        if (!ast_mutex_trylock(&p->owner->lock)) {
-                               ast_channel_masquerade(p->owner, p->chan->bridge);
+                               ast_channel_masquerade(p->owner, p->chan->_bridge);
                                p->alreadymasqed = 1;
                                ast_mutex_unlock(&p->owner->lock);
                        }
-                       ast_mutex_unlock(&p->chan->bridge->lock);
+                       ast_mutex_unlock(&(p->chan->_bridge)->lock);
                }
-       } else if (!isoutbound && p->owner && p->owner->bridge && p->chan) {
+       } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && !p->chan->pvt->readq) {
                /* Masquerade bridged channel into chan */
-               if (!ast_mutex_trylock(&p->owner->bridge->lock)) {
+               if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
                        if (!ast_mutex_trylock(&p->chan->lock)) {
-                               ast_channel_masquerade(p->chan, p->owner->bridge);
+                               ast_channel_masquerade(p->chan, p->owner->_bridge);
                                p->alreadymasqed = 1;
                                ast_mutex_unlock(&p->chan->lock);
                        }
-                       ast_mutex_unlock(&p->owner->bridge->lock);
+                       ast_mutex_unlock(&(p->owner->_bridge)->lock);
                }
        }
 }
@@ -170,11 +175,12 @@ static int local_write(struct ast_channel *ast, struct ast_frame *f)
 {
        struct local_pvt *p = ast->pvt->pvt;
        int res = -1;
-       int isoutbound = IS_OUTBOUND(ast, p);
+       int isoutbound;
 
 
        /* Just queue for delivery to the other side */
        ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
        res = local_queue_frame(p, isoutbound, f, ast);
        check_bridge(p, isoutbound);
        ast_mutex_unlock(&p->lock);
@@ -203,9 +209,10 @@ static int local_indicate(struct ast_channel *ast, int condition)
        struct local_pvt *p = ast->pvt->pvt;
        int res = -1;
        struct ast_frame f = { AST_FRAME_CONTROL, };
-       int isoutbound = IS_OUTBOUND(ast, p);
+       int isoutbound;
        /* Queue up a frame representing the indication as a control frame */
        ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
        f.subclass = condition;
        res = local_queue_frame(p, isoutbound, &f, ast);
        ast_mutex_unlock(&p->lock);
@@ -217,28 +224,61 @@ static int local_digit(struct ast_channel *ast, char digit)
        struct local_pvt *p = ast->pvt->pvt;
        int res = -1;
        struct ast_frame f = { AST_FRAME_DTMF, };
-       int isoutbound = IS_OUTBOUND(ast, p);
+       int isoutbound;
        ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
        f.subclass = digit;
        res = local_queue_frame(p, isoutbound, &f, ast);
        ast_mutex_unlock(&p->lock);
        return res;
 }
 
+static int local_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen)
+{
+       struct local_pvt *p = ast->pvt->pvt;
+       int res = -1;
+       struct ast_frame f = { AST_FRAME_HTML, };
+       int isoutbound;
+       ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
+       f.subclass = subclass;
+       f.data = data;
+       f.datalen = datalen;
+       res = local_queue_frame(p, isoutbound, &f, ast);
+       ast_mutex_unlock(&p->lock);
+       return res;
+}
+
 static int local_call(struct ast_channel *ast, char *dest, int timeout)
 {
        struct local_pvt *p = ast->pvt->pvt;
        int res;
        
        ast_mutex_lock(&p->lock);
-       if (p->owner->callerid)
-               p->chan->callerid = strdup(p->owner->callerid);
+       if (p->owner->cid.cid_num)
+               p->chan->cid.cid_num = strdup(p->owner->cid.cid_num);
+       else 
+               p->chan->cid.cid_num = NULL;
+
+       if (p->owner->cid.cid_name)
+               p->chan->cid.cid_name = strdup(p->owner->cid.cid_name);
+       else 
+               p->chan->cid.cid_name = NULL;
+
+       if (p->owner->cid.cid_rdnis)
+               p->chan->cid.cid_rdnis = strdup(p->owner->cid.cid_rdnis);
        else
-               p->chan->callerid = NULL;
-       if (p->owner->ani)
-               p->chan->ani = strdup(p->owner->ani);
+               p->chan->cid.cid_rdnis = NULL;
+
+       if (p->owner->cid.cid_ani)
+               p->chan->cid.cid_ani = strdup(p->owner->cid.cid_ani);
        else
-               p->chan->ani = NULL;
+               p->chan->cid.cid_ani = NULL;
+
+       strncpy(p->chan->language, p->owner->language, sizeof(p->chan->language) - 1);
+       strncpy(p->chan->accountcode, p->owner->accountcode, sizeof(p->chan->accountcode) - 1);
+       p->chan->cdrflags = p->owner->cdrflags;
+       
        p->launchedpbx = 1;
        /* Start switch on sub channel */
        res = ast_pbx_start(p->chan);
@@ -246,6 +286,7 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
        return res;
 }
 
+/*
 static void local_destroy(struct local_pvt *p)
 {
        struct local_pvt *cur, *prev = NULL;
@@ -257,6 +298,7 @@ static void local_destroy(struct local_pvt *p)
                                prev->next = cur->next;
                        else
                                locals = cur->next;
+                       ast_mutex_destroy(cur);
                        free(cur);
                        break;
                }
@@ -267,16 +309,18 @@ static void local_destroy(struct local_pvt *p)
        if (!cur)
                ast_log(LOG_WARNING, "Unable ot find local '%s@%s' in local list\n", p->exten, p->context);
 }
+*/
 
 static int local_hangup(struct ast_channel *ast)
 {
        struct local_pvt *p = ast->pvt->pvt;
-       int isoutbound = IS_OUTBOUND(ast, p);
+       int isoutbound;
        struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
        struct local_pvt *cur, *prev=NULL;
        struct ast_channel *ochan = NULL;
        int glaredetect;
        ast_mutex_lock(&p->lock);
+       isoutbound = IS_OUTBOUND(ast, p);
        if (isoutbound) {
                p->chan = NULL;
                p->launchedpbx = 0;
@@ -284,6 +328,10 @@ static int local_hangup(struct ast_channel *ast)
                p->owner = NULL;
        ast->pvt->pvt = NULL;
        
+       ast_mutex_lock(&usecnt_lock);
+       usecnt--;
+       ast_mutex_unlock(&usecnt_lock);
+       
        if (!p->owner && !p->chan) {
                /* Okay, done with the private part now, too. */
                glaredetect = p->glaredetect;
@@ -307,9 +355,14 @@ static int local_hangup(struct ast_channel *ast)
                        cur = cur->next;
                }
                ast_mutex_unlock(&locallock);
+               /* Grab / release lock just in case */
+               ast_mutex_lock(&p->lock);
+               ast_mutex_unlock(&p->lock);
                /* And destroy */
-               if (!glaredetect)
+               if (!glaredetect) {
+                       ast_mutex_destroy(&p->lock);
                        free(p);
+               }
                return 0;
        }
        if (p->chan && !p->launchedpbx)
@@ -349,7 +402,8 @@ static struct local_pvt *local_alloc(char *data, int format)
                        strncpy(tmp->context, "default", sizeof(tmp->context) - 1);
                tmp->reqformat = format;
                if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
-                       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->context, tmp->exten);
+                       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
+                       ast_mutex_destroy(&tmp->lock);
                        free(tmp);
                        tmp = NULL;
                } else {
@@ -398,6 +452,8 @@ static struct ast_channel *local_new(struct local_pvt *p, int state)
                tmp2->pvt->pvt = p;
                tmp->pvt->send_digit = local_digit;
                tmp2->pvt->send_digit = local_digit;
+               tmp->pvt->send_html = local_sendhtml;
+               tmp2->pvt->send_html = local_sendhtml;
                tmp->pvt->call = local_call;
                tmp2->pvt->call = local_call;
                tmp->pvt->hangup = local_hangup;
@@ -418,6 +474,7 @@ static struct ast_channel *local_new(struct local_pvt *p, int state)
                p->chan = tmp2;
                ast_mutex_lock(&usecnt_lock);
                usecnt++;
+               usecnt++;
                ast_mutex_unlock(&usecnt_lock);
                ast_update_use_count();
                strncpy(tmp->context, p->context, sizeof(tmp->context)-1);
@@ -431,7 +488,7 @@ static struct ast_channel *local_new(struct local_pvt *p, int state)
 }
 
 
-static struct ast_channel *local_request(char *type, int format, void *data)
+static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
 {
        struct local_pvt *p;
        struct ast_channel *chan = NULL;
@@ -445,7 +502,7 @@ static int locals_show(int fd, int argc, char **argv)
 {
        struct local_pvt *p;
 
-       if (argc != 2)
+       if (argc != 3)
                return RESULT_SHOWUSAGE;
        ast_mutex_lock(&locallock);
        p = locals;
@@ -462,11 +519,11 @@ static int locals_show(int fd, int argc, char **argv)
 }
 
 static char show_locals_usage[] = 
-"Usage: show locals\n"
-"       Provides summary information on locals.\n";
+"Usage: local show channels\n"
+"       Provides summary information on local channels.\n";
 
 static struct ast_cli_entry cli_show_locals = {
-       { "show", "locals", NULL }, locals_show, 
+       { "local", "show", "channels", NULL }, locals_show, 
        "Show status of local channels", show_locals_usage, NULL };
 
 int load_module()