/*
This file is part of Bolixo.
Bolixo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bolixo 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bolixo. If not, see .
*/
/*
Manage web session ID
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INSTRUMENT_DONOTOPEN
#include "instrument.h"
static DEBUG_KEY D_PROTO ("proto","Protocol information");
enum CONNECT_TYPE { TYPE_NONE, TYPE_CONTROL, TYPE_CLIENT, TYPE_ADMIN };
struct HANDLE_INFO: public ARRAY_OBJ{
CONNECT_TYPE type = TYPE_NONE;
int no = -1;
std::string host;
REQUEST_INFO req;
int wait_userid = -1;
};
#include "proto/bo-sessiond_control.protoh"
#define bo_sessiond_client_rep_waitevent_NEEDED
#include "proto/bo-sessiond_client.protoh"
#include "proto/bo-sessiond_admin.protoh"
#define session_log_session_NOTNEED
#define session_log_sessionv1_NOTNEED
#define session_log_notify_NOTNEED
#define session_log_notify_v1_NOTNEED
#define session_log_notify_v2_NOTNEED
#define session_log_notify_v3_NOTNEED
#include "proto/session_log.protoch"
#include "proto/session_log.protoh"
using namespace std;
struct VARIABLE{
string name;
string val;
VARIABLE (PARAM_STRING _name, PARAM_STRING _val){
name = _name.ptr;
val = _val.ptr;
}
};
// Information associated with a session
struct SESSION_INFO{
unsigned userid;
string userid_str;
string name;
string email;
string lang;
unsigned char dateformat;
string timezone;
bool admin;
vector vars;
struct {
time_t lastvisit = time(nullptr);
time_t lastping = (time_t)0;
unsigned nbacc = 0;
} stats;
SESSION_INFO(){
userid = (unsigned)-1;
admin = false;
dateformat = 0;
}
SESSION_INFO (unsigned _userid,
const string &_userid_str,
const char *_name,
const char *_email,
const char *_lang,
bool _admin,
unsigned _dateformat,
const char *_timezone){
userid = _userid;
userid_str = _userid_str;
name = _name;
email = _email;
lang = _lang;
admin = _admin;
dateformat = _dateformat;
timezone = _timezone;
stats.nbacc=1;
}
};
static const char *VAR_NOTIFIES = "notifies";
// Information associated with a user
// Notification are globals to all sessions of a user.
// Some variables are globals as well.
struct USER_INFO{
unsigned sequence = 0;
vector notes;
vector vars;
};
static unsigned max_key_notes=1; // Number of notifications kept with the same key
static void bo_sessiond_setnotify(
map &userinfos,
map> &waiting,
const vector &userids,
const char *name,
const char *script)
{
time_t now = time(NULL);
for (auto userid:userids){
auto &v = userinfos[userid];
unsigned sequence = ++v.sequence;
// Notifications contains script. We can't just override a notification with
// a new one. The previous script would be lost. A user would miss one script
// and the document/game would be broken
// Notifications like these are never deleted because the end user may
// have several UIs running.
// So we keep around the last max_key_notes.
// Further, in waitevent, if there are several consecutive event for the same
// key, we return a concatenation of the scripts.
unsigned found = 1; // We count the one we will add next
for (auto &n:v.notes){
if (n.key == name){
found++;
}
}
{
NOTIFY n;
n.key = name;
n.script = script;
n.when = now;
n.sequence = sequence;
v.notes.push_back(n);
}
for (auto it=v.notes.begin(); found > max_key_notes && it != v.notes.end(); ){
auto next_it = it+1;
if (it->key == name){
next_it = v.notes.erase(it);
found--;
}
it = next_it;
}
auto w = waiting.find(userid);
if (w != waiting.end()){
for (auto fd:w->second){
bo_sessiond_client_rep_waitevent (fd,true,"",name,script,sequence);
}
waiting.erase(w);
}
}
}
static void bo_sessiond_dumpvars(const char *prefix, const vector &vars, vector &tb)
{
for (auto &v:vars){
string tmp = string_f("\t%s %s:[",prefix,v.name.c_str());
bool geometry = v.name == "geometry";
for (auto &vv:v.vals){
if (geometry && vv.sname == "id") tmp += "\n\t";
tmp += string_f (" %s=%s",vv.sname.c_str(),vv.sval.c_str());
}
tmp += "]";
tb.push_back(move(tmp));
}
}
int main (int argc, char *argv[])
{
glocal int ret = -1;
glocal int noproc = 1;
glocal const char *client_secretfile = "/etc/bolixo/secrets.client";
glocal const char *admin_secretfile = "/etc/bolixo/secrets.admin";
glocal const char *bind = "0.0.0.0";
glocal const char *port = "9200";
glocal const char *control = "/var/run/bo-sessiond.sock";
glocal const char *user = "bolixo";
glocal bool daemon = false;
glocal const char *pidfile = "/var/run/bo-sessiond.pid";
glocal vector variables;
glocal vector user_variables;
glocal unsigned maxhandles = 10000;
glocal.ret = (argc,argv,"tlmpsql");
setproginfo ("bo-sessiond",VERSION,"Manage web sessions");
setgrouparg ("Networking");
setarg ('b',"bindaddr","Bind to this address (TCP)",glocal.bind,false);
setarg ('p',"tcpport","Listen for command on this TCP port",glocal.port,false);
setarg ('c',"control","Unix socket for bo-sessiond",glocal.control,false);
setarg (' ',"variable","Supported web session variables",glocal.variables,false);
setarg (' ',"user_variable","Supported web user variables",glocal.user_variables,false);
setgrouparg ("Misc.");
setarg (' ',"admin-secrets","File holding admin secrets for communication",glocal.admin_secretfile,false);
setarg (' ',"client-secrets","File holding client secrets for communication",glocal.client_secretfile,false);
setarg (' ',"user","Run the program as this user",glocal.user,false);
setarg (' ',"daemon","Run in background",glocal.daemon,false);
setarg (' ',"pidfile","File holding the PID of the process",glocal.pidfile,false);
setarg (' ',"maxhandles","Maximum number of file handle supported",glocal.maxhandles,false);
setarg (' ',"max_eq_notes","Maximum number of notifications kept with the same key",max_key_notes,false);
glocal const char *msg = msg;
("/tmp/err.log",true);
fprintf (fout,"%s\n",glocal.msg);
return 0;
if (glocal.daemon){
syslog (LOG_ERR,"%s",msg);
}else{
fprintf (stderr,"%s",msg);
}
if (glocal.daemon){
syslog (LOG_WARNING,"%s",msg);
}else{
fprintf (stderr,"%s",msg);
}
glocal set vars; // Acceptable variable names
glocal set user_vars; // glocal variable names
glocal map sessions;
glocal map userinfos;
glocal map> waiting; // Connections waiting for events
glocal map admin_secrets;
glocal map client_secrets;
glocal unsigned long nbrequest_admin = 0;
glocal unsigned long nbrequest_client = 0;
glocal unsigned long nbsessions_created = 0;
glocal CONNECT_INFO con;
glocal string controlport = string_f("unix:%s",glocal.control);
string clientport = string_f ("unix:/tmp/sessiond-client-%s.sock",glocal.port);
string adminport = string_f ("unix:/tmp/sessiond-admin-%s.sock",glocal.port);
fdpass_readsecrets (glocal.admin_secretfile,glocal.admin_secrets);
fdpass_readsecrets (glocal.client_secretfile,glocal.client_secrets);
int ret = -1;
for (auto s:glocal.variables) glocal.vars.insert(s);
for (auto s:glocal.user_variables){
glocal.vars.insert(s);
glocal.user_vars.insert(s);
}
{
FILE *fin = fopen ("/tmp/sessions.log","r");
if (fin != NULL){
glocal function &vars)> freadvars;
glocal.freadvars = [&](unsigned userid, SESSION_INFO &sess, const vector &vars){
for (auto &v:vars){
if (glocal.user_vars.count(v.name)!=0){
// Move per session variables to per user variables
auto &uvars = glocal.userinfos[userid].vars;
bool found = false;
for (auto &uv:uvars){
if (uv.name == v.name){
found = true;
break;
}
}
if (!found){
uvars.push_back(v);
}
}else{
sess.vars.push_back(v);
}
}
};
(fin);
SESSION_INFO sess(userid, userid_str, name, email, lang, admin, dateformat,"");
sess.stats.lastvisit = lastvisit;
sess.stats.nbacc = nbacc;
for (auto &v:vars) sess.vars.push_back(v);
glocal.sessions[session] = move(sess);
SESSION_INFO sess(userid, userid_str, name, email, lang, admin, dateformat,timezone);
sess.stats.lastvisit = lastvisit;
sess.stats.nbacc = nbacc;
for (auto &v:vars){
if (glocal.user_vars.count(v.name)!=0){
// Move per session variables to per user variables
auto &uvars = glocal.userinfos[userid].vars;
bool found = false;
for (auto &uv:uvars){
if (uv.name == v.name){
found = true;
break;
}
}
if (!found){
uvars.push_back(v);
}
}else{
sess.vars.push_back(v);
}
}
glocal.sessions[session] = move(sess);
SESSION_INFO sess(userid, userid_str, name, email, lang, admin, dateformat,timezone);
sess.stats.lastvisit = lastvisit;
sess.stats.lastping = lastping;
sess.stats.nbacc = nbacc;
glocal.freadvars(userid,sess,vars);
glocal.sessions[session] = move(sess);
auto &v = glocal.userinfos[userid];
// Old format, when must assign a sequence number
for (auto &n:notifies){
NOTIFY nn;
nn.key = n.key;
nn.when = n.when;
nn.sequence = ++v.sequence;
v.notes.push_back(nn);
}
auto &v = glocal.userinfos[userid];
v.sequence = 0;
for (auto &n:notifies){
if (v.sequence < n.sequence) v.sequence = n.sequence;
v.notes.push_back(n);
}
auto &v = glocal.userinfos[userid];
v.sequence = sequence;
for (auto &n:notifies){
NOTIFY note;
note.key = n.key;
note.when = n.when;
note.sequence = n.sequence;
v.notes.push_back(note);
}
auto &v = glocal.userinfos[userid];
v.sequence = sequence;
for (auto &n:notifies) v.notes.push_back(n);
auto &user = glocal.userinfos[userid];
user.sequence = sequence;
for (auto &n:notifies) user.notes.push_back(n);
// A bug created dups in user variables. We keep the first here
for (auto &var:vars){
bool found = false;
for (auto &uv:user.vars){
if (uv.name == var.name){
found = true;
break;
}
}
if (!found){
user.vars.push_back(var);
}
}
tlmp_error ("Invalid entry, reading sessions.log\n");
fclose (fin);
}
}
(glocal.bind,clientport,5);
HANDLE_INFO *n = new HANDLE_INFO;
info.data = n;
if (string_cmp(info.port,glocal.controlport)==0){
n->type = TYPE_CONTROL;
}else{
settcpnodelay(true);
char addr[20];
const char *fromstr = addr;
if (strncmp(info.port,"unix:",5)==0){
fromstr = info.port;
}else{
ipnum_ip2a (from,addr);
}
n->host = fromstr;
n->req.secret = fdpass_findsecret (glocal.client_secrets,fromstr);
if (n->req.secret.size() > 0){
n->type = TYPE_CLIENT;
}else{
n->req.secret = fdpass_findsecret (glocal.admin_secrets,fromstr);
if (n->req.secret.size() > 0){
n->type = TYPE_ADMIN;
}else{
tlmp_error ("Rejected connexion from IP %s\n",fromstr);
endclient = true;
}
}
}
HANDLE_INFO *n = (HANDLE_INFO*)info.data;
if (n->wait_userid != -1){
auto &w = glocal.waiting[n->wait_userid];
for (auto it=w.begin(); it != w.end(); it++){
if (*it == no){
w.erase(it);
break;
}
}
}
debug_printf (D_PROTO,"receive line: %s\n",line);
HANDLE_INFO *c = (HANDLE_INFO*)info.data;
static const char *tbtype[]={"none","control request","client request","admin request"};
ERROR_PREFIX prefix ("%s: host %s secret %s:",tbtype[c->type],c->host.c_str(),c->req.secret.c_str());
if (c->type == TYPE_CONTROL){
(this,c->req,line, info.linelen,endserver, endclient, no,c,c->host.c_str());
vector tb;
tb.push_back(string_f ("Version %s",VERSION));
tb.push_back(string_f ("nbsessions=%zu",glocal.sessions.size()));
unsigned long nbanon = 0;
unsigned long nbadmin = 0;
for (auto &x:glocal.sessions){
if (x.second.userid ==(unsigned)-1) nbanon++;
if (x.second.admin) nbadmin++;
}
tb.push_back(string_f ("nbanon=%lu",nbanon));
tb.push_back(string_f ("nbadmin=%lu",nbadmin));
tb.push_back(string_f ("nbuserinfos=%zu",glocal.userinfos.size()));
tb.push_back(string_f ("nbsesssions_created=%lu",glocal.nbsessions_created));
tb.push_back(string_f ("nbrequest_admin=%lu",glocal.nbrequest_admin));
tb.push_back(string_f ("nbrequest_client=%lu",glocal.nbrequest_client));
unsigned long nbwaiting=0;
for (auto &ww:glocal.waiting){
nbwaiting += ww.second.size();
}
tb.push_back(string_f("nbwaiting=%lu",nbwaiting));
tb.push_back(string_f ("max_eq_notes=%u",max_key_notes));
instrument_status (tb);
rep_status(tb);
toggle_instrument_file(on);
("/tmp/sessions.log",false);
for (auto const &s:glocal.sessions){
session_log_sessionv2(fout,s.first,s.second.userid,s.second.userid_str
,s.second.name,s.second.email,s.second.lang,s.second.timezone,s.second.admin
,s.second.dateformat
,s.second.stats.lastvisit,s.second.stats.lastping,s.second.stats.nbacc,s.second.vars);
}
for (auto const &s:glocal.userinfos){
session_log_notify_v4(fout,s.first,s.second.sequence,s.second.notes,s.second.vars);
}
return 0;
endserver = true;
unsigned pos = 0;
unsigned end = offset+nb-1;
vector tb;
tb.push_back(string_f("listsessions %u -> %u",offset,end));
for (auto &it:glocal.sessions){
if (pos >end){
break;
}else if (pos >= offset){
DATEASC datevisit,dateping;
fdpass_asctime (it.second.stats.lastvisit,datevisit);
fdpass_asctime (it.second.stats.lastping,dateping);
string tmp;
if (strncasecmp(it.second.userid_str.c_str(),"http://",7)==0
|| strncasecmp(it.second.userid_str.c_str(),"https://",8)==0){
const char *status = "unknown";
if (it.second.userid == (unsigned)-1){
status = "logged";
}else if (it.second.userid == (unsigned)-2){
status = "login";
}
tmp = string_f ("%07u: %s %s-%s %s %s %s %u %u %d %s",pos,it.first.c_str()
,status,it.second.userid_str.c_str(),it.second.name.c_str(),it.second.email.c_str()
,datevisit.buf,it.second.stats.nbacc
,it.second.userid,it.second.admin,it.second.lang.c_str());
}else if (it.second.userid==(unsigned)-1){
tmp = string_f ("%07u: %s anonymous %s %u",pos,it.first.c_str()
,datevisit.buf,it.second.stats.nbacc);
}else{
tmp = string_f ("%07u: %s %d-%s %s %s %s %s %u %u %d %s %u %s",pos,it.first.c_str()
,it.second.userid,it.second.userid_str.c_str(),it.second.name.c_str(),it.second.email.c_str()
,datevisit.buf,dateping.buf,it.second.stats.nbacc
,it.second.userid,it.second.admin,it.second.lang.c_str()
,it.second.dateformat,it.second.timezone.c_str());
}
tb.push_back(move(tmp));
bo_sessiond_dumpvars("S",it.second.vars,tb);
auto note = glocal.userinfos.find(it.second.userid);
if (note != glocal.userinfos.end()){
tmp = string_f("\t%s:",VAR_NOTIFIES);
tmp += string_f(" %u",note->second.sequence);
for (auto &n:note->second.notes){
tmp += string_f(" %s,%u,%u",n.key.c_str(),n.when,n.sequence);
}
tb.push_back(move(tmp));
bo_sessiond_dumpvars("U",note->second.vars,tb);
}
}
pos++;
}
rep_listsessions(tb);
glocal.userinfos.clear();
time_t t = time(NULL);
for (unsigned i=0; i
unsigned deletedanon = 0;
unsigned deleteduser = 0;
unsigned deletedadmin = 0;
time_t oldtime = time(NULL)-nbseconds;
for (auto it=glocal.sessions.begin(); it!= glocal.sessions.end(); ){
auto next = it;
next++;
if (it->second.stats.lastvisit < oldtime
&& it->second.stats.lastping < oldtime){
if (it->second.userid == (unsigned)-1){
if (anonymous){
next = glocal.sessions.erase(it);
deletedanon++;
}
}else if (it->second.admin){
if (adminuser){
next = glocal.sessions.erase(it);
deletedadmin++;
}
}else{
if (normaluser){
next = glocal.sessions.erase(it);
deleteduser++;
}
}
}
it = next;
}
rep_eraseold(deletedanon,deleteduser,deletedadmin);
time_t old = time(nullptr)-nbseconds;
unsigned deleted = 0;
for (auto &p:glocal.userinfos){
auto &v = p.second.notes;
for (auto it=v.begin(); it != v.end(); ){
auto next_it = it+1;
if ((time_t)it->when < old){
deleted++;
next_it = v.erase(it);
}
it = next_it;
}
}
rep_eraseoldnotes(deleted);
for (auto &w:glocal.waiting){
for (auto &c:w.second){
glocal.TCPSERVER.closeclient(c);
}
}
glocal.waiting.clear();
if (on){
debug_seton();
}else{
debug_setoff();
}
debug_setfdebug (filename);
max_key_notes = max_notes;
tlmp_error ("Control: Invalid command: %s\n",line);
endclient = true;
}else if (c->type == TYPE_CLIENT){
glocal.nbrequest_client++;
(this,c->req,line, info.linelen,endserver, endclient, no,c,c->host.c_str());
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
it->second.stats.lastping = time(nullptr);
it->second.stats.nbacc++;
rep_getsessioninfo(true,it->second.name,it->second.lang,it->second.dateformat
,it->second.admin,it->second.userid,it->second.timezone);
}else{
rep_getsessioninfo(false,"","",0,false,0,"");
}
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
it->second.stats.lastvisit = time(NULL);
it->second.stats.nbacc++;
vector vars = it->second.vars;
auto note = glocal.userinfos.find(it->second.userid);
if (note != glocal.userinfos.end()){
VAR var;
var.name = VAR_NOTIFIES;
// We send the sequence number as a variable
{
SNAMEVAL val;
val.sname = "notify_sequence";
val.sval = string_f("%u",note->second.sequence);
var.vals.push_back(val);
}
for (auto &n:note->second.notes){
SNAMEVAL val;
val.sname = n.key;
var.vals.push_back(val);
}
vars.push_back(var);
for (auto &v:note->second.vars){
vars.push_back(v);
}
}
rep_getsessioninfovars(true,it->second.name,it->second.lang,it->second.dateformat,it->second.admin,it->second.userid,vars);
}else{
vector vars;
rep_getsessioninfovars(false,"","",0,false,0,vars);
}
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
{
time_t now = time(nullptr);
if (activity){
it->second.stats.lastvisit = now;
it->second.stats.nbacc++;
}else{
// bo-websocket is calling this (wih activity == false) whenever it starts a new
// session but this is not really a user activity
it->second.stats.lastping = now;
}
}
vector vars = it->second.vars;
auto note = glocal.userinfos.find(it->second.userid);
if (note != glocal.userinfos.end()){
VAR var;
var.name = VAR_NOTIFIES;
// We send the sequence number as a variable
{
SNAMEVAL val;
val.sname = "notify_sequence";
val.sval = string_f("%u",note->second.sequence);
var.vals.push_back(val);
}
for (auto &n:note->second.notes){
SNAMEVAL val;
val.sname = n.key;
var.vals.push_back(val);
}
vars.push_back(var);
for (auto &v:note->second.vars){
vars.push_back(v);
}
}
rep_getsessioninfovars_v2(true,it->second.name,it->second.lang,it->second.dateformat,it->second.admin,it->second.userid,vars);
}else{
vector vars;
rep_getsessioninfovars_v2(false,"","",0,false,0,vars);
}
string msg;
bool success = false;
if (glocal.vars.count(var.name)==0){
msg = "unknown variable";
}else{
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
auto *vars = &it->second.vars;
if (glocal.user_vars.count(var.name)!=0){
vars = &glocal.userinfos[it->second.userid].vars;
}
bool found = false;
for (auto &v:*vars){
if (v.name == var.name){
v.vals.clear();
for (auto &vv:var.vals){
SNAMEVAL vals;
vals.sname = vv.sname;
vals.sval = vv.sval;
v.vals.push_back(vals);
}
found = true;
success = true;
msg = "Variable updated";
break;
}
}
if (!found){
vars->push_back(var);
msg = "Variable added";
success = true;
}
}else{
msg = "invalid session";
}
}
rep_setvar (success,msg);
bool success = false;
string msg;
auto it = glocal.sessions.find(sessionid);
if (it == glocal.sessions.end()){
msg = "Invalid sessionid";
}else{
auto note = glocal.userinfos.find(it->second.userid);
if (note != glocal.userinfos.end()){
for (auto vit=note->second.notes.begin(); vit != note->second.notes.end(); ){
auto next_vit = vit+1;
if (vit->key == name){
next_vit = note->second.notes.erase(vit);
}
vit = next_vit;
}
// We must keep the entry around to keep the sequence number.
//if (note->second.notes.size()==0) glocal.userinfos.erase(note);
}
success = true;
}
rep_delnotify(success,msg);
// sessionid sequence = success:b msg content sequence
auto it = glocal.sessions.find(sessionid);
if (it == glocal.sessions.end()){
rep_waitevent (false,"Invalid sessionid","","",0);
}else if (it->second.userid == (unsigned)-1){
rep_waitevent (false,"Anonymous session","","",0);
}else{
// We do not respond immediatly, only if there is an event
auto n = glocal.userinfos.find(it->second.userid);
unsigned next_sequence = (unsigned)-1;
string name;
string script;
if (n != glocal.userinfos.end()){
// We have to find the next event with the closest smallest
// sequence number, yet larger than the received sequence parameter.
for (auto &nn:n->second.notes){
if (nn.sequence > sequence
&& nn.sequence < next_sequence){
next_sequence = nn.sequence;
name = nn.key;
script = nn.script;
}else if (nn.sequence == next_sequence+1
&& nn.key == name){
script += nn.script;
next_sequence = nn.sequence;
//tlmp_warning ("merge name=%s next_sequence=%u sequence=%u",name.c_str(),next_sequence,nn.sequence);
}
}
}
if (next_sequence != (unsigned)-1){
rep_waitevent (true,"",name,script,next_sequence);
}else{
// We record the request and set_notify will reply
c->wait_userid = it->second.userid;
auto &w = glocal.waiting[it->second.userid];
bool found = false;
for (auto u:w){
if (u==no){
found = true;
break;
}
}
if (!found) w.push_back(no);
}
}
bo_sessiond_setnotify(glocal.userinfos,glocal.waiting,userids,name,script);
rep_test (true);
bool ret = false;
auto it = glocal.sessions.find(sessionid);
if (it == glocal.sessions.end()){
tlmp_error ("ping invalid session %s",sessionid);
}else{
ret = true;
time_t now = time(nullptr);
if (activity){
it->second.stats.lastvisit = now;
it->second.stats.nbacc++;
}else{
it->second.stats.lastping = now;
}
}
rep_ping (ret);
tlmp_error ("Client: Invalid command: %s\n",line);
endclient = true;
}else if (c->type == TYPE_ADMIN){
glocal.nbrequest_admin++;
(this,c->req,line, info.linelen,endserver, endclient, no,c,c->host.c_str());
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
it->second.stats.lastping = time(nullptr);
it->second.stats.nbacc++;
rep_getsessioninfo(true,it->second.name.c_str(),it->second.email.c_str(),it->second.lang,it->second.admin,it->second.userid);
}else{
rep_getsessioninfo(false,"","",0,false,0);
}
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
rep_getsession(true,it->second.userid,it->second.userid_str.c_str(),it->second.admin,it->second.lang);
}else{
rep_getsession(false,0,"",false,"");
}
auto it = glocal.sessions.find(sessionid);
if (it == glocal.sessions.end()){
tlmp_error ("setsession: %s does not exist\n",sessionid);
}else{
it->second = SESSION_INFO(userid,userid_str,name,email,lang,admin,dateformat,timezone);
}
auto it = glocal.sessions.find(sessionid);
if (it == glocal.sessions.end()){
tlmp_error ("setsession: %s does not exist\n",sessionid);
}else{
it->second.lang = lang;
it->second.dateformat = dateformat;
// Update all sessions for this user
for (auto &s:glocal.sessions){
if (s.second.userid==it->second.userid){
s.second.lang = lang;
s.second.dateformat = dateformat;
s.second.timezone = timezone;
}
}
}
// Assigned a notification to a list of userids
bo_sessiond_setnotify(glocal.userinfos,glocal.waiting,userids,name,script);
auto it = glocal.sessions.find(sessionid);
if (it != glocal.sessions.end()){
glocal.sessions.erase(it);
}else{
tlmp_error ("deletesession: unknown sessionid %s\n",sessionid);
}
vector sessionids;
for (auto &it:glocal.sessions){
if (it.second.userid==userid) sessionids.push_back(it.first);
}
for (auto &it:sessionids){
auto s = glocal.sessions.find(it);
if (s != glocal.sessions.end()){
glocal.sessions.erase(s);
}
}
auto it = glocal.sessions.find(sessionid);
if (it == glocal.sessions.end()){
glocal.nbsessions_created++;
glocal.sessions[sessionid]=SESSION_INFO();
}else{
tlmp_error ("createsession: %s already exists\n",sessionid);
}
rep_test (true);
tlmp_error ("Admin: Invalid command: %s\n",line);
endclient = true;
}
bool some_errors = false;
if (fdpass_setcontrol(s,glocal.control,glocal.user)==-1){
some_errors = true;
}
if (s.listen (NULL,adminport)==-1){
some_errors = true;
}
if (!some_errors && s.is_ok()){
chmod (clientport.c_str()+5,0666);
chmod (adminport.c_str()+5,0666);
s.setmaxclients (glocal.maxhandles);
s.setrawmode(true);
if (glocal.daemon){
daemon_init(glocal.pidfile,glocal.user);
}
s.loop();
ret = 0;
}
return ret;
return glocal.ret;
}