--- app_queue.c 2004-02-18 18:16:02.000000000 -0800 +++ shady_queue.c 2004-02-18 18:15:29.000000000 -0800 @@ -35,8 +35,6 @@ #include #include -#include "../astconf.h" - #include #define QUEUE_STRATEGY_RINGALL 0 @@ -77,7 +75,6 @@ " 'T' -- to allow the calling user to transfer the call.\n" " 'd' -- data-quality (modem) call (minimum delay).\n" " 'H' -- allow caller to hang up by hitting *.\n" -" 'n' -- no retries on the timeout; will exit this application and go to the next step.\n" " In addition to transferring the call, a call may be parked and then picked\n" "up by another user.\n" " The optionnal URL will be sent to the called party if the channel supports\n" @@ -102,6 +99,9 @@ "Example: RemoveQueueMember(techsupport|SIP/3000)\n" ""; + + + /* We define a customer "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. */ @@ -130,8 +130,6 @@ char announce[80]; /* Announcement to play */ char context[80]; /* Context when user exits queue */ int pos; /* Where we are in the queue */ - int opos; /* Where we started in the queue */ - int handled; /* Whether our call was handled */ time_t start; /* When we started holding */ struct ast_channel *chan; /* Our channel */ struct queue_ent *next; /* The next queue entry */ @@ -225,7 +223,6 @@ qe->next = NULL; qe->parent = q; qe->pos = ++pos; - qe->opos = pos; strncpy(qe->moh, q->moh, sizeof(qe->moh)); strncpy(qe->announce, q->announce, sizeof(qe->announce)); strncpy(qe->context, q->context, sizeof(qe->context)); @@ -346,6 +343,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp) { int res; + char act[256] = ""; /* 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 */ @@ -372,6 +370,13 @@ tmp->chan->ani = strdup(qe->chan->ani); else tmp->chan->ani = NULL; + + // we use the account code to keep track of the called number for shadydial + if (tmp->chan->accountcode) + free(tmp->chan->accountcode); + strncpy(act, (char *)qe->chan->accountcode, sizeof(act) - 1); + ast_cdr_setaccount(tmp->chan, strlen(act) ? act : 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 */ @@ -489,7 +494,10 @@ } else { ast_log(LOG_NOTICE, "No one is answered queue %s\n", queue); } - *to = 0; + //*to = 0; + + *to = 1; + return NULL; } winner = ast_waitfor_n(watchers, pos, to); @@ -609,11 +617,19 @@ static int wait_our_turn(struct queue_ent *qe) { + time_t now; struct queue_ent *ch; int res = 0; for (;;) { - /* Atomically read the parent head -- does not need a lock */ + + time(&now); + if ((now - qe->start) > qe->parent->timeout) + return -1; + + /* Atomically read the parent head */ + ast_mutex_lock(&qe->parent->lock); ch = qe->parent->head; + ast_mutex_unlock(&qe->parent->lock); /* If we are now at the top of the head, break out */ if (qe->parent->head == qe) break; @@ -695,7 +711,7 @@ return 0; } -static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url, int *go_on) +static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url) { struct member *cur; struct localuser *outgoing=NULL, *tmp = NULL; @@ -704,9 +720,6 @@ int allowredir_out=0; int allowdisconnect=0; char restofit[AST_MAX_EXTENSION]; - char oldexten[AST_MAX_EXTENSION]=""; - char oldcontext[AST_MAX_EXTENSION]=""; - char queuename[256]=""; char *newnum; struct ast_channel *peer; struct localuser *lpeer; @@ -715,10 +728,8 @@ int x=0; char *announce = NULL; char digit = 0; - time_t callstart; /* Hold the lock while we setup the outgoing calls */ ast_mutex_lock(&qe->parent->lock); - strncpy(queuename, qe->parent->name, sizeof(queuename) - 1); cur = qe->parent->members; if (strlen(qe->announce)) announce = qe->announce; @@ -728,7 +739,6 @@ /* Get a technology/[device:]number pair */ tmp = malloc(sizeof(struct localuser)); if (!tmp) { - ast_mutex_unlock(&qe->parent->lock); ast_log(LOG_WARNING, "Out of memory\n"); goto out; } @@ -747,8 +757,6 @@ tmp->dataquality = 1; if (strchr(options, 'H')) tmp->allowdisconnect = 1; - if (strchr(options, 'n')) - *go_on = 1; } if (url) { ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url); @@ -807,7 +815,6 @@ /* Ah ha! Someone answered within the desired timeframe. Of course after this we will always return with -1 so that it is hung up properly after the conversation. */ - qe->handled++; if (!strcmp(qe->chan->type,"Zap")) { if (tmp->dataquality) zapx = 0; ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0); @@ -833,7 +840,6 @@ if (res2) { /* Agent must have hung up */ ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name); - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", ""); ast_hangup(peer); return -1; } @@ -844,7 +850,6 @@ /* Make sure channels are compatible */ res = ast_channel_make_compatible(qe->chan, peer); if (res < 0) { - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", ""); ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); ast_hangup(peer); return -1; @@ -856,18 +861,7 @@ ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); ast_channel_sendurl( peer, url ); } /* /JDG */ - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start); - strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1); - strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1); - time(&callstart); bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect); - if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context); - } else if (qe->chan->_softhangup) { - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); - } else { - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); - } if(bridge != AST_PBX_NO_HANGUP_PEER) ast_hangup(peer); @@ -882,8 +876,17 @@ static int wait_a_bit(struct queue_ent *qe) { - /* Don't need to hold the lock while we setup the outgoing calls */ - int retrywait = qe->parent->retry * 1000; + int retrywait; + + time_t now; + time(&now); + if ((now - qe->start) > qe->parent->timeout) + return -1; + + /* Hold the lock while we setup the outgoing calls */ + ast_mutex_lock(&qe->parent->lock); + retrywait = qe->parent->retry * 1000; + ast_mutex_unlock(&qe->parent->lock); return ast_waitfordigit(qe->chan, retrywait); } @@ -1120,11 +1123,7 @@ char *options = NULL; char *url = NULL; char *announceoverride = NULL; - /* whether to exit Queue application after the timeout hits */ - int go_on = 0; - - - + /* Our queue entry */ struct queue_ent qe; @@ -1155,65 +1154,46 @@ } } } - if (option_debug) - ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s\n", - queuename, options, url, announceoverride); + printf("queue: %s, options: %s, url: %s, announce: %s\n", + queuename, options, url, announceoverride); /* Setup our queue entry */ memset(&qe, 0, sizeof(qe)); qe.chan = chan; qe.start = time(NULL); if (!join_queue(queuename, &qe)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->callerid ? chan->callerid : ""); /* Start music on hold */ ast_moh_start(chan, qe.moh); for (;;) { res = wait_our_turn(&qe); /* If they hungup, return immediately */ if (res < 0) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "User disconnected while waiting their turn\n"); res = -1; } break; } - if (!res) + if (!res) break; - if (valid_exit(&qe, res)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + if (valid_exit(&qe, res)) break; - } } if (!res) { for (;;) { - res = try_calling(&qe, options, announceoverride, url, &go_on); - if (res) { - if (res < 0) { - if (!qe.handled) - ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); - } else if (res > 0) - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + res = try_calling(&qe, options, announceoverride, url); + if (res) break; - } - res = wait_a_bit(&qe); + //res = wait_a_bit(&qe); + res = -1; if (res < 0) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n"); res = -1; } break; } - if (res && valid_exit(&qe, res)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + if (res && valid_exit(&qe, res)) break; - } - /* exit after a timeout if 'n' option enabled */ - if (go_on) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); - res = 0; - break; - } } } /* Don't allow return code > 0 */ @@ -1247,7 +1227,6 @@ /* Mark all queues as dead for the moment */ q = queues; while(q) { - q->dead = 1; q = q->next; } /* Chug through config file */ @@ -1381,7 +1360,7 @@ ast_mutex_unlock(&qlock); } -static int __queues_show(int fd, int argc, char **argv, int queue_show) +static int queues_show(int fd, int argc, char **argv) { struct ast_call_queue *q; struct queue_ent *qe; @@ -1390,32 +1369,17 @@ time_t now; char max[80]; char calls[80]; + time(&now); - if ((!queue_show && argc != 2) || (queue_show && argc != 3)) + if (argc != 2) return RESULT_SHOWUSAGE; - ast_mutex_lock(&qlock); q = queues; if (!q) { - ast_mutex_unlock(&qlock); - if (queue_show) - ast_cli(fd, "No such queue: %s.\n",argv[2]); - else - ast_cli(fd, "No queues.\n"); + ast_cli(fd, "No queues.\n"); return RESULT_SUCCESS; } while(q) { ast_mutex_lock(&q->lock); - if (queue_show) { - if (strcasecmp(q->name, argv[2]) != 0) { - ast_mutex_unlock(&q->lock); - q = q->next; - if (!q) { - ast_cli(fd, "No such queue: %s.\n",argv[2]); - break; - } - continue; - } - } if (q->maxlen) snprintf(max, sizeof(max), "%d", q->maxlen); else @@ -1432,7 +1396,7 @@ strcat(max, " (dynamic)"); if (mem->calls) { snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)", - mem->calls, (long)(time(NULL) - mem->lastcall)); + mem->calls, time(NULL) - mem->lastcall); } else strcpy(calls, " has taken no calls yet"); ast_cli(fd, " %s/%s%s%s\n", mem->tech, mem->loc, max, calls); @@ -1450,39 +1414,56 @@ ast_cli(fd, "\n"); ast_mutex_unlock(&q->lock); q = q->next; - if (queue_show) - break; } - ast_mutex_unlock(&qlock); return RESULT_SUCCESS; } -static int queues_show(int fd, int argc, char **argv) -{ - return __queues_show(fd, argc, argv, 0); -} - -static int queue_show(int fd, int argc, char **argv) -{ - return __queues_show(fd, argc, argv, 1); -} - -static char *complete_queue(char *line, char *word, int pos, int state) +static int agent_queues_show(int fd, int argc, char **argv) { struct ast_call_queue *q; - int which=0; + struct queue_ent *qe; + struct member *mem; + time_t now; + char max[80]; + int agents=0; + int callers=0; - ast_mutex_lock(&qlock); + time(&now); + if (argc != 2) + return RESULT_SHOWUSAGE; q = queues; + if (!q) { + ast_cli(fd, "No queues.\n"); + return RESULT_SUCCESS; + } while(q) { - if (!strncasecmp(word, q->name, strlen(word))) { - if (++which > state) - break; - } + ast_mutex_lock(&q->lock); + if (q->maxlen) + snprintf(max, sizeof(max), "%d", q->maxlen); + else + strcpy(max, "unlimited"); + ast_cli(fd, "Queue: %s\r\n", q->name); + if (q->members) { + mem = q->members; + while (mem) { + mem = mem->next; + agents++; + } + } + ast_cli(fd, "Agents: %d\r\n", agents); + if (q->head) { + qe = q->head; + while (qe) { + qe = q->next; + callers++; + } + } + ast_cli(fd, "Callers: %d\r\n", callers); + ast_mutex_unlock(&q->lock); q = q->next; } - ast_mutex_unlock(&qlock); - return q ? strdup(q->name) : NULL; + ast_cli(fd, "\n"); + return RESULT_SUCCESS; } /* JDG: callback to display queues status in manager */ @@ -1492,6 +1473,11 @@ return queues_show( s->fd, 2, a ); } /* /JDG */ +static int manager_agent_queues_show( struct mansession *s, struct message *m ) +{ + char *a[] = { "show", "agentqueues" }; + return agent_queues_show( s->fd, 2, a ); +} /* Dump queue status */ static int manager_queues_status( struct mansession *s, struct message *m ) @@ -1504,20 +1490,15 @@ struct queue_ent *qe; astman_send_ack(s, m, "Queue status will follow"); time(&now); - ast_mutex_lock(&qlock); q = queues; - if (id && &id) { - snprintf(idText,256,"ActionID: %s\r\n",id); - } while(q) { ast_mutex_lock(&q->lock); ast_cli(s->fd, "Event: QueueParams\r\n" "Queue: %s\r\n" "Max: %d\r\n" "Calls: %d\r\n" - "%s" "\r\n", - q->name, q->maxlen, q->count,idText); + q->name, q->maxlen, q->count); #if 0 /* Do we care about queue members? */ for (mem = q->members; mem; mem = mem->next) @@ -1531,13 +1512,11 @@ "Channel: %s\r\n" "CallerID: %s\r\n" "Wait: %ld\r\n" - "%s" "\r\n", - q->name, pos++, qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : ""), (long)(now - qe->start), idText); + q->name, pos++, qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : ""), now - qe->start); ast_mutex_unlock(&q->lock); q = q->next; } - ast_mutex_unlock(&qlock); return RESULT_SUCCESS; } @@ -1549,21 +1528,13 @@ { "show", "queues", NULL }, queues_show, "Show status of queues", show_queues_usage, NULL }; -static char show_queue_usage[] = -"Usage: show queue\n" -" Provides summary information on a specified queue.\n"; - -static struct ast_cli_entry cli_show_queue = { - { "show", "queue", NULL }, queue_show, - "Show status of a specified queue", show_queue_usage, complete_queue }; - int unload_module(void) { STANDARD_HANGUP_LOCALUSERS; - ast_cli_unregister(&cli_show_queue); ast_cli_unregister(&cli_show_queues); ast_manager_unregister( "Queues" ); ast_manager_unregister( "QueueStatus" ); + ast_manager_unregister( "AgentQueues" ); return ast_unregister_application(app); } @@ -1572,10 +1543,10 @@ int res; res = ast_register_application(app, queue_exec, synopsis, descrip); if (!res) { - ast_cli_register(&cli_show_queue); ast_cli_register(&cli_show_queues); ast_manager_register( "Queues", 0, manager_queues_show, "Queues" ); ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" ); + ast_manager_register( "AgentQueues", 0, manager_agent_queues_show, "AgentQueues" ); // [PHM 06/26/03] ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;