Start on queueing strategies
authorMark Spencer <markster@digium.com>
Sun, 27 Jul 2003 01:55:22 +0000 (01:55 +0000)
committerMark Spencer <markster@digium.com>
Sun, 27 Jul 2003 01:55:22 +0000 (01:55 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1226 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_queue.c

index 5d8ca0c..fd5fb88 100755 (executable)
 
 #include <pthread.h>
 
+#define QUEUE_STRATEGY_RINGALL         0
+#define QUEUE_STRATEGY_ROUNDROBIN      1
+#define QUEUE_STRATEGY_LEASTRECENT     2
+#define QUEUE_STRATEGY_FEWESTCALLS     3
+#define QUEUE_STRATEGY_RANDOM          4
+
 #define DEFAULT_RETRY          5
 #define DEFAULT_TIMEOUT                15
 #define RECHECK                                1               /* Recheck every second to see we we're at the top yet */
@@ -91,7 +97,10 @@ static char *app_rqm_descrip =
 
 struct localuser {
        struct ast_channel *chan;
+       char numsubst[256];
+       char tech[40];
        int stillgoing;
+       int metric;
        int allowredirect_in;
        int allowredirect_out;
        int ringbackonly;
@@ -117,6 +126,7 @@ struct queue_ent {
 struct member {
        char tech[80];                          /* Technology */
        char loc[256];                          /* Location */
+       struct timeval lastcall;        /* When last successful call was hungup */
        struct member *next;            /* Next member */
 };
 
@@ -126,6 +136,7 @@ struct ast_call_queue {
        char moh[80];                   /* Name of musiconhold to be used */
        char announce[80];              /* Announcement to play */
        char context[80];               /* Announcement to play */
+       int strategy;                   /* Queueing strategy */
        int announcetimeout;    /* How often to announce their position */
        int count;                              /* How many entries are in the queue */
        int maxlen;                             /* Max number of entries in queue */
@@ -274,7 +285,7 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
        struct localuser *oo;
        while(outgoing) {
                /* Hangup any existing lines we have open */
-               if (outgoing->chan != exception)
+               if (outgoing->chan && (outgoing->chan != exception))
                        ast_hangup(outgoing->chan);
                oo = outgoing;
                outgoing=outgoing->next;
@@ -306,7 +317,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
                watchers[0] = in;
                while(o) {
                        /* Keep track of important channels */
-                       if (o->stillgoing) {
+                       if (o->stillgoing && o->chan) {
                                watchers[pos++] = o->chan;
                                found = 1;
                        }
@@ -439,6 +450,65 @@ static int wait_our_turn(struct queue_ent *qe)
        return res;
 }
 
+static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
+{
+       int res;
+       /* Request the peer */
+       tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
+       if (!tmp->chan) {                       /* If we can't, just go on to the next call */
+#if 0
+               ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
+#endif                 
+               if (qe->chan->cdr)
+                       ast_cdr_busy(qe->chan->cdr);
+               tmp->stillgoing = 0;
+               return 0;
+       }
+       tmp->chan->appl = "AppQueue";
+       tmp->chan->data = "(Outgoing Line)";
+       tmp->chan->whentohangup = 0;
+       if (tmp->chan->callerid)
+               free(tmp->chan->callerid);
+       if (tmp->chan->ani)
+               free(tmp->chan->ani);
+       if (qe->chan->callerid)
+               tmp->chan->callerid = strdup(qe->chan->callerid);
+       else
+               tmp->chan->callerid = NULL;
+       if (qe->chan->ani)
+               tmp->chan->ani = strdup(qe->chan->ani);
+       else
+               tmp->chan->ani = NULL;
+       /* Presense of ADSI CPE on outgoing channel follows ours */
+       tmp->chan->adsicpe = qe->chan->adsicpe;
+       /* Place the call, but don't wait on the answer */
+       res = ast_call(tmp->chan, tmp->numsubst, 0);
+       if (res) {
+               /* Again, keep going even if there's an error */
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
+               else if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->numsubst);
+               ast_hangup(tmp->chan);
+               tmp->chan = NULL;
+               tmp->stillgoing = 0;
+               return 0;
+       } else
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->numsubst);
+       return 0;
+}
+
+static int calc_metric(struct ast_call_queue *q, struct queue_ent *qe, struct localuser *tmp)
+{
+       switch (q->strategy) {
+       case QUEUE_STRATEGY_RINGALL:
+               ast_log(LOG_WARNING, "Can't calculate metric for ringall strategy\n");
+               break;
+       }
+       return 0;
+}
+
 static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url)
 {
        struct member *cur;
@@ -447,7 +517,6 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
        int allowredir_in=0;
        int allowredir_out=0;
        int allowdisconnect=0;
-       char numsubst[AST_MAX_EXTENSION];
        char restofit[AST_MAX_EXTENSION];
        char *newnum;
        struct ast_channel *peer;
@@ -469,6 +538,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
                        goto out;
                }
                memset(tmp, 0, sizeof(struct localuser));
+               tmp->stillgoing = -1;
                if (options) {
                        if (strchr(options, 't'))
                                tmp->allowredirect_in = 1;
@@ -488,83 +558,28 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri
                } else 
                        ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
 
-               strncpy(numsubst, cur->loc, sizeof(numsubst)-1);
+               strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
+               strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
                /* If we're dialing by extension, look at the extension to know what to dial */
-               if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
+               if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
                        strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
-                       snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", qe->chan->exten,restofit);
+                       snprintf(newnum, sizeof(tmp->numsubst) - (newnum - tmp->numsubst), "%s%s", qe->chan->exten,restofit);
                        if (option_debug)
-                               ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
-               }
-               /* Request the peer */
-               tmp->chan = ast_request(cur->tech, qe->chan->nativeformats, numsubst);
-               if (!tmp->chan) {
-                       /* If we can't, just go on to the next call */
-#if 0
-                       ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
-#endif                 
-                       if (qe->chan->cdr)
-                               ast_cdr_busy(qe->chan->cdr);
-                       free(tmp);
-                       cur = cur->next;
-                       continue;
-               }
-#if 0          
-               /* Don't honor call forwarding on a queue! */
-               if (strlen(tmp->chan->call_forward)) {
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
-                       /* Setup parameters */
-                       strncpy(chan->exten, tmp->chan->call_forward, sizeof(chan->exten));
-                       strncpy(chan->context, tmp->chan->context, sizeof(chan->context));
-                       chan->priority = 0;
-                       to = 0;
-                       ast_hangup(tmp->chan);
-                       free(tmp);
-                       cur = rest;
-                       break;
+                               ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->numsubst);
                }
-#endif         
-               tmp->chan->appl = "AppQueue";
-               tmp->chan->data = "(Outgoing Line)";
-               tmp->chan->whentohangup = 0;
-               if (tmp->chan->callerid)
-                       free(tmp->chan->callerid);
-               if (tmp->chan->ani)
-                       free(tmp->chan->ani);
-               if (qe->chan->callerid)
-                       tmp->chan->callerid = strdup(qe->chan->callerid);
-               else
-                       tmp->chan->callerid = NULL;
-               if (qe->chan->ani)
-                       tmp->chan->ani = strdup(qe->chan->ani);
+               /* Special case: If we ring everyone, go ahead and ring them, otherwise
+                  just calculate their metric for the appropriate strategy */
+               if (!qe->parent->strategy)
+                       ring_entry(qe, tmp);
                else
-                       tmp->chan->ani = NULL;
-               /* Presense of ADSI CPE on outgoing channel follows ours */
-               tmp->chan->adsicpe = qe->chan->adsicpe;
-               /* Place the call, but don't wait on the answer */
-               res = ast_call(tmp->chan, numsubst, 0);
-               if (res) {
-                       /* Again, keep going even if there's an error */
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
-                       else if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
-                       ast_hangup(tmp->chan);
-                       free(tmp);
-                       cur = cur->next;
-                       continue;
-               } else
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
+                       calc_metric(qe->parent, qe, tmp);
                /* Put them in the list of outgoing thingies...  We're ready now. 
                   XXX If we're forcibly removed, these outgoing calls won't get
                   hung up XXX */
-               tmp->stillgoing = -1;
                tmp->next = outgoing;
                outgoing = tmp;         
                /* If this line is up, don't try anybody else */
-               if (outgoing->chan->_state == AST_STATE_UP)
+               if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
                        break;
 
                cur = cur->next;