From d5c048617510e70e7107cd615595564454e55986 Mon Sep 17 00:00:00 2001 From: Sperl Viktor Date: Wed, 27 Nov 2024 17:36:39 +0100 Subject: [PATCH] app_queue: allow dynamically adding a queue member in paused state. Fixes: #1007 UserNote: use the p option of AddQueueMember() for paused member state. Optionally, use the r(reason) option to specify a custom reason for the pause. --- apps/app_queue.c | 97 ++++++++++++++++++++++++++---- configs/samples/queues.conf.sample | 6 +- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index b4d6345761..2053328a6f 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -323,7 +323,17 @@ - + + + + + + @@ -878,6 +888,9 @@ To pause or not the member initially (true/false or 1/0). + + Text description why the member is paused. + Text alias for the interface. @@ -914,10 +927,10 @@ Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause. - + The name of the queue in which to pause or unpause this member. If not specified, the member will be paused or unpaused in all the queues it is a member of. - + Text description, returned in the event QueueMemberPaused. @@ -1502,6 +1515,22 @@ AST_APP_OPTIONS(queue_exec_options, BEGIN_OPTIONS AST_APP_OPTION('W', OPT_CALLER_AUTOMON), END_OPTIONS); + +enum aqm_flags { + AQMFLAG_PAUSED = (1 << 1), + AQMFLAG_REASON = (1 << 2), +}; + +enum aqm_args { + AQM_OPT_ARG_PAUSE_REASON = 0, + AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */ +}; + +AST_APP_OPTIONS(aqm_opts, { + AST_APP_OPTION('p', AQMFLAG_PAUSED), + AST_APP_OPTION_ARG('r', AQMFLAG_REASON, AQM_OPT_ARG_PAUSE_REASON), +}); + enum { QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_LEASTRECENT, @@ -8354,7 +8383,7 @@ static int rqm_exec(struct ast_channel *chan, const char *data) static int aqm_exec(struct ast_channel *chan, const char *data) { int res=-1; - char *parse, *tmp, *temppos = NULL; + char *parse, *tmp, *temppos = NULL, *reason = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(queuename); AST_APP_ARG(interface); @@ -8365,7 +8394,9 @@ static int aqm_exec(struct ast_channel *chan, const char *data) AST_APP_ARG(wrapuptime); ); int penalty = 0; + int paused = 0; int wrapuptime; + struct ast_flags flags = { 0 }; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n"); @@ -8376,6 +8407,17 @@ static int aqm_exec(struct ast_channel *chan, const char *data) AST_STANDARD_APP_ARGS(args, parse); + if (args.options) { + char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, }; + ast_app_parse_options(aqm_opts, &flags, opts, args.options); + if (ast_test_flag(&flags, AQMFLAG_PAUSED)) { + paused = 1; + if (ast_test_flag(&flags, AQMFLAG_REASON) && !ast_strlen_zero(opts[AQM_OPT_ARG_PAUSE_REASON])) { + reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]); + } + } + } + if (ast_strlen_zero(args.interface)) { args.interface = ast_strdupa(ast_channel_name(chan)); temppos = strrchr(args.interface, '-'); @@ -8402,7 +8444,7 @@ static int aqm_exec(struct ast_channel *chan, const char *data) wrapuptime = 0; } - switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL, wrapuptime)) { + switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) { case RES_OKAY: if (ast_strlen_zero(args.membername) || !log_membername_as_agent) { ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", ""); @@ -9623,6 +9665,7 @@ static void reload_single_member(const char *memberdata, struct call_queue *q) int penalty; int ringinuse; int wrapuptime; + int paused; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(interface); AST_APP_ARG(penalty); @@ -9630,6 +9673,7 @@ static void reload_single_member(const char *memberdata, struct call_queue *q) AST_APP_ARG(state_interface); AST_APP_ARG(ringinuse); AST_APP_ARG(wrapuptime); + AST_APP_ARG(paused); ); if (ast_strlen_zero(memberdata)) { @@ -9695,11 +9739,30 @@ static void reload_single_member(const char *memberdata, struct call_queue *q) wrapuptime = 0; } + if (!ast_strlen_zero(args.paused)) { + tmp = args.paused; + ast_strip(tmp); + if (ast_true(tmp)) { + paused = 1; + } else if (ast_false(tmp)) { + paused = 0; + } else { + ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername); + paused = 0; + } + } else { + paused = 0; + } + /* Find the old position in the list */ ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); cur = ao2_find(q->members, &tmpmem, OBJ_POINTER); - if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse, wrapuptime))) { + if (cur) { + paused = cur->paused; + } + + if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) { newm->wrapuptime = wrapuptime; if (cur) { ao2_lock(q->members); @@ -10610,13 +10673,14 @@ static int manager_queues_status(struct mansession *s, const struct message *m) static int manager_add_queue_member(struct mansession *s, const struct message *m) { - const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface, *wrapuptime_s; + const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s; int paused, penalty, wrapuptime = 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"); + reason = astman_get_header(m, "Reason"); /* Optional */ membername = astman_get_header(m, "MemberName"); state_interface = astman_get_header(m, "StateInterface"); wrapuptime_s = astman_get_header(m, "Wrapuptime"); @@ -10649,7 +10713,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message * paused = abs(ast_true(paused_s)); } - switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL, wrapuptime)) { + switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) { case RES_OKAY: if (ast_strlen_zero(membername) || !log_membername_as_agent) { ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); @@ -10989,21 +11053,21 @@ static int manager_request_withdraw_caller_from_queue(struct mansession *s, cons static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - const char *queuename, *interface, *membername = NULL, *state_interface = NULL; - int penalty; + const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL; + int penalty, paused = 0; switch ( cmd ) { case CLI_INIT: e->command = "queue add member"; e->usage = - "Usage: queue add member to [penalty [as [state_interface ]]]\n" + "Usage: queue add member to [penalty [as [state_interface [paused ]]]]\n" " Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n"; return NULL; case CLI_GENERATE: return complete_queue_add_member(a->line, a->word, a->pos, a->n); } - if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { + if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) { return CLI_SHOWUSAGE; } else if (strcmp(a->argv[4], "to")) { return CLI_SHOWUSAGE; @@ -11013,6 +11077,8 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as return CLI_SHOWUSAGE; } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { return CLI_SHOWUSAGE; + } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) { + return CLI_SHOWUSAGE; } queuename = a->argv[5]; @@ -11039,7 +11105,12 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as state_interface = a->argv[11]; } - switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL, 0)) { + if (a->argc >= 14) { + paused = 1; + reason = a->argv[13]; + } + + switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) { case RES_OKAY: if (ast_strlen_zero(membername) || !log_membername_as_agent) { ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample index 4207a01e2d..1b853eee6c 100644 --- a/configs/samples/queues.conf.sample +++ b/configs/samples/queues.conf.sample @@ -548,12 +548,12 @@ monitor-type = MixMonitor ; must also preload pbx_config.so and chan_local.so (or pbx_ael.so, pbx_lua.so, ; or pbx_realtime.so, depending on how your dialplan is configured). ; -; syntax: member => interface,[,penalty][,membername][,state_interface][,ringinuse][,wrapuptime] +; syntax: member => interface,[,penalty][,membername][,state_interface][,ringinuse][,wrapuptime][,paused] ; ;member => DAHDI/1 ;member => DAHDI/2,10 ;member => DAHDI/3,10,Bob Johnson ;member => Local/1001@agents,0,May Flowers,Agent:1001 ;member => Local/1002@agents,0,John Doe,Agent:1002 -;member => Local/1000@default,0,John Smith,SIP/1000 -;member => Local/2000@default,0,Lorem Ipsum,SIP/2000,no +;member => Local/1000@default,0,John Smith,PJSIP/1000 +;member => Local/2000@default,0,Lorem Ipsum,PJSIP/2000,no