subscriberRegistry/srmanager.cpp

308 lines
9.3 KiB
C++
Executable File

/*
* Copyright 2011 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
#include <string>
#include <sqlite3.h>
#include <time.h>
#include "Configuration.h"
#include "Logger.h"
#include <string.h>
#include "servershare.h"
#include "SubscriberRegistry.h"
#include <algorithm>
using namespace std;
ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db", "srmanager", getConfigurationKeys());
Log dummy("srmanager",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);
map<string,string> gArgs;
string gDatabase;
string gVisibleSipColumns;
string gUrl;
string gTitle;
string gVisibleExtColumns = "exten dial";
// just using this for the database access
SubscriberRegistry gSubscriberRegistry;
#define NO_BUTTON 0
#define UPDATE_BUTTON 1
#define ADD_BUTTON 2
#define DELETE_BUTTON 4
// may need some way to add/update a NULL field
void tableRow(vector<string> &names, vector<string> &values, int buttons, string id)
{
cout << "<form name=\"input\" action=\"" << gUrl << "\" method=\"post\">\n";
for (size_t i = 0; i < names.size(); i++) {
string name = names[i];
string value = values.size() == 0 ? "" : values[i];
cout << "<input type=\"text\" name=\"" << name << "\" value=\"" << value << "\" />\n";
}
cout << "<input type=\"hidden\" name=\"id\" value=\"" << id << "\" />\n";
if (buttons & UPDATE_BUTTON) {
cout << "<input type=\"submit\" name=\"what\" value=\"Update\" />\n";
}
if (buttons & ADD_BUTTON) {
cout << "<input type=\"submit\" name=\"what\" value=\"Add\" />\n";
}
if (buttons & DELETE_BUTTON) {
cout << "<input type=\"submit\" name=\"what\" value=\"Delete\" />\n";
}
cout << "</form>\n";
}
// make the header a fake form to get the same widths
void initTable(vector<string> &cols)
{
tableRow(cols, cols, NO_BUTTON, "0");
}
void table(const char *tableName, vector<string> &cols, bool addButtonP, const char *note)
{
cout << "<h4>" << gDatabase << "." << tableName << " " << note << "</h4>\n";
initTable(cols);
ostringstream os;
os << "select id," << join(",", cols) << " from " << tableName;
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(gSubscriberRegistry.db(), &stmt,os.str().c_str())) {
LOG(ERR) << "sqlite3_prepare_statement problem - statement: " << os.str();
LOG(ERR) << " " << sqlite3_errmsg(gSubscriberRegistry.db());
return;
}
int src = sqlite3_run_query(gSubscriberRegistry.db(), stmt);
while (src == SQLITE_ROW) {
vector<string> values;
const char *id = (const char*)sqlite3_column_text(stmt, 0);
for (int i = 1; i <= (int)cols.size(); i++) {
const char *value = (const char*)sqlite3_column_text(stmt, i);
values.push_back(value ? value : "(null)");
}
tableRow(cols, values, UPDATE_BUTTON | DELETE_BUTTON, id);
src = sqlite3_run_query(gSubscriberRegistry.db(), stmt);
}
sqlite3_finalize(stmt);
if (addButtonP) {
vector<string> dummy;
tableRow(cols, dummy, ADD_BUTTON, "0");
}
}
void getFields(vector<string> *fields, vector<bool> *isSet)
{
vector<string> vsc;
split(' ', gVisibleSipColumns, &vsc);
sqlite3_stmt *stmt;
const char *cmd = "pragma table_info(sip_buddies)";
if (sqlite3_prepare_statement(gSubscriberRegistry.db(), &stmt, cmd)) {
LOG(ERR) << "sqlite3_prepare_statement problem - statement: " << cmd;
LOG(ERR) << " " << sqlite3_errmsg(gSubscriberRegistry.db());
return;
}
int src = sqlite3_run_query(gSubscriberRegistry.db(), stmt);
while (src == SQLITE_ROW) {
string field = (char*)sqlite3_column_text(stmt, 1);
fields->push_back(field);
isSet->push_back(find(vsc.begin(), vsc.end(), field) != vsc.end());
src = sqlite3_run_query(gSubscriberRegistry.db(), stmt);
}
sqlite3_finalize(stmt);
}
void mainTables()
{
cout << "<form name=\"provision\" action=\"" << gUrl << "\" method=\"post\">\n";
cout << "Phone Number = ";
cout << "<input type=\"text\" name=\"phonenumber\" value=\"\" />\n";
cout << "IMSI = ";
cout << "<input type=\"text\" name=\"imsi\" value=\"\" />\n";
cout << "<input type=\"submit\" name=\"what\" value=\"Provision\" />\n";
cout << "</form>\n";
cout << "<br><hr><br>\n";
vector<string> vsc;
split(' ', gVisibleSipColumns, &vsc);
table("sip_buddies", vsc, false, "(scroll down to change which fields of sip_buddies are visible)");
cout << "<hr>";
vector<string> vec;
split(' ', gVisibleExtColumns, &vec);
table("dialdata_table", vec, true, "");
cout << "<br><hr><br>\n";
cout << "<FORM METHOD=\"LINK\" ACTION=\"" << gUrl << "\"> <INPUT TYPE=\"submit\" VALUE=\"Refresh\"> </FORM>\n";
cout << "<br><hr><br>\n";
cout << "<h4>Selected fields are included in sip_buddies table (submit button at bottom)</h4>\n";
cout << "<form method=\"post\" action=\"" << gUrl << "\">\n";
vector<string> fields;
vector<bool> isSet;
getFields(&fields, &isSet);
for (int i = 0; i < (int)fields.size(); i++) {
string field = fields[i];
string checked = isSet[i] ? "checked" : "";
cout << "<input type=\"checkbox\" name=\"" << field << "\" value=\"" << field << "\"" << checked << " /> " << field << "<br />\n";
}
cout << "<br><INPUT TYPE=SUBMIT name=\"what\" VALUE=\"Submit\">\n";
cout << "</form>\n";
}
string nullCheck(string s)
{
if (s == "(null)") {
return "NULL";
} else {
return "\"" + s + "\"";
}
}
void doCmd(string cmd)
{
string table;
vector<string> cols;
if (gArgs.find("dial") == gArgs.end()) {
table = "sip_buddies";
split(' ', gVisibleSipColumns, &cols);
} else {
table = "dialdata_table";
split(' ', gVisibleExtColumns, &cols);
}
string id = gArgs["id"];
ostringstream os;
if (cmd == "add") {
string names = join(",", cols);
vector<string> values0;
vector<string>::iterator it;
for (it = cols.begin(); it != cols.end(); it++) {
values0.push_back(nullCheck(gArgs[*it]));
}
string values = join(",", values0);
os << "insert into " << table << " (" << names << ") values (" << values << ")";
} else if (cmd == "delete") {
os << "delete from " << table << " where id = " << id;
} else if (cmd == "update") {
vector<string> sets0;
vector<string>::iterator it;
for (it = cols.begin(); it != cols.end(); it++) {
sets0.push_back(*it + "=" + nullCheck(gArgs[*it]));
}
string sets = join(",", sets0);
os << "update " << table << " set " << sets << " where id = " << id;
} else {
LOG(ERR) << "internal error";
}
LOG(INFO) << os.str();
if (!sqlite3_command(gSubscriberRegistry.db(), os.str().c_str())) {
LOG(ERR) << "sqlite3_command problem - statement: " << os.str();
return;
}
mainTables();
}
void initHtml()
{
cout << "Content-Type: text/html\n\n";
cout << "<HTML>\n";
cout << "<HEAD>\n";
cout << "<TITLE>" << gTitle << "</TITLE>\n";
cout << "</HEAD>\n";
cout << "<BODY>\n";
cout << "<h4>" << gTitle << "</h4>\n";
time_t rawtime;
time ( &rawtime );
struct tm * timeinfo;
timeinfo = localtime ( &rawtime );
cout << "<h4>" << asctime(timeinfo) << "</h4>\n";
}
void endHtml()
{
cout << "</BODY>\n";
cout << "</HTML>\n";
}
void doVisibles()
{
gVisibleSipColumns = "";
map<string,string>::iterator it;
bool first = true;
for (it = gArgs.begin(); it != gArgs.end(); it++) {
if (it->first == "what") continue;
if (first) {
first = false;
} else {
gVisibleSipColumns += " ";
}
gVisibleSipColumns += it->first;
}
if (!gConfig.set("SubscriberRegistry.Manager.VisibleColumns", gVisibleSipColumns)) {
LOG(ERR) << "unable to update SubscriberRegistry.Manager.VisibleColumns";
}
}
int main(int argc, char **argv)
{
gSubscriberRegistry.init();
// start the html return
initHtml();
// read the config file
gVisibleSipColumns = gConfig.getStr("SubscriberRegistry.Manager.VisibleColumns");
gUrl = "/cgi/srmanager.cgi";
gTitle = gConfig.getStr("SubscriberRegistry.Manager.Title");
// connect to the database
gDatabase = gConfig.getStr("SubscriberRegistry.db");
// decode the http query
decodeQuery(gArgs);
// execute command
string what = gArgs["what"];
if (!what.length() || what == "Main") {
mainTables();
} else if (what == "Add") {
doCmd("add");
} else if (what == "Update") {
doCmd("update");
} else if (what == "Delete") {
doCmd("delete");
} else if (what == "Provision") {
gSubscriberRegistry.addUser(gArgs["imsi"].c_str(), gArgs["phonenumber"].c_str());
mainTables();
} else if (what == "Submit") {
doVisibles();
mainTables();
} else {
cout << "unrecognized what parameter<br>\n";
map<string,string>::iterator it;
for (it = gArgs.begin(); it != gArgs.end(); it++) {
cout << it->first << " -> " << it->second << "<br>\n";
}
}
// finish the html return
endHtml();
}