diff --git a/include_apps/oacd_freeswitch/src/freeswitch_fetch_handler.erl b/include_apps/oacd_freeswitch/src/freeswitch_fetch_handler.erl new file mode 100644 index 00000000..1c01bcb5 --- /dev/null +++ b/include_apps/oacd_freeswitch/src/freeswitch_fetch_handler.erl @@ -0,0 +1,263 @@ +%% @doc Fetch handler for freeswitch sip authentication. Adds trigger for +%% the auth_agent_success hook to nab the agent password and generate some +%% a1 hashes for it. + +-module(freeswitch_fetch_handler). +-behavior(gen_server). + +-include_lib("OpenACD/include/log.hrl"). + +-define(default_dial_string(Type), case Type of + sip_registration -> "sofia/internal/$1%"; + sip -> "sofia/internal/sip:$1"; + iax2 -> "iax2/$1"; + h323 -> "opal/h3232:$1"; + pstn -> ""; + rtmp -> "rtmp/$1" +end). +-define(EMPTYRESPONSE, ""). +-define(NOTFOUNDRESPONSE, +" +
+ +
+
"). + +-define(DIALUSERRESPONSE, +" +
+ + + + + + + +
+
"). + +-define(REGISTERRESPONSE, +" +
+ + + + + + + + + + +
+
"). + +-define(USERRESPONSE, +" +
+ + + + +
+
"). + +-define(ets, oacd_freeswitch_a1). + +% gen_server +-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2, + code_change/3]). +% public api +-export([start_link/3,hook_callback/3,set_hook/0]). + +%% ====================================================================== +%% API +%% ====================================================================== + + +start_link(Freeswitch,DialstringBases,SipAuth) when SipAuth =:= sip_auth; SipAuth =:= no_sip_auth -> + Pid = proc_lib:spawn_link(fun() -> + {foo, Freeswitch} ! {bind, directory}, + receive + ok -> + erlang:register(?MODULE,self()), + {ok, State} = init({Freeswitch,DialstringBases,SipAuth}), + gen_server:enter_loop(?MODULE,[],State,{local, ?MODULE}); + {error,Reason} -> + exit(Reason) + after 5000 -> + exit(timeout) + end + end), + {ok, Pid}. + +hook_callback(User, Pass, _Res) -> + ?DEBUG("Hook triggered for user auth: ~p", [User]), + {ok, Ifs} = inet:getif(), + IfsToIpStrings = fun({Ip,_,_},Acc) -> + {A,B,C,D} = Ip, + Ips = lists:flatten(io_lib:format("~p.~p.~p.~p",[A,B,C,D])), + [Ips | Acc] + end, + Localhost = net_adm:localhost(), + IpStrings = lists:foldl(IfsToIpStrings,[Localhost],Ifs), + Hashes = [{IPString,util:bin_to_hexstr(erlang:md5(User++":"++IPString++":"++Pass))} || IPString <- IpStrings], + ets:insert(?ets, {User, Hashes}). + +set_hook() -> + cpx_hooks:set_hook(?MODULE, auth_agent_success, {?MODULE, hook_callback, []}). + +%% ====================================================================== +%% gen_server +%% ====================================================================== + +%% ---------------------------------------------------------------------- +%% init +%% ---------------------------------------------------------------------- + +init({Freeswitch,Dialstrings,SipAuth}) -> + ets:new(?ets, [named_table, public]), + set_hook(), + ?INFO("Started",[]), + {ok, {Freeswitch,Dialstrings,SipAuth}}. + +%% ---------------------------------------------------------------------- +%% handle_call +%% ---------------------------------------------------------------------- + +handle_call(_Msg,_From,State) -> + {reply, {error, invalid},State}. + +%% ---------------------------------------------------------------------- +%% handle_cast +%% ---------------------------------------------------------------------- + +handle_cast(_Msg,State) -> + {noreply,State}. + +%% ---------------------------------------------------------------------- +%% handle_info +%% ---------------------------------------------------------------------- + +handle_info({fetch, directory, "domain", "name", _Value, Id, [undefined | Data]}, State) -> + %?DEBUG("The data: ~p", [Data]), + case proplists:get_value("as_channel", Data) of + "true" -> + fetch_as_channel(Id,Data,State); + _Else -> + case proplists:get_value("action",Data) of + "sip_auth" -> + fetch_sip_auth(Id,Data,State); + _ -> + fetch_user_lookup(Id,Data,State) + end + end, + {noreply, State}; + +handle_info({fetch, _Section, _Something, _Key, _Value, ID, [undefined | _Data]},{Node,_,_}=State) -> + freeswitch:fetch_reply(Node, ID, ?EMPTYRESPONSE), + {noreply,State}; + +handle_info({nodedown,Node},{Node,_,_}=State) -> + {stop,nodedown,State}; + +handle_info(_Msg,State) -> + {noreoply,State}. + +%% ---------------------------------------------------------------------- +%% terminate +%% ---------------------------------------------------------------------- + +terminate(_Why,_State)-> ok. + +%% ---------------------------------------------------------------------- +%% code_change +%% ---------------------------------------------------------------------- + +code_change(_Old,State,_Extra) -> + {ok,State}. + +%% ====================================================================== +%% Internal +%% ====================================================================== + +fetch_user_lookup(Id,_Data,{Node,_,no_sip_auth}) -> + ?DEBUG("Lookup when not doing sip auth, empty response",[]), + % I guess we're just looking up a user? + % Looking up for first part of an auth most likely. + % only auth we support is sip (which is above) so we'll + % depend on that. + freeswitch:fetch_reply(Node, Id, ?EMPTYRESPONSE); + +fetch_user_lookup(ID,Data,{Node,_,_}) -> + User = proplists:get_value("user", Data), + Domain = proplists:get_value("domain", Data), + case agent_manager:query_agent(User) of + {true, _Pid} -> + ?DEBUG("Lookup succeeded for user ~s@~s", [User,Domain]), + freeswitch:fetch_reply(Node, ID, lists:flatten(io_lib:format(?USERRESPONSE, [Domain, User]))); + false -> + freeswitch:fetch_reply(Node, ID, ?EMPTYRESPONSE) + end. + +fetch_sip_auth(ID,_Data,{Node,_,no_sip_auth}) -> + %% not doing sip auth, return nothing + ?DEBUG("Not doing SIP auth", []), + freeswitch:fetch_reply(Node, ID, ""); + +fetch_sip_auth(ID,Data,{Node,_,sip_auth}) -> + User = proplists:get_value("user", Data), + Domain = proplists:get_value("domain", Data), + Realm = proplists:get_value("sip_auth_realm", Data), + % TODO Can this be done w/o dealing w/ a plain text pw? + case ets:lookup(?ets, User) of + [] -> + ?DEBUG("Sip auth ~s@~s for relam ~s is not found",[User,Domain,Realm]), + freeswitch:fetch_reply(Node, ID, ?EMPTYRESPONSE); + [{User,Hashes}] -> + case proplists:get_value(Realm,Hashes) of + undefined -> + ?DEBUG("Sip auth ~s@~s for relam ~s has no hash",[User,Domain,Realm]), + freeswitch:fetch_reply(Node, ID, ?EMPTYRESPONSE); + Hash -> + ?DEBUG("Sip auth ~s@~s for relam ~s found hash ~s",[User,Domain,Realm,Hash]), + freeswitch:fetch_reply(Node, ID, lists:flatten(io_lib:format(?REGISTERRESPONSE,[Domain,User,Hash]))) + end + end. + +fetch_as_channel(ID,Data,{Node,State,_}) -> + User = proplists:get_value("user", Data), + Domain = proplists:get_value("domain", Data), + case agent_manager:query_agent(User) of + {true, Pid} -> + try agent:dump_state(Pid) of + Agent -> + {ok, {Opts, _}} = agent:get_endpoint(freeswitch_media, Agent), + Type = proplists:get_value(type, Opts), + Dat = proplists:get_value(data, Opts), + + DialString = case {Type, Dat} of + {sip_registration, undefined} -> + "${sofia_contact("++User++"@"++Domain++")}"; + {sip_registration, D} -> + "${sofia_contact("++re:replace(D, "@", "_", [{return, list}])++"@"++Domain++")}"; + {sip, D} -> + freeswitch_media_manager:do_dial_string(proplists:get_value(sip, State, "sofia/internal/sip:"), D, []); + {iax2, D} -> + freeswitch_media_manager:do_dial_string(proplists:get_value(iax2, State, "iax2/"), D, []); + {h323, D} -> + freeswitch_media_manager:do_dial_string(proplists:get_value(h323, State, "opal/h323:"), D, []); + {pstn, D} -> + freeswitch_media_manager:do_dial_string(proplists:get_value(dialstring, State, ""), D, []); + {rtmp,D} -> + freeswitch_media_manager:do_dial_string(proplists:get_value(rtmp, State, "rtmp/$1"), D, []) + end, + ?NOTICE("returning ~s for user directory entry ~s", [DialString, User]), + freeswitch:fetch_reply(Node, ID, lists:flatten(io_lib:format(?DIALUSERRESPONSE, [Domain, User, DialString]))) + catch + _:_ -> % agent pid is toast? + freeswitch:fetch_reply(Node, ID, ?NOTFOUNDRESPONSE) + end; + false -> + freeswitch:fetch_reply(Node, ID, ?NOTFOUNDRESPONSE) + end. diff --git a/include_apps/oacd_freeswitch/src/freeswitch_media.erl b/include_apps/oacd_freeswitch/src/freeswitch_media.erl index ff47a52f..6f444063 100644 --- a/include_apps/oacd_freeswitch/src/freeswitch_media.erl +++ b/include_apps/oacd_freeswitch/src/freeswitch_media.erl @@ -146,24 +146,33 @@ %%==================================================================== %% API %%==================================================================== -%% @doc starts the freeswitch media gen_server. `Cnode' is the C node the communicates directly with freeswitch. + +%% @doc starts the freeswitch media gen_media. `Cnode' is the C node the +%% communicates directly with freeswitch. Dialstring is the data used to +%% connect to an outside line. UUID is the id of the channel on +%% freeswith, and therefore the id of the call in OpenACD. -spec(start/3 :: (Cnode :: atom(), DialString :: string(), UUID :: string()) -> {'ok', pid()}). start(Cnode, DialString, UUID) -> gen_media:start(?MODULE, [Cnode, DialString, UUID]). +%% @doc Starts the freeswitch gen_media linked to the calling process. +%% @see start/3 -spec(start_link/3 :: (Cnode :: atom(), DialString :: string(), UUID :: string()) -> {'ok', pid()}). start_link(Cnode, DialString, UUID) -> gen_media:start_link(?MODULE, [Cnode, DialString, UUID]). -%% @doc returns the record of the call freeswitch media `MPid' is in charge of. +%% @doc returns the record of the call freeswitch media `MPid' is in +%% charge of. -spec(get_call/1 :: (MPid :: pid()) -> #call{}). get_call(MPid) -> gen_media:get_call(MPid). +%% @doc A debugging function that returns the state record. -spec(dump_state/1 :: (Mpid :: pid()) -> #state{}). dump_state(Mpid) when is_pid(Mpid) -> gen_media:call(Mpid, dump_state). +%% @hidden '3rd_party_pickup'(Mpid) -> Self = self(), gen_media:cast(Mpid, {'3rd_party_pickup', Self}). @@ -171,6 +180,7 @@ dump_state(Mpid) when is_pid(Mpid) -> %%==================================================================== %% gen_media callbacks %%==================================================================== + %% @private init([Cnode, DialString, UUID]) -> process_flag(trap_exit, true), @@ -179,10 +189,12 @@ init([Cnode, DialString, UUID]) -> Call = #call{id = UUID, source = self(), client = Client, priority = Priority, callerid={CidName, CidNum}, dnis=DNIS, media_path = inband}, {ok, {#state{statename = inivr, cnode=Cnode, manager_pid = Manager, dialstring = DialString, dial_vars = ["sip_h_X-FromData='"++SIPFrom++"'"], uuid = UUID}, Call, {inivr, [DNIS]}}}. +%% @private -spec(urlpop_getvars/1 :: (State :: #state{}) -> [{binary(), binary()}]). urlpop_getvars(#state{ivroption = Ivropt} = _State) -> [{"itxt", Ivropt}]. +%% @private -spec(handle_announce/3 :: (Announcement :: string(), Callrec :: #call{}, State :: #state{}) -> {'ok', #state{}}). handle_announce(Announcement, Callrec, State) -> freeswitch:sendmsg(State#state.cnode, Callrec#call.id, @@ -195,6 +207,19 @@ handle_announce(Announcement, Callrec, State) -> %% perpare_endpoint %%-------------------------------------------------------------------- +-type(agent_registration_type() :: 'sip' | 'sip_registration' | 'h323' | + 'iax2' | 'pstn'). +-type(agent_registration_data_opt() :: {'date', string()}). +-type(agent_registration_type_opt() :: {'type', agent_registration_type()}). +-type(persistant_ring_opt() :: 'persistant'). +-type(endpoint_opt() :: persistant_ring_opt() | + agent_registration_type_opt() | agent_registration_data_opt()). +-type(endpoint_opts() :: [endpoint_opt()]). +-type(freeswitch_ring_endpoint() :: pid() | {'freeswitch_ring','start',[_]}). +%% @doc Handle an agent being setup with a freeswitch_media endpoint. +%% Options uses defaults of [{type,sip_registration},{data,agent_login()}]. +-spec(prepare_endpoint/2 :: (Agent :: #agent{}, Options :: endpoint_opts()) + -> {'ok', freeswitch_ring_endpoint()}). prepare_endpoint(Agent, Options) -> {Node, Dialstring, Dest} = freeswitch_media_manager:get_ring_data(Agent, Options), case proplists:get_value(persistant, Options) of @@ -214,6 +239,7 @@ prepare_endpoint(Agent, Options) -> %% handle_answer %%-------------------------------------------------------------------- +%% @hidden handle_answer(Apid, StateName, Callrec, GenMediaState, State) when StateName =:= inqueue_ringing; StateName =:= oncall_ringing -> {RingUUID, RingPid} = case GenMediaState of @@ -251,7 +277,9 @@ handle_answer(Apid, StateName, Callrec, GenMediaState, State) when {error, Error, State} end. -%% TODO added for testing only (implemented with focus on real Calls - no other media) + +% TODO added for testing only (implemented with focus on real Calls - no other media) +%% @hidden -spec(handle_end_call/4 :: (GMState :: atom(), Callrec :: #call{}, GMStateData :: any(), State :: #state{}) -> {'ok', #state{}}). handle_end_call(_Gmstate, Callrec, _Gmstatedata, State) -> @@ -260,6 +288,7 @@ handle_end_call(_Gmstate, Callrec, _Gmstatedata, State) -> {"hangup-cause", "SUBSCRIBER_ABSENT"}]), {deferred, State}. +%% @hidden handle_ring(Apid, RingData, Callrec, State) when is_pid(Apid) -> ?INFO("ring to agent ~p for call ~s", [Apid, Callrec#call.id]), % TODO - we could avoid this if we had the agent's login, @@ -281,6 +310,7 @@ handle_ring({Apid, #agent{ring_channel = {RPid, transient, _}} = AgentRec}, _Rin {ok, [{"itxt", State#state.ivroption}], State#state{statename = NewStatename, agent_pid = Apid, ringchannel = RPid}}. % TODO This needs to be updated when conferencing is fixed. +%% @hidden handle_ring_stop(_StateName, Callrec, _GenMedia, #state{xferchannel = RingChannel} = State) when is_pid(RingChannel) -> ?DEBUG("hanging up transfer channel for ~p", [Callrec#call.id]), freeswitch_ring:hangup(RingChannel), @@ -303,6 +333,7 @@ handle_ring_stop(_StateName, Callrec, _GenMedia, State) -> end, {ok, State#state{statename = NewStatename, ringchannel=undefined}}. +%% @hidden -spec(handle_voicemail/3 :: (Agent :: pid() | 'undefined', Call :: #call{}, State :: #state{}) -> {'ok', #state{}}). handle_voicemail(Agent, Callrec, State) when is_pid(Agent) -> {ok, Midstate} = handle_ring_stop(undefined, Callrec, undefined, State), @@ -312,6 +343,7 @@ handle_voicemail(undefined, Call, State) -> freeswitch:bgapi(State#state.cnode, uuid_transfer, UUID ++ " 'playback:IVR/prrec.wav,gentones:%(500\\,0\\,500),sleep:600,record:/tmp/${uuid}.wav' inline"), {ok, State#state{statename = inivr, voicemail = "/tmp/"++UUID++".wav"}}. +%% @hidden -spec(handle_spy/3 :: (Agent :: {pid(), #agent{}}, Call :: #call{}, State :: #state{}) -> {'error', 'bad_agent', #state{}} | {'ok', #state{}}). handle_spy({Agent, AgentRec}, Call, #state{cnode = Fnode, ringchannel = Chan} = State) when is_pid(Chan) -> agent:blab(Agent, "While spying, you have the following options:\n"++ @@ -325,6 +357,7 @@ handle_spy({Agent, AgentRec}, Call, #state{cnode = Fnode, ringchannel = Chan} = handle_spy(_Agent, _Call, State) -> {invalid, State}. +%% @hidden handle_agent_transfer(AgentPid, Timeout, Call, State) -> AgentRec = agent:dump_state(AgentPid), % TODO - avoid this ?INFO("transfer_agent to ~p for call ~p", [AgentRec#agent.login, Call#call.id]), @@ -346,6 +379,7 @@ handle_agent_transfer(AgentPid, Timeout, Call, State) -> {error, Error, State} end. +%% @hidden handle_wrapup(_From, _StateName, #call{media_path = inband} = Call, _GenMediaState, State) -> ?DEBUG("Handling wrapup request", []), % TODO This could prolly stand to be a bit more elegant. @@ -356,7 +390,8 @@ handle_wrapup(_From, _StateName, _Call, _GenMediaState, State) -> % no direct hangup by the agent ?DEBUG("Not doing wrapup request", []), {ok, State}. - + +%% @hidden handle_queue_transfer(_Queue, _StateName, Call, _GenMediaState, #state{cnode = Fnode} = State) -> case State#state.record_path of undefined -> diff --git a/include_apps/oacd_freeswitch/src/freeswitch_media_manager.erl b/include_apps/oacd_freeswitch/src/freeswitch_media_manager.erl index 2b2c3cd4..9de47b9e 100644 --- a/include_apps/oacd_freeswitch/src/freeswitch_media_manager.erl +++ b/include_apps/oacd_freeswitch/src/freeswitch_media_manager.erl @@ -27,13 +27,14 @@ %% Micah Warren %% -%% @doc The controlling module for connection CPX to a freeswitch +%% @doc The controlling module for connection OpenACD to a freeswitch %% installation. There are 2 primary requirements for this work: -%% the freeswitch installaction must have mod_erlang installed and active, and the freeswitch dialplan must add the following -%% variables to the call data: +%% the freeswitch installation must have mod_erlang installed and active, +%% and the freeswitch dialplan must add the following variables added +%% to the call data: %%
-%%
queue
The name of the queue as entered into the queue_manager
-%%
brand
As the combined brand id
+%%
queue
The name of the queue as configured in OpenACD
+%%
brand
The Id of the client to associate the call with
%%
%% Primary job of this module is to listen to freeswitch for events, and %% shove those events to the appriate child process. @@ -371,9 +372,9 @@ init([Nodename, Options]) -> Lpid = start_listener(Nodename), freeswitch:event(Nodename, ['CHANNEL_DESTROY']), StrippedOpts = [ X || {Key, _} = X <- Options, Key /= domain], - {ok, Pid} = freeswitch:start_fetch_handler(Nodename, directory, ?MODULE, fetch_domain_user, StrippedOpts), - link(Pid), - {Lpid, Pid, StrippedOpts}; + %{ok, Pid} = freeswitch:start_fetch_handler(Nodename, directory, ?MODULE, fetch_domain_user, StrippedOpts), + %link(Pid), + {Lpid, undefined, StrippedOpts}; _ -> StrippedOpts = [ X || {Key, _} = X <- Options, Key /= domain], {undefined, undefined, StrippedOpts} @@ -866,6 +867,7 @@ fetch_domain_user(Node, State) -> Domain = proplists:get_value("domain", Data), Realm = proplists:get_value("sip_auth_realm", Data), % TODO Can this be done w/o dealing w/ a plain text pw? + ?DEBUG("Sip auth\n\tUser: ~p\n\tdomain: ~p\n\tRelam: ~p",[User,Domain,Realm]), freeswitch:fetch_reply(Node, ID, ?EMPTYRESPONSE) % case agent_manager:query_agent(User) of % {true, Pid} -> diff --git a/include_apps/oacd_freeswitch/src/oacd_freeswitch_sup.erl b/include_apps/oacd_freeswitch/src/oacd_freeswitch_sup.erl index f46d0d2c..528c5016 100644 --- a/include_apps/oacd_freeswitch/src/oacd_freeswitch_sup.erl +++ b/include_apps/oacd_freeswitch/src/oacd_freeswitch_sup.erl @@ -10,4 +10,13 @@ start_link(FsNode, Args) -> init({FsNode, Args}) -> MFA = {freeswitch_media_manager, start_link, [FsNode, Args]}, Kid = {freeswitch_media_manager, MFA, permanent, 1000, worker, [freeswitch_media_manager]}, - {ok, {{one_for_one, 5, 10}, [Kid]}}. + + SipAuth = case proplists:get_bool(sipauth,Args) of + sipauth -> sip_auth; + true -> sip_auth; + _ -> no_sip_auth + end, + MFA2 = {freeswitch_fetch_handler, start_link, [FsNode,Args,SipAuth]}, + Kid2 = {freeswitch_fetch_handler, MFA2, permanent, 1000, worker, [freeswitch_fetch_handler]}, + + {ok, {{one_for_one, 5, 10}, [Kid,Kid2]}}. diff --git a/priv/www/admin/openacd/queues.js b/priv/www/admin/openacd/queues.js index db40da26..fe607b46 100644 --- a/priv/www/admin/openacd/queues.js +++ b/priv/www/admin/openacd/queues.js @@ -271,11 +271,12 @@ queues.newQueue = function(form, reciper, node){ } }); }; - queues.store.fetchItemByIdentity({ - identity:vals.group, - onItem:function(i){ - vals.group = queues.store.getValue(i, 'name'); - doxhr(); - } - }); + var group = queues.store.query({'name':vals.group}); + if(group.length){ + group = group[0]; + } else { + group = 'Default'; + } + vals.group = group; + doxhr(); }; diff --git a/src/agent_auth.erl b/src/agent_auth.erl index e1aab6a6..386cbd1b 100644 --- a/src/agent_auth.erl +++ b/src/agent_auth.erl @@ -87,6 +87,23 @@ %% %% Aysnchronously triggers all hooks when an agent is created. %% Args :: [Record :: #agent_auth{}] +%% +%% === auth_agent === +%% +%% Synchronously triggers hooks until one returns a response. If no hooks +%% return a response, a denial is returned. +%% +%% Args :: [Username :: string(), Password :: string()] +%% Returns :: 'deny' | {'allow', string(), skill_list(), security_level(), +%% profile_name()}). +%% +%% === auth_agent_success === +%% +%% Asynchronously triggers all hooks when an agent is successfully +%% authenticated. +%% +%% Args :: [Username :: string(), Password :: string(), +%% Return :: auth_agent_return()] -module(agent_auth). @@ -428,7 +445,10 @@ get_extended_prop({_, _} = U, Prop) -> -spec(auth/2 :: (Username :: string(), Password :: string()) -> 'deny' | {'allow', string(), skill_list(), security_level(), profile_name()}). auth(Username, Password) -> case cpx_hooks:trigger_hooks(auth_agent, [Username, Password], first) of - {ok, Res} -> Res; + {ok, deny} -> deny; + {ok, Res} -> + cpx_hooks:async_trigger_hooks(auth_agent_success, [Username, Password, Res]), + Res; _ -> deny end. diff --git a/src/cpx.erl b/src/cpx.erl index e0d6ace8..9bbc1b02 100644 --- a/src/cpx.erl +++ b/src/cpx.erl @@ -80,6 +80,7 @@ unload_plugin/1, load_plugin/1, plugins_running/0, + set_plugin_env/2, call_state/1, get_queue/1, get_agent/1, @@ -331,6 +332,17 @@ load_plugin(Plugin) -> end end. +%% @doc Sets the application variables for a plugin. +-spec set_plugin_env(PluginName :: atom(), Env :: [{atom(),any()}]) -> 'ok'. +set_plugin_env(_PluginName, []) -> + ok; +set_plugin_env(PluginName, [{Key,Val}|Tail]) -> + application:set_env(PluginName, Key, Val), + set_plugin_env(PluginName,Tail); +set_plugin_env(PluginName, [Key | Tail]) when is_atom(Key) -> + application:set_env(PluginName, Key, true), + set_plugin_env(PluginName,Tail). + -spec(get_queue/1 :: (Queue :: string()) -> pid() | 'none'). get_queue(Queue) -> queue_manager:get_queue(Queue). diff --git a/src/cpx_web_management.erl b/src/cpx_web_management.erl index a6faab27..96483e07 100644 --- a/src/cpx_web_management.erl +++ b/src/cpx_web_management.erl @@ -1018,8 +1018,13 @@ api({queues, "queue", Queue, "update"}, ?COOKIE, Post) -> queue_manager:load_queue(Queue), {200, [], mochijson2:encode({struct, [{success, true}]})}; api({queues, "queue", Queue, "delete"}, ?COOKIE, _Post) -> - call_queue_config:destroy_queue(Queue), - {200, [], mochijson2:encode({struct, [{success, true}]})}; + case call_queue_config:get_queue(Queue) of + noexists -> + {200, [], mochijson2:encode({struct, [{success, false}, {<<"message">>, <<"No such queue">>}]})}; + Queuerec -> + call_queue_config:destroy_queue(Queuerec), + {200, [], mochijson2:encode({struct, [{success, true}]})} + end; api({queues, "queue", "new"}, ?COOKIE = Cookie, Post) -> Name = proplists:get_value("name", Post), Qrec = #call_queue{ @@ -2066,7 +2071,8 @@ api({modules, Node, "freeswitch_media_manager", "update"}, ?COOKIE, Post) -> Atomnode = list_to_existing_atom(Node), case proplists:get_value("enabled", Post) of undefined -> - rpc:call(Atomnode, cpx_supervisor, destroy, [freeswitch_media_manager], 2000), + rpc:call(Atomnode, cpx, unload_plugin, [oacd_freeswitch]), + %rpc:call(Atomnode, cpx_supervisor, destroy, [freeswitch_media_manager], 2000), {200, [], mochijson2:encode({struct, [{success, true}]})}; _Else -> PostToProp = [ @@ -2086,14 +2092,16 @@ api({modules, Node, "freeswitch_media_manager", "update"}, ?COOKIE, Post) -> end, MidOptions = lists:foldl(Builder, [], PostToProp), Options = [X || {_K, Val} = X <- MidOptions, Val =/= ""], - Args = [list_to_atom(proplists:get_value("cnode", Post)), Options], - Conf = #cpx_conf{ - id = freeswitch_media_manager, - module_name = freeswitch_media_manager, - start_function = start_link, - supervisor = mediamanager_sup, - start_args = Args}, - rpc:call(Atomnode, cpx_supervisor, update_conf, [freeswitch_media_manager, Conf], 2000), + Args = [{freeswitch_node, list_to_atom(proplists:get_value("cnode", Post))} | Options], + Args0 = case proplists:get_value(sipauth,Args) of + "sipauth" -> [sipauth | proplists:delete(sipauth,Args)]; + _ -> proplists:delete(sipauth,Args) + end, + %Conf = #cpx_conf{ id = freeswitch_media_manager, module_name = freeswitch_media_manager, start_function = start_link, supervisor = mediamanager_sup, start_args = Args}, + %rpc:call(Atomnode, cpx_supervisor, update_conf, [freeswitch_media_manager, Conf], 2000), + rpc:call(Atomnode, cpx, set_plugin_env, [oacd_freeswitch, Args0]), + rpc:call(Atomnode, cpx, reload_plugin, [oacd_freeswitch]), + rpc:call(Atomnode, application, start, [oacd_freeswitch]), {200, [], mochijson2:encode({struct, [{success, true}]})} end; api({modules, Node, "freeswitch_media_manager", "get"}, ?COOKIE, _Post) ->