Well, I have been working on this again, and ran into another issue that I need to resolve. Please bear with me, I am trying to make my explanation as clear as I can.
Working with the “Agent without agent channel” from the wiki and suggestions from the forum here, I have gotten dynamic agents to work fairly well.
The problem comes in when the dialplan attempts to “logoff” an agent that rejects or doesn’t answer calls. The dialplan runs RemoveQueueMember, but the caller in the queue hears this run and then gets disconnected.
Is there a way to hangup/disconnect the unanswered call and continue processing items in the dialplan? Perhaps I can initiate the agent “logout” another way preventing the queue caller from getting disconnected?
Here is what I have in extensions.conf. Please excuse the mess
exten => 8301,1,Goto(agent_login,s,1);
exten => 8302,1,Goto(agent_avail,s,1);
exten => 8303,1,Goto(agent_moretime,s,1);
[agent_call]
; Local/${agent}@agent_call are dynamic members
; added to semicolon-separated queues in AGENT1/valid tree
exten => _XXXX,1,SetVar(agent=${EXTEN});
exten => _XXXX,2,noop()
exten => _XXXX,2,ResponseTimeout(1);
exten => _XXXX,3,DBget(mychan=AGENT/${agent}/onChannel);
exten => _XXXX,4,Goto(check,1);
exten => _XXXX,104,Congestion(); oops, we shouldn’‘t be calling this agent
; check if channel in use
exten => check,1,ChanIsAvail(${mychan},s,);
exten => check,102,Goto(busy,1);
exten => check,2,DBget(wrapUpAt=AGENT/${agent}/wrapUpAt);
exten => check,3,GotoIf($[ $[${EPOCH} - ${wrapUpAt}] < 0]?busy,1);
exten => check,4,DBdel(AGENT/${agent}/wrapUpAt); expired, nuke it
exten => check,103,NoOp(agent ${agent} has no wrapUpAt in astdb == call);
exten => check,104,Goto(5);
; check availability
exten => check,5,DBget(avail=AGENT/${agent}/avail);
exten => check,6,GotoIf(${avail}?call,1:busy,1);
exten => check,106,NoOp(agent ${agent} has no avail in astdb == call);
exten => check,107,Goto(call,1);
; call agent
exten => call,1,SetVar(_ALERT_INFO=queue);
exten => call,2,UserEvent(QueueCall|Queue: ${queue});
exten => call,3,Dial(${mychan},15,gM(agent_answered^${agent}));
exten => call,4,Goto(call-${DIALSTATUS},1);
; handle dial results, auto-logout agent under two conditions
exten => call-BUSY,1,DBget(rejects=AGENT/${agent}/rejects);
exten => call-BUSY,102,SetVar(rejects=0);
exten => call-BUSY,103,Goto(2);
exten => call-BUSY,2,SetVar(rejects=$[${rejects} + 1]);
exten => call-BUSY,3,DBput(AGENT/${agent}/rejects=${rejects});
exten => call-BUSY,4,UserEvent(AgentReject,Agent: ${agent});
exten => call-BUSY,5,GotoIf($[${rejects} > 2]?slacker-rejects,1); 3 strikes you’‘re out (on DND?)
exten => call-BUSY,6,Hangup; keep their position
exten => call-NOANSWER,1,DBget(bounces=AGENT/${agent}/bounces);
exten => call-NOANSWER,102,SetVar(bounces=0);
exten => call-NOANSWER,103,Goto(2);
exten => call-NOANSWER,2,SetVar(bounces=$[${bounces} + 1]);
exten => call-NOANSWER,3,DBput(AGENT/${agent}/bounces=${bounces});
exten => call-NOANSWER,4,UserEvent(AgentBounce,Agent: ${agent});
exten => call-NOANSWER,5,GotoIf($[${bounces} > 2]?slacker-bounces,1); 3 strikes you’'re out (bouncing)
exten => call-NOANSWER,6,Hangup; keep their position
;
exten => slacker-bounces,1,SetVar(reason=bounced 3 calls);
exten => slacker-bounces,2,Goto(slacker,1);
exten => slacker-rejects,1,SetVar(reason=rejected 3 calls);
exten => slacker-rejects,2,Goto(slacker,1);
exten => slacker,1,UserEvent(AgentSlacker,Agent: ${agent});
exten => slacker,n,NoOp(agent ${agent} is a slacker: ${reason});
; res_perl required. this notifies the phone (sip message) and an IRC bot
; exten => slacker,n,Perl(notify_slacker.pl:${agent}:${reason}); "not using this"
exten => slacker,n,Goto(agent_login,logout,1); log them off
;
exten => busy,1,Busy();
exten => t,1,Hangup();
exten => i,1,Congestion();
[macro-agent_answered]
exten => s,1,DBdel(AGENT/${ARG1}/bounces);
exten => s,2,DBdel(AGENT/${ARG1}/rejects);
[agent_avail]
; toggle available status
exten => s,1,Answer;
exten => s,2,ResponseTimeout(1);
exten => s,3,Wait(1);
exten => s,4,ResponseTimeout(1);
exten => s,5,Cut(mychan=CHANNEL,-,1);
exten => s,6,DBget(agent=AGENT/channelHasAgent/${mychan});
exten => s,107,Goto(login,1);
exten => s,7,DBget(stat=AGENT/${agent}/avail);
exten => s,8,GotoIf(${stat}?unavail,1:avail,1);
; set unavailable, you slacker
exten => unavail,1,DBput(AGENT/${agent}/avail=0);
; exten => unavail,2,Playback(xm/agent-avail-no);
exten => unavail,2,Playback(abandon-all-hope); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => unavail,3,UserEvent(AgentUnavailable,Agent: ${agent});
; set available
exten => avail,1,DBput(AGENT/${agent}/avail=1);
; exten => avail,2,Playback(xm/agent-avail-yes);
exten => avail,2,Playback(welcome); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => avail,3,UserEvent(AgentAvailable,Agent: ${agent});
; not logged in
; exten => login,1,Playback(xm/agent-avail-login);
exten => login,1,Playback(airport); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => login,2,Goto(agent_login,s,1)
;
exten => t,1,Hangup();
exten => i,1,Playback(agent-avail-error); “More sounds needed”
[agent_moretime]
exten => s,1,Answer;
exten => s,2,ResponseTimeout(1);
exten => s,3,Wait(1);
exten => s,4,NoOp(agent needs more wrap up time);
exten => s,5,ResponseTimeout(1);
exten => s,6,Cut(mychan=CHANNEL,-,1);
exten => s,7,DBget(agent=AGENT/channelHasAgent/${mychan});
exten => s,108,Goto(login,1);
exten => s,8,DBput(AGENT/${agent}/wrapUpAt=$[${EPOCH} + ${WRAPUPTIME}]);
exten => s,9,Playback(another-time); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => s,10,UserEvent(AgentMoreTime,Agent: ${agent}, Until: $[${EPOCH} + ${WRAPUPTIME}]);
;
exten => login,1,Playback(airport); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => login,2,Goto(agent_login,s,1)
;
exten => t,1,Hangup();
exten => i,1,Playback(an-error-has-occured); ‘I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!’
[agent_login]
exten => s,1,Answer();
exten => s,2,Wait(1);
exten => s,3,ResponseTimeout(5);
exten => s,4,Cut(mychan=CHANNEL,-,1);
exten => s,5,DBget(agent=AGENT/channelHasAgent/${mychan});
exten => s,106,Goto(start,1);
exten => s,6,Goto(logout,1);
; a couple of read routines to get agent id
exten => start,1,Read(agent,agent-user);
exten => start,2,VMAuthenticate(${agent}@penzeys)
exten => start,3,Goto(verify,1);
exten => dupe,1,Read(continue,agent-alreadyon,9); 'Press 9 to logout existing connection I REALLY NEED TO CHANGE THIS AFTER I CREA$
exten => dupe,2,GotoIf($["${continue}" = “9”]?3:4);
exten => dupe,3,Goto(logout,1);
exten => dupe,4,Read(agent,agent-user); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => dupe,5,Goto(verify,1);
exten => bad,1,Read(agent,agent-incorrect); 'I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!'
exten => bad,2,Goto(verify,1);
; verification
exten => verify,1,DBget(onchan=AGENT/${agent}/onChannel);
exten => verify,102,Goto(3);
exten => verify,2,GotoIf($["${onchan}" = “{mychan}”]?logout,1:dupe,1);
exten => verify,3,DBget(queues=AGENT1/valid/${agent});
exten => verify,104,Goto(bad,1);
exten => verify,4,Goto(login,1);
; login routine
exten => login,1,DBput(AGENT/channelHasAgent/${mychan}=${agent});
exten => login,2,DBput(AGENT/${agent}/onChannel=${mychan});
exten => login,3,DBput(AGENT/${agent}/avail=1);
exten => login,4,SetVar(i=1);
exten => login,5,Cut(j=queues,:,${i});
exten => login,6,While($[${LEN(${j})} > 0]);
exten => login,7,AddQueueMember(${j},Local/${agent}@agent_call);
exten => login,8,SetVar(i=$[${i} + 1]);
exten => login,9,Cut(j=queues,:,${i});
exten => login,10,EndWhile;
exten => login,11,Playback(agent-loginok);
exten => login,12,Goto(t,1);
; logout, leave configured queues
exten => logout,1,playback(wait-moment);
exten => logout,2,DBget(queues=AGENT1/valid/${agent});
exten => logout,3,SetVar(i=1);
exten => logout,4,Cut(j=queues,:,${i});
exten = logout,5,noop(i)
exten = logout,6,noop(j)
exten => logout,7,While($[${LEN(${j})} > 0])
exten => logout,8,RemoveQueueMember(${j},Local/${agent}@agent_call);
exten => logout,9,SetVar(i=$[${i} + 1]);
exten => logout,10,Cut(j=queues,:,${i});
exten => logout,11,EndWhile;
exten => logout,12,DBget(agentchan=AGENT/${agent}/onChannel);
;exten => logout,n,DBdel(AGENT/channelHasAgent/${mychan});
exten = logout,13,noop()
exten => logout,14,DBdel(AGENT/channelHasAgent/${agentchan});
exten => logout,15,DBdeltree(AGENT/${agent});
exten => logout,16,Playback(agent-loggedoff,skip);
exten => logout,17,GotoIf($["${continue}" = “1”]?login,1); logging off a dupe, go back
exten => logout,18,Goto(t,1);
;
exten => t,1,Hangup;
exten => i,1,Playback(an-error-has-occured); ‘I REALLY NEED TO CHANGE THIS AFTER I CREATE A SOUND FILE FOR IT!’