Skip to content
Snippets Groups Projects
app_queue.c 131 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			if (q->callscompleted > 0)
    				sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
    
    			astman_append(s, "Event: QueueParams\r\n"
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    				"Queue: %s\r\n"
    				"Max: %d\r\n"
    				"Calls: %d\r\n"
    				"Holdtime: %d\r\n"
    				"Completed: %d\r\n"
    				"Abandoned: %d\r\n"
    				"ServiceLevel: %d\r\n"
    				"ServicelevelPerf: %2.1f\r\n"
    				"Weight: %d\r\n"
    				"%s"
    				"\r\n",
    				q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
    				q->callsabandoned, q->servicelevel, sl, q->weight, idText);
    
    			/* List Queue Members */
    			for (mem = q->members; mem; mem = mem->next) {
    				if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
    
    					astman_append(s, "Event: QueueMember\r\n"
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    						"Queue: %s\r\n"
    						"Location: %s\r\n"
    						"Membership: %s\r\n"
    						"Penalty: %d\r\n"
    						"CallsTaken: %d\r\n"
    						"LastCall: %d\r\n"
    						"Status: %d\r\n"
    						"Paused: %d\r\n"
    						"%s"
    						"\r\n",
    						q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
    						mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
    
    				}
    			}
    			/* List Queue Entries */
    			pos = 1;
    			for (qe = q->head; qe; qe = qe->next) {
    
    				astman_append(s, "Event: QueueEntry\r\n"
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    					"Queue: %s\r\n"
    					"Position: %d\r\n"
    					"Channel: %s\r\n"
    					"CallerID: %s\r\n"
    					"CallerIDName: %s\r\n"
    					"Wait: %ld\r\n"
    					"%s"
    					"\r\n",
    					q->name, pos++, qe->chan->name,
    					S_OR(qe->chan->cid.cid_num, "unknown"),
    					S_OR(qe->chan->cid.cid_name, "unknown"),
    					(long) (now - qe->start), idText);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		"Event: QueueStatusComplete\r\n"
    		"%s"
    		"\r\n",idText);
    
    	return RESULT_SUCCESS;
    }
    
    
    static int manager_add_queue_member(struct mansession *s, struct message *m)
    {
    
    	char *queuename, *interface, *penalty_s, *paused_s;
    	int paused, penalty = 0;
    
    
    	queuename = astman_get_header(m, "Queue");
    	interface = astman_get_header(m, "Interface");
    	penalty_s = astman_get_header(m, "Penalty");
    
    	paused_s = astman_get_header(m, "Paused");
    
    
    	if (ast_strlen_zero(queuename)) {
    		astman_send_error(s, m, "'Queue' not specified.");
    		return 0;
    	}
    
    	if (ast_strlen_zero(interface)) {
    		astman_send_error(s, m, "'Interface' not specified.");
    		return 0;
    	}
    
    	if (ast_strlen_zero(penalty_s))
    		penalty = 0;
    
    	else if (sscanf(penalty_s, "%d", &penalty) != 1)
    
    	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)) {
    
    	case RES_OKAY:
    		astman_send_ack(s, m, "Added interface to queue");
    		break;
    	case RES_EXISTS:
    		astman_send_error(s, m, "Unable to add interface: Already there");
    		break;
    	case RES_NOSUCHQUEUE:
    		astman_send_error(s, m, "Unable to add interface to queue: No such queue");
    		break;
    	case RES_OUTOFMEMORY:
    		astman_send_error(s, m, "Out of memory");
    		break;
    	}
    
    	return 0;
    }
    
    static int manager_remove_queue_member(struct mansession *s, struct message *m)
    {
    	char *queuename, *interface;
    
    	queuename = astman_get_header(m, "Queue");
    	interface = astman_get_header(m, "Interface");
    
    	if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
    		astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
    		return 0;
    	}
    
    	switch (remove_from_queue(queuename, interface)) {
    	case RES_OKAY:
    		astman_send_ack(s, m, "Removed interface from queue");
    		break;
    	case RES_EXISTS:
    		astman_send_error(s, m, "Unable to remove interface: Not there");
    		break;
    	case RES_NOSUCHQUEUE:
    		astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
    		break;
    	case RES_OUTOFMEMORY:
    		astman_send_error(s, m, "Out of memory");
    		break;
    	}
    
    static int manager_pause_queue_member(struct mansession *s, struct message *m)
    {
    	char *queuename, *interface, *paused_s;
    	int paused;
    
    	interface = astman_get_header(m, "Interface");
    	paused_s = astman_get_header(m, "Paused");
    	queuename = astman_get_header(m, "Queue");	/* Optional - if not supplied, pause the given Interface in all queues */
    
    	if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
    		astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
    		return 0;
    	}
    
    	paused = abs(ast_true(paused_s));
    
    	if (set_member_paused(queuename, interface, paused))
    		astman_send_error(s, m, "Interface not found");
    	else
    
    		astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
    
    static int handle_add_queue_member(int fd, int argc, char *argv[])
    {
    	char *queuename, *interface;
    	int penalty;
    
    	if ((argc != 6) && (argc != 8)) {
    		return RESULT_SHOWUSAGE;
    	} else if (strcmp(argv[4], "to")) {
    		return RESULT_SHOWUSAGE;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else if ((argc == 8) && strcmp(argv[6], "penalty")) {
    
    		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;
    		}
    	} else {
    		penalty = 0;
    	}
    
    
    	switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
    
    	case RES_OKAY:
    		ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
    		return RESULT_SUCCESS;
    	case RES_EXISTS:
    		ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
    		return RESULT_FAILURE;
    	case RES_NOSUCHQUEUE:
    		ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
    		return RESULT_FAILURE;
    	case RES_OUTOFMEMORY:
    		ast_cli(fd, "Out of memory\n");
    		return RESULT_FAILURE;
    	default:
    		return RESULT_FAILURE;
    	}
    }
    
    
    static char *complete_add_queue_member(const char *line, const char *word, int pos, int state)
    
    {
    	/* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty> */
    	switch (pos) {
    
    	case 3:	/* Don't attempt to complete name of member (infinite possibilities) */
    
    	case 4:	/* only one possible match, "to" */
    
    		return state == 0 ? ast_strdup("to") : NULL;
    
    		return complete_queue(line, word, pos, state);
    
    	case 6: /* only one possible match, "penalty" */
    
    		return state == 0 ? ast_strdup("penalty") : NULL;
    
    	case 7:
    		if (state < 100) {	/* 0-99 */
    
    				sprintf(num, "%d", state);
    			}
    			return num;
    		} else {
    			return NULL;
    		}
    	default:
    		return NULL;
    	}
    }
    
    static int handle_remove_queue_member(int fd, int argc, char *argv[])
    {
    	char *queuename, *interface;
    
    	if (argc != 6) {
    		return RESULT_SHOWUSAGE;
    	} else if (strcmp(argv[4], "from")) {
    		return RESULT_SHOWUSAGE;
    	}
    
    	queuename = argv[5];
    	interface = argv[3];
    
    	switch (remove_from_queue(queuename, interface)) {
    	case RES_OKAY:
    		ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
    		return RESULT_SUCCESS;
    	case RES_EXISTS:
    		ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
    		return RESULT_FAILURE;
    	case RES_NOSUCHQUEUE:
    		ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
    		return RESULT_FAILURE;
    	case RES_OUTOFMEMORY:
    		ast_cli(fd, "Out of memory\n");
    		return RESULT_FAILURE;
    	default:
    		return RESULT_FAILURE;
    	}
    }
    
    
    static char *complete_remove_queue_member(const char *line, const char *word, int pos, int state)
    
    	struct call_queue *q;
    
    	/* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
    	if (pos > 5 || pos < 3)
    		return NULL;
    	if (pos == 4)	/* only one possible match, 'from' */
    		return state == 0 ? ast_strdup("from") : NULL;
    
    	if (pos == 5)	/* No need to duplicate code */
    		return complete_queue(line, word, pos, state);
    
    	/* here is the case for 3, <member> */
    	if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
    
    		AST_LIST_TRAVERSE(&queues, q, list) {
    
    			ast_mutex_lock(&q->lock);
    			for (m = q->members ; m ; m = m->next) {
    				if (++which > state) {
    					ast_mutex_unlock(&q->lock);
    
    					return ast_strdup(m->interface);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    static char show_queues_usage[] =
    
    Mark Spencer's avatar
    Mark Spencer committed
    "Usage: show queues\n"
    "       Provides summary information on call queues.\n";
    
    static struct ast_cli_entry cli_show_queues = {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	{ "show", "queues", NULL }, queues_show,
    
    Mark Spencer's avatar
    Mark Spencer committed
    	"Show status of queues", show_queues_usage, NULL };
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    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 = {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    	{ "show", "queue", NULL }, queue_show,
    
    	"Show status of a specified queue", show_queue_usage, complete_queue };
    
    
    static char aqm_cmd_usage[] =
    "Usage: add queue member <channel> to <queue> [penalty <penalty>]\n";
    
    static struct ast_cli_entry cli_add_queue_member = {
    	{ "add", "queue", "member", NULL }, handle_add_queue_member,
    	"Add a channel to a specified queue", aqm_cmd_usage, complete_add_queue_member };
    
    static char rqm_cmd_usage[] =
    "Usage: remove queue member <channel> from <queue>\n";
    
    static struct ast_cli_entry cli_remove_queue_member = {
    	{ "remove", "queue", "member", NULL }, handle_remove_queue_member,
    	"Removes a channel from a specified queue", rqm_cmd_usage, complete_remove_queue_member };
    
    
    static int unload_module(void)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	int res;
    
    	res = ast_cli_unregister(&cli_show_queue);
    	res |= ast_cli_unregister(&cli_show_queues);
    	res |= ast_cli_unregister(&cli_add_queue_member);
    	res |= ast_cli_unregister(&cli_remove_queue_member);
    	res |= ast_manager_unregister("Queues");
    	res |= ast_manager_unregister("QueueStatus");
    	res |= ast_manager_unregister("QueueAdd");
    	res |= ast_manager_unregister("QueueRemove");
    	res |= ast_manager_unregister("QueuePause");
    	res |= ast_unregister_application(app_aqm);
    	res |= ast_unregister_application(app_rqm);
    	res |= ast_unregister_application(app_pqm);
    	res |= ast_unregister_application(app_upqm);
    
    	res |= ast_unregister_application(app_ql);
    
    	res |= ast_custom_function_unregister(&queueagentcount_function);
    
    	res |= ast_custom_function_unregister(&queuemembercount_function);
    	res |= ast_custom_function_unregister(&queuememberlist_function);
    
    	res |= ast_custom_function_unregister(&queuewaitingcount_function);
    
    	ast_module_user_hangup_all();
    
    	clear_and_free_interfaces();
    
    static int load_module(void)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    
    	if(!reload_queues())
    		return AST_MODULE_LOAD_DECLINE;
    	if (queue_persistent_members)
    		reload_queue_members();
    
    Mark Spencer's avatar
    Mark Spencer committed
    	res = ast_register_application(app, queue_exec, synopsis, descrip);
    
    	res |= ast_cli_register(&cli_show_queue);
    	res |= ast_cli_register(&cli_show_queues);
    	res |= ast_cli_register(&cli_add_queue_member);
    	res |= ast_cli_register(&cli_remove_queue_member);
    
    	res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
    	res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
    	res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
    	res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
    	res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
    	res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
    	res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
    	res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
    	res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
    	res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
    
    	res |= ast_custom_function_register(&queueagentcount_function);
    
    	res |= ast_custom_function_register(&queuemembercount_function);
    	res |= ast_custom_function_register(&queuememberlist_function);
    
    	res |= ast_custom_function_register(&queuewaitingcount_function);
    
    	res |= ast_devstate_add(statechange_queue, NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	reload_queues();
    	return 0;
    }
    
    
    AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
    		.load = load_module,
    		.unload = unload_module,
    		.reload = reload,
    	       );