Index: apps/app_queue.c =================================================================== --- apps/app_queue.c (revision 18692) +++ apps/app_queue.c (working copy) @@ -163,6 +163,7 @@ "then it will then jump to this priority. Otherwise it will return an error\n" "The option string may contain zero or more of the following characters:\n" " 'j' -- jump to +101 priority when appropriate.\n" +" 'A(agentnum)' -- set agentnum.\n" " This application sets the following channel variable upon completion:\n" " AQMSTATUS The status of the attempt to add a queue member as a \n" " text string, one of\n" @@ -298,6 +299,7 @@ struct member { char interface[80]; /*!< Technology/Location */ int penalty; /*!< Are we a last resort? */ + int agentnum; /*!< Agent working number? */ int calls; /*!< Number of calls serviced by this member */ int dynamic; /*!< Are we dynamically added? */ int status; /*!< Status of queue member */ @@ -318,6 +320,7 @@ char name[80]; /*!< Name */ char moh[80]; /*!< Music On Hold class to be used */ char announce[80]; /*!< Announcement to play when call is answered */ + int announceagentnum; /*!< if to play agent number for caller */ char context[AST_MAX_CONTEXT]; /*!< Exit context */ unsigned int monjoin:1; unsigned int dead:1; @@ -351,6 +354,8 @@ char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */ char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */ char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/* Sound files: Custom announce, no default */ + char sound_announceagentnum1[80]; /*!< Sound file: before announcing agentnum, default to "announceagentnum1" */ + char sound_announceagentnum2[80]; /*!< Sound file: after announcing agentnum, default to "announceagentnum2" */ int count; /*!< How many entries */ int maxlen; /*!< Max number of entries */ @@ -495,12 +500,13 @@ "Location: %s\r\n" "Membership: %s\r\n" "Penalty: %d\r\n" + "Agentnum: %d\r\n" "CallsTaken: %d\r\n" "LastCall: %d\r\n" "Status: %d\r\n" "Paused: %d\r\n", q->name, cur->interface, cur->dynamic ? "dynamic" : "static", - cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); + cur->penalty, cur->agentnum, cur->calls, (int)cur->lastcall, cur->status, cur->paused); } } } @@ -534,7 +540,7 @@ return 0; } -static struct member *create_queue_member(char *interface, int penalty, int paused) +static struct member *create_queue_member(char *interface, int penalty, int agentnum, int paused) { struct member *cur; @@ -542,6 +548,7 @@ if ((cur = ast_calloc(1, sizeof(*cur)))) { cur->penalty = penalty; + cur->agentnum = agentnum; cur->paused = paused; ast_copy_string(cur->interface, interface, sizeof(cur->interface)); if (!strchr(cur->interface, '/')) @@ -572,6 +579,7 @@ q->maxlen = 0; q->announcefrequency = 0; q->announceholdtime = 0; + q->announceagentnum = 0; q->roundingseconds = 0; /* Default - don't announce seconds */ q->servicelevel = 0; q->ringinuse = 1; @@ -581,6 +589,8 @@ q->monfmt[0] = '\0'; q->periodicannouncefrequency = 0; ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); + ast_copy_string(q->sound_announceagentnum1, "announceagentnum1", sizeof(q->sound_announceagentnum1)); + ast_copy_string(q->sound_announceagentnum2, "announceagentnum2", sizeof(q->sound_announceagentnum2)); ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); @@ -620,6 +630,8 @@ ast_copy_string(q->moh, val, sizeof(q->moh)); } else if (!strcasecmp(param, "announce")) { ast_copy_string(q->announce, val, sizeof(q->announce)); + } else if(! strcasecmp(param, "announceagentnum")) { + q->announceagentnum = ast_true(val); } else if (!strcasecmp(param, "context")) { ast_copy_string(q->context, val, sizeof(q->context)); } else if (!strcasecmp(param, "timeout")) { @@ -692,6 +704,10 @@ } } else if (!strcasecmp(param, "periodic-announce-frequency")) { q->periodicannouncefrequency = atoi(val); + } else if(! strcasecmp(param, "announceagentnum1")) { + ast_copy_string(q->sound_announceagentnum1, val, sizeof(q->sound_announceagentnum1)); + } else if(! strcasecmp(param, "announceagentnum2")) { + ast_copy_string(q->sound_announceagentnum2, val, sizeof(q->sound_announceagentnum2)); } else if (!strcasecmp(param, "retry")) { q->retry = atoi(val); if (q->retry < 0) @@ -755,16 +771,22 @@ } } -static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str) +static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str, const char * agentnum_str) { struct member *m, *prev_m; int penalty = 0; + int agentnum = 0; if(penalty_str) { penalty = atoi(penalty_str); if(penalty < 0) penalty = 0; } + if(agentnum_str) { + agentnum = atoi(agentnum_str); + if(agentnum < 0) + agentnum = 0; + } /* Find the member, or the place to put a new one. */ prev_m = NULL; @@ -776,7 +798,7 @@ /* Create a new one if not found, else update penalty */ if (!m) { - m = create_queue_member(interface, penalty, 0); + m = create_queue_member(interface, penalty, agentnum, 0); if (m) { m->dead = 0; if (prev_m) { @@ -788,6 +810,7 @@ } else { m->dead = 0; /* Do not delete this one. */ m->penalty = penalty; + m->agentnum = agentnum; } } @@ -910,7 +933,9 @@ interface = ast_category_browse(member_config, NULL); while (interface) { - rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty")); + rt_handle_member_record(q, interface, + ast_variable_retrieve(member_config, interface, "penalty"), + ast_variable_retrieve(member_config, interface, "agentnum")); interface = ast_category_browse(member_config, interface); } @@ -1295,12 +1320,13 @@ "Location: %s\r\n" "Membership: %s\r\n" "Penalty: %d\r\n" + "Agentnum: %d\r\n" "CallsTaken: %d\r\n" "LastCall: %d\r\n" "Status: %d\r\n" "Paused: %d\r\n", q->name, cur->interface, cur->dynamic ? "dynamic" : "static", - cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); + cur->penalty, cur->agentnum, cur->calls, (int)cur->lastcall, cur->status, cur->paused); } break; } @@ -2161,6 +2187,47 @@ member = lpeer->member; hangupcalls(outgoing, peer); outgoing = NULL; + if (qe->parent->announceagentnum && member->agentnum) { //Announce agentnum here + int res2; + res2 = ast_autoservice_start(peer); + if(!res2) { + ast_log(LOG_DEBUG, "Announce agentnum %d", member->agentnum); + /* Stop music on hold */ + ast_moh_stop(qe->chan); + if(!play_file(qe->chan, qe->parent->sound_announceagentnum1)) { + ast_say_digits(qe->chan, member->agentnum, AST_DIGIT_ANY, qe->chan->language); + play_file(qe->chan, qe->parent->sound_announceagentnum2); + } else + ast_log(LOG_WARNING, "Agentnum announcement file '%s' is unavailable, continuing anyway...\n", + qe->parent->sound_announceagentnum1); + // restart moh + ast_moh_start(qe->chan, qe->moh); + } + res2 |= ast_autoservice_stop(peer); + if (qe->chan->_softhangup) { + /* Caller must have hung up just before being connected*/ + ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); + record_abandoned(qe); + ast_hangup(peer); + return -1; + } else 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", "%s", ""); + record_abandoned(qe); + if (qe->parent->eventwhencalled) { + manager_event(EVENT_FLAG_AGENT, "AgentDump", + "Queue: %s\r\n" + "Uniqueid: %s\r\n" + "Channel: %s\r\n" + "Member: %s\r\n", + queuename, qe->chan->uniqueid, peer->name, member->interface); + } + ast_hangup(peer); + goto out; + } + } if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { int res2; res2 = ast_autoservice_start(qe->chan); @@ -2215,6 +2282,7 @@ } /* Stop music on hold */ ast_moh_stop(qe->chan); + /* If appropriate, log that we have a destination channel */ if (qe->chan->cdr) ast_cdr_setdestchan(qe->chan->cdr, peer->name); @@ -2355,8 +2423,8 @@ if (!cur_member->dynamic) continue; - res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s", - cur_member->interface, cur_member->penalty, cur_member->paused, + res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%d;%s", + cur_member->interface, cur_member->penalty, cur_member->agentnum, cur_member->paused, cur_member->next ? "|" : ""); if (res != strlen(value + value_len)) { ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); @@ -2418,7 +2486,7 @@ return res; } -static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump) +static int add_to_queue(char *queuename, char *interface, int penalty, int agentnum, int paused, int dump) { struct ast_call_queue *q; struct member *new_member; @@ -2433,7 +2501,7 @@ if (q) { ast_mutex_lock(&q->lock); if (interface_exists(q, interface) == NULL) { - new_member = create_queue_member(interface, penalty, paused); + new_member = create_queue_member(interface, penalty, agentnum, paused); if (new_member != NULL) { new_member->dynamic = 1; @@ -2444,12 +2512,14 @@ "Location: %s\r\n" "Membership: %s\r\n" "Penalty: %d\r\n" + "Agentnum: %d\r\n" "CallsTaken: %d\r\n" "LastCall: %d\r\n" "Status: %d\r\n" "Paused: %d\r\n", q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static", - new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused); + new_member->penalty, new_member->agentnum, new_member->calls, + (int)new_member->lastcall, new_member->status, new_member->paused); if (dump) dump_queue_members(q); @@ -2519,6 +2589,8 @@ char *interface; char *penalty_tok; int penalty = 0; + char *agentnum_tok; + int agentnum = 0; char *paused_tok; int paused = 0; struct ast_db_entry *db_tree; @@ -2559,6 +2631,7 @@ interface = strsep(&member, ";"); penalty_tok = strsep(&member, ";"); + agentnum_tok = strsep(&member, ";"); paused_tok = strsep(&member, ";"); if (!penalty_tok) { @@ -2570,6 +2643,15 @@ ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); break; } + if (!agentnum_tok) { + ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (agentnum)\n", queue_name); + break; + } + agentnum = strtol(agentnum_tok, NULL, 10); + if (errno == ERANGE) { + ast_log(LOG_WARNING, "Error converting agentnum: %s: Out of range.\n", agentnum_tok); + break; + } if (!paused_tok) { ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); @@ -2582,9 +2664,9 @@ } if (option_debug) - ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused); + ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Agentnum %d Paused: %d\n", queue_name, interface, penalty, agentnum, paused); - if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) { + if (add_to_queue(queue_name, interface, penalty, agentnum, paused, 0) == RES_OUTOFMEMORY) { ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); break; } @@ -2781,6 +2863,8 @@ AST_APP_ARG(options); ); int penalty = 0; + int agentnum = 0; + char *agentnum_str = 0; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n"); @@ -2811,10 +2895,21 @@ if (args.options) { if (strchr(args.options, 'j')) priority_jump = 1; + agentnum_str = strchr(args.options, 'A'); + if(agentnum_str) { + + ++agentnum_str; + agentnum = atoi(agentnum_str); + if (errno == ERANGE) { + ast_log(LOG_WARNING, "Error converting agentnum: %s: Out of range.\n", agentnum_str); + } + if(agentnum < 0) { + ast_log(LOG_WARNING, "agentnum can not less than: %s", args.queuename); + agentnum = 0; + } + } } - - - switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) { + switch (add_to_queue(args.queuename, args.interface, penalty, agentnum, 0, queue_persistent_members)) { case RES_OKAY: ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); @@ -3244,6 +3339,8 @@ char *general_val = NULL; char interface[80]; int penalty; + /* agent number */ + int agentnum; cfg = ast_config_load("queues.conf"); if (!cfg) { @@ -3303,9 +3400,22 @@ if (penalty < 0) { penalty = 0; } - } else + /* get agent number */ + if((tmp = strchr(tmp, ','))) { + *tmp = '\0'; + ++tmp; + agentnum = atoi(tmp); + if(agentnum < 0) { + /* not to play agent number when agentnum is zero */ + agentnum = 0; + } + } else + agentnum = 0; + } else { penalty = 0; - cur = create_queue_member(interface, penalty, 0); + agentnum = 0; + } + cur = create_queue_member(interface, penalty, agentnum, 0); if (cur) { if (prev) prev->next = cur; @@ -3417,6 +3527,8 @@ max_left = sizeof(max_buf); if (mem->penalty) ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); + if(mem->agentnum) + ast_build_string(&max, &max_left, " with agentnum %d", mem->agentnum); if (mem->dynamic) ast_build_string(&max, &max_left, " (dynamic)"); if (mem->paused) @@ -3556,6 +3668,7 @@ "Location: %s\r\n" "Membership: %s\r\n" "Penalty: %d\r\n" + "Agentnum: %d\r\n" "CallsTaken: %d\r\n" "LastCall: %d\r\n" "Status: %d\r\n" @@ -3563,7 +3676,7 @@ "%s" "\r\n", q->name, mem->interface, mem->dynamic ? "dynamic" : "static", - mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); + mem->penalty, mem->agentnum, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); } } /* List Queue Entries */ @@ -3599,12 +3712,13 @@ static int manager_add_queue_member(struct mansession *s, struct message *m) { - char *queuename, *interface, *penalty_s, *paused_s; - int paused, penalty = 0; + char *queuename, *interface, *penalty_s, *agentnum_s, *paused_s; + int paused, penalty, agentnum = 0; queuename = astman_get_header(m, "Queue"); interface = astman_get_header(m, "Interface"); penalty_s = astman_get_header(m, "Penalty"); + agentnum_s = astman_get_header(m, "Agentnum"); paused_s = astman_get_header(m, "Paused"); if (ast_strlen_zero(queuename)) { @@ -3621,13 +3735,16 @@ penalty = 0; else if (sscanf(penalty_s, "%d", &penalty) != 1) penalty = 0; - + if (ast_strlen_zero(agentnum_s)) + agentnum = 0; + else if (sscanf(agentnum_s, "%d", &agentnum) != 1) + agentnum = 0; if (ast_strlen_zero(paused_s)) paused = 0; else paused = abs(ast_true(paused_s)); - switch (add_to_queue(queuename, interface, penalty, paused, queue_persistent_members)) { + switch (add_to_queue(queuename, interface, penalty, agentnum,paused, queue_persistent_members)) { case RES_OKAY: astman_send_ack(s, m, "Added interface to queue"); break; @@ -3699,33 +3816,59 @@ static int handle_add_queue_member(int fd, int argc, char *argv[]) { char *queuename, *interface; - int penalty; + int penalty, agentnum; - if ((argc != 6) && (argc != 8)) { + if ((argc != 6) && (argc != 8) && (argc != 10)) { return RESULT_SHOWUSAGE; } else if (strcmp(argv[4], "to")) { return RESULT_SHOWUSAGE; - } else if ((argc == 8) && strcmp(argv[6], "penalty")) { + } else if ((argc == 8) && strcmp(argv[6], "penalty") && strcmp(argv[6], "agentnum")) { return RESULT_SHOWUSAGE; - } + } else if((argc == 10) && strcmp(argv[8], "agentnum")) { + return RESULT_SHOWUSAGE; + } else if((argc == 10) && ! strcmp(argv[8], "agentnum") && !strcmp(argv[8], "agentnum")) { + return RESULT_SHOWUSAGE; + } queuename = argv[5]; interface = argv[3]; - if (argc == 8) { - if (sscanf(argv[7], "%d", &penalty) == 1) { - if (penalty < 0) { - ast_cli(fd, "Penalty must be >= 0\n"); - penalty = 0; - } - } else { - ast_cli(fd, "Penalty must be an integer >= 0\n"); - penalty = 0; - } + if (argc >= 8) { + if(argc == 10) { + if(sscanf(argv[9], "%d", &agentnum) == 1) { + if(agentnum < 0) { + ast_cli(fd, "Agentnum must be >= 0\n"); + agentnum = 0; + } + } + } + if(strcmp(argv[6], "penalty")) { + /* agent number */ + if(sscanf(argv[7], "%d", &agentnum) == 1) { + if(agentnum < 0) { + ast_cli(fd, "Agentnum must be >= 0\n"); + agentnum = 0; + } + } else { + ast_cli(fd, "Agentnum must be an integer >= 0\n"); + agentnum = 0; + } + } else { /* penalty */ + if (sscanf(argv[7], "%d", &penalty) == 1) { + if (penalty < 0) { + ast_cli(fd, "Penalty must be >= 0\n"); + penalty = 0; + } + } else { + ast_cli(fd, "Penalty must be an integer >= 0\n"); + penalty = 0; + } + } } else { penalty = 0; + agentnum = 0; } - switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) { + switch (add_to_queue(queuename, interface, penalty, agentnum, 0, queue_persistent_members)) { case RES_OKAY: ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); return RESULT_SUCCESS; @@ -3745,7 +3888,9 @@ static char *complete_add_queue_member(const char *line, const char *word, int pos, int state) { - /* 0 - add; 1 - queue; 2 - member; 3 - ; 4 - to; 5 - ; 6 - penalty; 7 - */ + /* 0 - add; 1 - queue; 2 - member; 3 - ; 4 - to; 5 - ; + * 6 - penalty(agentnum if no penalty); 7 - ; 8 - agentnum; 9 - + */ switch (pos) { case 3: /* Don't attempt to complete name of member (infinite possibilities) */ return NULL; @@ -3849,7 +3994,7 @@ "Show status of a specified queue", show_queue_usage, complete_queue }; static char aqm_cmd_usage[] = -"Usage: add queue member to [penalty ]\n"; +"Usage: add queue member to [penalty ] [agentnum ]\n"; static struct ast_cli_entry cli_add_queue_member = { { "add", "queue", "member", NULL }, handle_add_queue_member,