Add support for multiple caller pins

In config.ini, add the [pins] section, with key/value entries
for the expected pin and the channel regex to switch to when
the caller enters the pin. Here's an example:

[pins]
12345 = DevOps Team
23456 = Sales Team
This commit is contained in:
Scott Hardin 2017-05-27 22:12:26 +02:00
parent d3213be149
commit 75cafbfefe
9 changed files with 82 additions and 57 deletions

View File

@ -3,6 +3,7 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
using namespace config;
@ -50,4 +51,15 @@ std::string config::Configuration::getString(const std::string &property) {
return get<std::string>(impl->ptree, property);
}
// TODO: return set
std::unordered_map<std::string, std::string> config::Configuration::getChildren(const std::string &property) {
std::unordered_map<std::string, std::string> pins;
BOOST_FOREACH(boost::property_tree::ptree::value_type &v,
impl->ptree.get_child(property)) {
//pins[v.first.data()] = get<std::string>(impl->ptree, property + "." + v.second.data());
pins[v.first.data()] = v.second.data();
}
return pins;
}

View File

@ -5,6 +5,7 @@
#include <vector>
#include <string>
#include <stdexcept>
#include <unordered_map>
namespace config {
@ -31,6 +32,8 @@ namespace config {
std::string getString(const std::string &property);
std::unordered_map<std::string, std::string> getChildren(const std::string &property);
private:
ConfigurationImpl *impl;
};

View File

@ -50,3 +50,9 @@ void mumble::MumbleChannelJoiner::findJoinChannel(mumble::MumbleCommunicator *mc
}
}
void mumble::MumbleChannelJoiner::joinOtherChannel(mumble::MumbleCommunicator *mc, std::string channelNameRegex) {
this->channelNameRegex = boost::regex(channelNameRegex);
findJoinChannel(mc);
}

View File

@ -22,6 +22,7 @@ namespace mumble {
void checkChannel(std::string channel_name, int channel_id);
void maybeJoinChannel(mumble::MumbleCommunicator *mc);
void findJoinChannel(mumble::MumbleCommunicator *mc);
void joinOtherChannel(mumble::MumbleCommunicator *mc, std::string channelNameRegex);
private:
log4cpp::Category &logger;

View File

@ -121,8 +121,8 @@ namespace sip {
class _Account : public pj::Account {
public:
_Account(sip::PjsuaCommunicator &comm)
: communicator(comm) { }
_Account(sip::PjsuaCommunicator &comm, int max_calls)
: communicator(comm) { this->max_calls = max_calls; }
virtual void onRegState(pj::OnRegStateParam &prm) override;
@ -131,7 +131,8 @@ namespace sip {
private:
sip::PjsuaCommunicator &communicator;
bool available = true;
int active_calls = 0;
int max_calls;
friend class _Call;
};
@ -166,7 +167,7 @@ namespace sip {
* if no pin is set, go ahead and turn off mute/deaf
* otherwise, wait for pin to be entered
*/
if ( communicator.caller_pin.length() == 0 ) {
if ( communicator.pins.size() == 0 ) {
// No PIN set... enter DTMF root menu and turn off mute/deaf
communicator.dtmf_mode = DTMF_MODE_ROOT;
// turning off mute automatically turns off deaf
@ -185,7 +186,11 @@ namespace sip {
} else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
auto &acc = dynamic_cast<_Account &>(account);
if (not acc.available) {
/*
* Not sure why we check acc.available, but with multi-call
* functionality, this check doesn't work.
*/
//if (not acc.available) {
auto msgText = "Call from " + address + " finished.";
communicator.calls[ci.id].mixer->clear();
@ -198,8 +203,9 @@ namespace sip {
communicator.calls[ci.id].onDisconnect();
acc.available = true;
}
//acc.available = true;
acc.active_calls--;
//}
delete this;
} else {
@ -221,7 +227,7 @@ namespace sip {
communicator.calls[ci.id].media->startTransmit(*aud_med);
aud_med->startTransmit(*communicator.calls[ci.id].media);
} else if (ci.media[0].status == PJSUA_CALL_MEDIA_NONE) {
dynamic_cast<_Account &>(account).available = true;
dynamic_cast<_Account &>(account).active_calls++;
}
}
@ -293,6 +299,7 @@ namespace sip {
pj::CallOpParam param;
auto ci = getInfo();
std::string chanName;
/*
* DTMF CALLER MENU
@ -308,11 +315,15 @@ namespace sip {
/*
* When user presses '#', test PIN entry
*/
if ( communicator.caller_pin.length() > 0 ) {
if ( communicator.got_dtmf == communicator.caller_pin ) {
if ( communicator.pins.size() > 0 ) {
if ( communicator.pins.count(communicator.got_dtmf) > 0 ) {
communicator.logger.info("Caller entered correct PIN");
communicator.dtmf_mode = DTMF_MODE_ROOT;
communicator.calls[ci.id].joinAuthChannel();
communicator.logger.notice("MYDEBUG: %s:%s",
communicator.got_dtmf.c_str(),
communicator.pins[communicator.got_dtmf].c_str());
communicator.calls[ci.id].joinOtherChannel(
communicator.pins[communicator.got_dtmf]);
this->playAudioFile(communicator.file_entering_channel);
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
@ -386,12 +397,23 @@ namespace sip {
this->playAudioFile(communicator.file_mute_off);
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
break;
case '0':
case '9':
if ( communicator.pins.size() > 0 ) {
communicator.dtmf_mode = DTMF_MODE_UNAUTH;
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_DEAF, true);
communicator.calls[ci.id].joinDefaultChannel();
this->playAudioFile(communicator.file_prompt_pin);
} else {
// we should have a 'not supported' message
}
break;
case '0': // block these for the menu itself
case '*':
default:
// play menu
communicator.logger.info("Unsupported DTMF digit '%s' in state STAR", prm.digit.c_str());
this->playAudioFile(communicator.file_menu);
break;
default:
communicator.logger.info("Unsupported DTMF digit '%s' in state STAR", prm.digit.c_str());
}
/*
* In any case, switch back to root after one digit
@ -422,17 +444,13 @@ namespace sip {
if (communicator.uriValidator.validateUri(uri)) {
if (available) {
if (active_calls < max_calls) {
param.statusCode = PJSIP_SC_OK;
available = false;
active_calls++;
} else {
/*
* EXPERIMENT WITH MULTI-LINE
*/
communicator.logger.info("MULTI-LINE Incoming call from %s.", uri.c_str());
communicator.logger.notice("BUSY - reject incoming call from %s.", uri.c_str());
param.statusCode = PJSIP_SC_OK;
available = false;
//param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
}
call->answer(param);
@ -450,6 +468,7 @@ sip::PjsuaCommunicator::PjsuaCommunicator(IncomingConnectionValidator &validator
uriValidator(validator) {
logWriter.reset(new sip::_LogWriter(pjsuaLogger));
max_calls = maxCalls;
endpoint.libCreate();
@ -551,7 +570,7 @@ void sip::PjsuaCommunicator::registerAccount(string host, string user, string pa
accountConfig.sipConfig.authCreds.push_back(cred);
logger.info("Registering account for URI: %s.", uri.c_str());
account.reset(new _Account(*this));
account.reset(new _Account(*this, max_calls));
account->create(accountConfig);
}

View File

@ -80,7 +80,8 @@ namespace sip {
std::function<void()> onConnect;
std::function<void()> onDisconnect;
std::function<void()> onCallerAuth;
std::function<void()> joinAuthChannel;
std::function<void()> joinAuthChannel; // DEPRECATE ?
std::function<void(std::string channelNameRegex)> joinOtherChannel;
std::function<void()> joinDefaultChannel;
};
@ -114,6 +115,7 @@ namespace sip {
std::string file_mute_on;
std::string file_mute_off;
std::string file_menu;
int max_calls;
// TODO: move these to private?
std::string got_dtmf;
@ -126,6 +128,8 @@ namespace sip {
call calls[MY_MAX_CALLS];
std::unordered_map<std::string, std::string> pins;
private:
log4cpp::Category &logger;
log4cpp::Category &pjsuaLogger;

View File

@ -60,6 +60,11 @@ int main(int argc, char *argv[]) {
sip::PjsuaCommunicator pjsuaCommunicator(connectionValidator, conf.getInt("sip.frameLength"), max_calls);
try {
pjsuaCommunicator.pins = conf.getChildren("pins");
} catch (...) {
}
mumble::MumbleCommunicatorConfig mumbleConf;
mumbleConf.host = conf.getString("mumble.host");
mumbleConf.port = conf.getInt("mumble.port");
@ -79,19 +84,6 @@ int main(int argc, char *argv[]) {
mumbleConf.comment = "";
}
try {
mumbleConf.authchan = conf.getString("mumble.channelAuthExpression");
} catch (...) {
mumbleConf.authchan = "";
}
/* default to <no pin> */
try {
pjsuaCommunicator.caller_pin = conf.getString("app.caller_pin");
} catch (...) {
pjsuaCommunicator.caller_pin = "";
}
try { pjsuaCommunicator.file_welcome = conf.getString("files.welcome");
} catch (...) {
pjsuaCommunicator.file_welcome = "welcome.wav";
@ -137,23 +129,10 @@ int main(int argc, char *argv[]) {
pjsuaCommunicator.file_menu = "menu.wav";
}
/* If the channelUnauthExpression is set, use this as the default
* channel and use channelNameExpression for the authchan. Otherwise,
* use the channelNameExpression for the default.
*/
std::string defaultChan = conf.getString("mumble.channelNameExpression");
std::string authChan = "";
if ( pjsuaCommunicator.caller_pin.size() > 0 ) {
try {
authChan = conf.getString("mumble.channelAuthExpression");
} catch (...) {
// defaultChan = conf.getString("mumble.channelNameExpression");
}
}
mumble::MumbleChannelJoiner mumbleChannelJoiner(defaultChan);
mumble::MumbleChannelJoiner mumbleAuthChannelJoiner(authChan);
mumble::MumbleChannelJoiner mumbleOtherChannelJoiner(defaultChan);
for (int i = 0; i<max_calls; i++) {
@ -223,11 +202,12 @@ int main(int argc, char *argv[]) {
&mumbleChannelJoiner,
mumcom);
// PJ notifies Mumble that Caller Auth is done
pjsuaCommunicator.calls[i].joinAuthChannel = std::bind(
&mumble::MumbleChannelJoiner::findJoinChannel,
&mumbleAuthChannelJoiner,
mumcom);
// PJ notifies Mumble to join other channel
pjsuaCommunicator.calls[i].joinOtherChannel = std::bind(
&mumble::MumbleChannelJoiner::joinOtherChannel,
&mumbleOtherChannelJoiner,
mumcom,
_1);
// Passing audio from Mumble to SIP
mumcom->onIncomingPcmSamples = std::bind(

View File

@ -1,3 +1,3 @@
Press star one for status.
Press star five to mute.
Press star six to un-mute.
Press star nine to change channel.

Binary file not shown.