/***************************************************************************
FILE: cl_group.cc
LVU : 1.4.1
DESC:
Object for a group including code to join/leave users, set to private/public
and so on.
Copyright (C) Neil Robertson 2003-2005
This program 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 2 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 General Public License for more details.
***************************************************************************/
#include "globals.h"
/*** Given id load config file. This is for public and user groups ***/
cl_group::cl_group(uint16_t gid, cl_local_user *own)
{
FILE *fp;
cl_group *grp;
struct stat fs;
int linenum,ban_level,i,err;
uint16_t uid;
cl_splitline sl(1);
char path[MAXPATHLEN];
char line[ARR_SIZE];
char *config_option[]={
"name",
"private",
"fixed",
"ban"
};
enum {
OPT_NAME,
OPT_PRIVATE,
OPT_FIXED,
OPT_BAN,
OPT_END
};
name = NULL;
/* Its inefficient having to call init first but if theres an error on
group loading everything has to be set up ok for the destructor to
work properly */
init(gid,own ? GROUP_TYPE_USER : GROUP_TYPE_PUBLIC,own);
if ((type == GROUP_TYPE_USER && id < MIN_LOCAL_USER_ID) ||
(type == GROUP_TYPE_PUBLIC && id >= MIN_LOCAL_USER_ID)) {
error = ERR_INVALID_ID; return;
}
// See if group with this id already exists
if ((grp = get_group(gid)) && grp != this) {
error = ERR_DUPLICATE_ID; return;
}
// User group config
if (own) {
sprintf(path,"%s/%04X/%s",USER_DIR,id,USER_GROUP_CONFIG_FILE);
sprintf(glogfile,"%s/%04X/%s",USER_DIR,id,USER_GROUP_LOG_FILE);
}
else {
// Public group config
sprintf(path,"%s/%04X/",PUB_GROUP_DIR,gid);
if (stat(path,&fs) == -1 || (fs.st_mode & S_IFMT) != S_IFDIR) {
error = ERR_NO_DIR; return;
}
strcat(path,PUB_GROUP_CONFIG_FILE);
sprintf(glogfile,"%s/%04X/%s",PUB_GROUP_DIR,gid,PUB_GROUP_LOG_FILE);
}
// Open config file
if (!(fp=fopen(path,"r"))) {
error = ERR_CANT_OPEN_FILE; return;
}
err = 0;
linenum = 1;
fgets(line,ARR_SIZE-1,fp);
while(!feof(fp) && !(err = ferror(fp))) {
if (sl.parse(line) != OK) goto ERROR;
if (sl.wcnt) {
for(i=0;i < OPT_END;++i)
if (!strcmp(sl.word[0],config_option[i])) break;
switch(i) {
case OPT_NAME:
if (sl.wcnt > 2 || !sl.word[1][0]) goto ERROR;
set_name(sl.word[1]);
break;
case OPT_PRIVATE:
if (!strcasecmp(sl.word[1],"YES"))
SETFLAG(GROUP_FLAG_PRIVATE);
else
if (strcasecmp(sl.word[1],"NO")) goto ERROR;
break;
case OPT_FIXED:
if (!strcasecmp(sl.word[1],"YES"))
SETFLAG(GROUP_FLAG_FIXED);
else
if (strcasecmp(sl.word[1],"NO")) goto ERROR;
break;
case OPT_BAN:
if (sl.wcnt < 3 ||
(ban_level = get_level(sl.word[1])) == -1 ||
!(uid = idstr_to_id(sl.word[2])))
goto ERROR;
switch(sl.wcnt) {
case 3:
ban(ban_level,uid,0,0);
break;
case 5:
ban(ban_level,uid,
(uint32_t)inet_addr(sl.word[3]),
htons((uint16_t)atoi(sl.word[4])));
break;
default: goto ERROR;
}
break;
default:
if (own) own->warnprintf("Unknown option '%s' on group config file line %d.\n",sl.word[0],linenum);
else {
if (booting)
printf(" WARNING: Unknown option '%s' on config file line %d.\n",sl.word[0],linenum);
else
log(1,"WARNING: Unknown option '%s' for group %04X on config file line %d.\n",sl.word[0],id,linenum);
}
}
}
fgets(line,ARR_SIZE-1,fp);
++linenum;
continue;
ERROR:
if (own) own->warnprintf("Invalid configuration for option '%s' on group config file line %d.\n",config_option[i],linenum);
else {
if (booting)
printf(" WARNING: Invalid configuration for option '%s' on config file line %d.\n",config_option[i],linenum);
else
log(1,"WARNING: Invalid configuration for option '%s' for group %04X on config file line %d.\n",config_option[i],id,linenum);
}
fgets(line,ARR_SIZE-1,fp);
++linenum;
}
fclose(fp);
grouplog(false,"~BG******************** GROUP LOADED/CREATED *******************\n");
if (err) log(1,"ERROR: Read failure while reading config file: %s\n",strerror(err));
if (!name) error = ERR_NAME_NOT_SET;
}
/*** Constructor for hard coded and user groups if user group config file
doesn't exist for some reason and for public groups created by the
"group create" command. ***/
cl_group::cl_group(uint16_t gid, char *nme, int typ, cl_local_user *own)
{
cl_group *grp;
char path[MAXPATHLEN];
name = NULL;
glogfile[0] = 0;
set_name(nme);
init(gid,typ,own);
// Errors checked after init since init sets up stuff that destructor
// will undo so it must be run regardless...
if ((grp = get_group(gid)) && grp != this) {
error = ERR_DUPLICATE_ID; return;
}
switch(type) {
case GROUP_TYPE_SYSTEM:
if (id >= MIN_LOCAL_USER_ID) error = ERR_INVALID_ID;
return;
case GROUP_TYPE_PUBLIC:
if (id >= MIN_LOCAL_USER_ID) {
error = ERR_INVALID_ID; return;
}
// Create directory. Don't check result since any errors will become
// apparent on save.
sprintf(path,"%s/%04X",PUB_GROUP_DIR,gid);
mkdir(path,0700);
error = save();
sprintf(glogfile,"%s/%04X/%s",PUB_GROUP_DIR,gid,PUB_GROUP_LOG_FILE);
break;
case GROUP_TYPE_USER:
if (id < MIN_LOCAL_USER_ID) error = ERR_INVALID_ID;
}
grouplog(false,"~BG*********************** GROUP CREATED ***********************\n");
}
/*** Initialise everything except the name ***/
void cl_group::init(uint16_t gid, int typ, cl_local_user *own)
{
int i;
id = gid;
type = typ;
error = OK;
ucnt = 0;
flags = 0;
owner = own;
revpos = 0;
first_ban = NULL;
last_ban = NULL;
board = ((id != GONE_REMOTE_GROUP_ID) ? new cl_board(this) : NULL);
revbuff = new revline[num_review_lines];
for(i=0;i < num_review_lines;++i) {
revbuff[i].line = NULL;
revbuff[i].alloc = 0;
}
switch(type) {
case GROUP_TYPE_SYSTEM: system_group_count++; break;
case GROUP_TYPE_PUBLIC: public_group_count++; break;
case GROUP_TYPE_USER : user_group_count++;
}
add_list_item(first_group,last_group,this);
}
/*** Destructor ***/
cl_group::~cl_group()
{
cl_user *u;
st_user_ban *gb,*gbn;
int i;
// Return all users to their own group and if they were using the board
// reader terminate it etc
FOR_ALL_USERS(u) {
/* If user is being prompted about deleting this group then reset.
User who is actually deleting group will have had this set to NULL
already */
if (u->del_group == this) u->reset_to_cmd_stage();
// If user is in group then bung him back to his home group unless it
// is his home group in which case hes logging off so dont bother
if (u->group == this && this != u->home_group) {
u->uprintf("\n~FYYour current group has been deleted. Returning to your home group...\n");
u->home_group->join(u);
u->prompt();
}
// Delete any invites for this group
for(i=0;i < MAX_INVITES;++i) {
if (u->invite[i].grp == this) {
u->infoprintf("Your invite into group %04X (%s~RS) has been revoked because the group has been deleted.\n",id,name);
u->invite[i].grp = NULL;
break;
}
}
// If user is paging info on this group then reset pointer
if (u->com_page_ptr == (void *)this) u->com_page_ptr = NULL;
// If user was monitoring this group then reset
if (u->mon_group == this) {
u->infoprintf("You can no longer monitor group ~FT%04X~RS (%s~RS)\n",id,name);
u->mon_group = NULL;
}
if (u->prev_group == this) u->prev_group = NULL;
}
FREE(name);
// Free review lines & delete board
for(i=0;i < num_review_lines;++i) FREE(revbuff[i].line);
delete revbuff;
if (board) delete board;
// Delete bans
for(gb = first_ban;gb;gb = gbn) {
gbn = gb->next;
delete gb;
}
// Write messge to log
grouplog(false,"~BY******************* GROUP UNLOADED/DELETED ******************\n");
switch(type) {
case GROUP_TYPE_SYSTEM: system_group_count--; break;
case GROUP_TYPE_PUBLIC: public_group_count--; break;
case GROUP_TYPE_USER : user_group_count--;
}
remove_list_item(first_group,last_group,this);
}
//////////////////// METHODS ///////////////////////
/*** Set the name ***/
int cl_group::set_name(char *nme)
{
char *tmp;
if (!nme) nme = "";
if (!(tmp = strdup(nme))) return ERR_MALLOC;
if ((int)strlen(tmp) > max_group_name_len) tmp[max_group_name_len] = '\0';
FREE(name);
name = tmp;
return OK;
}
/*** Set group to private ***/
int cl_group::set_private()
{
cl_user *u;
if (type == GROUP_TYPE_SYSTEM) return ERR_SYSTEM_GROUP;
if (FLAGISSET(GROUP_FLAG_PRIVATE)) return ERR_GROUP_ACCESS_SAME;
if (FLAGISSET(GROUP_FLAG_FIXED)) return ERR_GROUP_FIXED;
SETFLAG(GROUP_FLAG_PRIVATE);
// If anyone monitoring this group then switch it off. Can't be arsed to
// check if they would still have permission or not, let em just reset it.
FOR_ALL_USERS(u) {
if (u->mon_group == this) {
u->infoprintf("Group ~FT%04X~RS (%s~RS) has been set to private so you are no longer monitoring the group.\n",id,name);
u->mon_group = NULL;
}
}
// Only user groups can be loaded as private if they're not fixed
return (type != GROUP_TYPE_SYSTEM) ? save() : OK;
}
/*** Set group to public ***/
int cl_group::set_public()
{
cl_user *u;
int i;
if (type == GROUP_TYPE_SYSTEM) return ERR_SYSTEM_GROUP;
if (!FLAGISSET(GROUP_FLAG_PRIVATE)) return ERR_GROUP_ACCESS_SAME;
if (FLAGISSET(GROUP_FLAG_FIXED)) return ERR_GROUP_FIXED;
UNSETFLAG(GROUP_FLAG_PRIVATE);
// Revoke any invites
FOR_ALL_USERS(u) {
if (u->level != USER_LEVEL_LOGIN) {
for(i=0;i < MAX_INVITES;++i) {
if (u->invite[i].grp == this) {
u->infoprintf("Your invite to group %04X (%s~RS) has been revoked because the group has returned to public access.\n",id,name);
u->invite[i].grp = NULL;
break;
}
}
}
}
return (type != GROUP_TYPE_SYSTEM) ? save() : OK;
}
/*** Set group to fixed ***/
int cl_group::set_fixed()
{
if (type == GROUP_TYPE_SYSTEM) return ERR_SYSTEM_GROUP;
if (FLAGISSET(GROUP_FLAG_FIXED)) return ERR_GROUP_ACCESS_SAME;
SETFLAG(GROUP_FLAG_FIXED);
return (type != GROUP_TYPE_SYSTEM) ? save() : OK;
}
/*** Set group to unfixed ***/
int cl_group::set_unfixed()
{
if (type == GROUP_TYPE_SYSTEM) return ERR_SYSTEM_GROUP;
if (!FLAGISSET(GROUP_FLAG_FIXED)) return ERR_GROUP_ACCESS_SAME;
UNSETFLAG(GROUP_FLAG_FIXED);
return (type != GROUP_TYPE_SYSTEM) ? save() : OK;
}
/*** Save the groups config ***/
int cl_group::save()
{
char path[MAXPATHLEN];
char path2[MAXPATHLEN];
FILE *fp;
st_user_ban *gb;
switch(type) {
case GROUP_TYPE_SYSTEM: return OK;
case GROUP_TYPE_USER:
sprintf(path,"%s/%04X/groupconfig.tmp",USER_DIR,id);
break;
case GROUP_TYPE_PUBLIC:
sprintf(path,"%s/%04X/config.tmp",PUB_GROUP_DIR,id);
}
if (!(fp = fopen(path,"w"))) return ERR_CANT_OPEN_FILE;
fprintf(fp,"name = \"%s\"\n",name);
fprintf(fp,"private = %s\n",noyes[FLAGISSET(GROUP_FLAG_PRIVATE)]);
fprintf(fp,"fixed = %s\n",noyes[FLAGISSET(GROUP_FLAG_FIXED)]);
FOR_ALL_GROUP_BANS(gb) {
if (gb->utype == USER_TYPE_LOCAL)
fprintf(fp,"ban = %s, %04X\n",user_level[gb->level],gb->uid);
else fprintf(fp,"ban = %s, %04X, %s, %u\n",
user_level[gb->level],
gb->uid,
inet_ntoa(gb->home_addr.sin_addr),
ntohs(gb->home_addr.sin_port));
}
fclose(fp);
if (type == GROUP_TYPE_USER)
sprintf(path2,"%s/%04X/%s",USER_DIR,id,USER_GROUP_CONFIG_FILE);
else
sprintf(path2,"%s/%04X/%s",PUB_GROUP_DIR,id,PUB_GROUP_CONFIG_FILE);
if (rename(path,path2)) {
unlink(path); return ERR_CANT_RENAME_FILE;
}
return OK;
}
/** Save the description to a file ***/
int cl_group::save_desc(char *desc)
{
char path[MAXPATHLEN];
FILE *fp;
int ret;
if (type == GROUP_TYPE_USER)
sprintf(path,"%s/%04X/%s",USER_DIR,id,USER_GROUP_DESC_FILE);
else
sprintf(path,"%s/%04X/%s",PUB_GROUP_DIR,id,PUB_GROUP_DESC_FILE);
if (!(fp = fopen(path,"w"))) return ERR_CANT_OPEN_FILE;
ret=fputs(desc,fp);
fclose(fp);
return (ret == EOF ? ERR_WRITE : OK);
}
/*** User joins the group ***/
void cl_group::join(cl_user *u, cl_server *server, uint16_t remgid)
{
cl_server *svr;
// Leaves old group. Will be null if new remote user
if (u->group &&
!O_FLAGISSET(u,USER_FLAG_LEFT) &&
(u->group != gone_remote_group ||
(u->group == gone_remote_group && u->server_to != server)))
u->group->leave(u);
u->prev_group = u->group;
u->group=this;
u->server_to = server;
if (this == gone_remote_group)
// Joining remote group
u->uprintf("You join group %04X@%s\n",remgid,server->name);
else {
// Joining this local group
if (!O_FLAGISSET(u,USER_FLAG_INVISIBLE))
geprintf(
MSG_MISC,
u,
NULL,"~BTJOINED:~RS ~FT%04X~RS, %s %s\n",u->id,u->name,u->desc);
// Don't look if we're a new login joining start group because thats
// done by do_login_messages()
if (!O_FLAGISSET(u,USER_FLAG_NEW_LOGIN)) u->look(u->group,0);
}
ucnt++;
// Send out group change notification
FOR_ALL_SERVERS(svr)
if (svr->stage == SERVER_STAGE_CONNECTED) svr->send_group_change(u);
}
/*** User leaves a group. This just resets some stuff. ***/
void cl_group::leave(cl_user *u)
{
if (this == gone_remote_group) {
u->server_to->send_leave(u->id);
u->server_to = NULL;
u->group = NULL;
}
else
if (!O_FLAGISSET(u,USER_FLAG_INVISIBLE))
geprintf(MSG_MISC,u,NULL,"~BMLEFT:~RS ~FT%04X~RS, %s %s\n",
u->id,u->name,u->desc);
// If doing anything on the board then quit as user could have been forced
// to leave group.
switch(u->stage) {
case USER_STAGE_BOARD:
case USER_STAGE_BOARD_DEL:
case USER_STAGE_BOARD_SUBJECT:
case USER_STAGE_BOARD_READ_FROM:
u->uprintf("~NP\n\n~FYForcing exit of board reader.\n\n");
FREE(u->msg_subject);
u->page_pos = 0;
u->stage = USER_STAGE_CMD_LINE;
if (u->editor) delete u->editor;
u->flags = u->prev_flags;
u->prompt();
}
// If no one left and group is private, return it to public.
if (!--ucnt && type == GROUP_TYPE_PUBLIC) set_public();
}
/*** Send text to all users in the group ***/
void cl_group::gprintf(int mtype, char *fmtstr,...)
{
char str[ARR_SIZE],str2[ARR_SIZE],*s;
va_list args;
cl_user *u;
int ret;
va_start(args,fmtstr);
vsnprintf(str,ARR_SIZE,fmtstr,args);
va_end(args);
FOR_ALL_USERS(u) {
if (u->group == this || u->mon_group == this) {
if (u->mon_group == this) {
sprintf(str2,"~OLMONITOR %04X: ~RS%s",id,str);
s = str2;
}
else s = str;
switch(mtype) {
case MSG_SPEECH:
if (!O_FLAGISSET(u,USER_FLAG_NO_SPEECH)) u->uprintf(s);
break;
case MSG_SHOUT:
// This will never be used here but include
// for the sake of completeness.
if (!O_FLAGISSET(u,USER_FLAG_NO_SHOUTS)) u->uprintf(s);
break;
case MSG_INFO:
u->infoprintf(s);
break;
case MSG_MISC:
if (!O_FLAGISSET(u,USER_FLAG_NO_MISC)) u->uprintf(s);
break;
case MSG_SYSTEM:
u->sysprintf(s);
break;
case MSG_BCAST:
u->uprintf(s);
}
}
}
grouplog(false,str);
if ((ret=add_review_line(revbuff,&revpos,str)) != OK)
log(1,"ERROR: cl_group::gprintf() -> add_revline_line(): %s",
err_string[ret]);
}
/*** Send text to all users in group except those specified ***/
void cl_group::geprintf(int mtype, cl_user *u1, cl_user *u2, char *fmtstr, ...)
{
char str[ARR_SIZE],str2[ARR_SIZE],*s;
va_list args;
cl_user *u;
int ret;
va_start(args,fmtstr);
vsnprintf(str,ARR_SIZE,fmtstr,args);
va_end(args);
FOR_ALL_USERS(u) {
if (u != u1 &&
u != u2 && u->group == this) {
if (u->mon_group == this) {
sprintf(str2,"~OLMONITOR %04X: ~RS%s",id,str);
s = str2;
}
else s = str;
switch(mtype) {
case MSG_SPEECH:
if (!O_FLAGISSET(u,USER_FLAG_NO_SPEECH)) u->uprintf(s);
break;
case MSG_SHOUT:
// This will never be used here but include
// for the sake of completeness.
if (!O_FLAGISSET(u,USER_FLAG_NO_SHOUTS)) u->uprintf(s);
break;
case MSG_INFO:
u->infoprintf(s);
break;
case MSG_MISC:
if (!O_FLAGISSET(u,USER_FLAG_NO_MISC)) u->uprintf(s);
break;
case MSG_SYSTEM:
u->sysprintf(s);
break;
case MSG_BCAST:
u->uprintf(s);
}
}
}
grouplog(false,str);
if ((ret=add_review_line(revbuff,&revpos,str)) != OK)
log(1,"ERROR: cl_group::gprintf() -> add_revline_line(): %s",
err_string[ret]);
}
/*** User speaks ***/
int cl_group::speak(int comnum, cl_user *u, char *txt)
{
// Cheat a bit. Don't return an error here but print a message.
if (O_FLAGISSET(u,USER_FLAG_MUZZLED)) {
if (u->muzzle_end_time)
u->uprintf("You cannot %s because you are muzzled for another %s.\n",
command[comnum],
time_period(u->muzzle_end_time - server_time));
else
u->uprintf("You cannot %s because you are muzzled indefinately.\n",command[comnum]);
return OK;
}
if (this == gone_remote_group) return ERR_RESTRICTED_GROUP;
if (O_FLAGISSET(u,USER_FLAG_NO_SPEECH)) return ERR_NOSPEECH;
switch(comnum) {
case COM_SAY:
gprintf(MSG_SPEECH,"~FT%04X,%s~FG:~RS %s\n",u->id,u->name,txt);
break;
case COM_EMOTE:
gprintf(MSG_SPEECH,"~FT%04X~FG:~RS %s %s\n",u->id,u->name,txt);
break;
case COM_THINK:
gprintf(MSG_SPEECH,"~FT%04X~FG:~RS %s thinks . o O ( %s )\n",
u->id,u->name,txt);
}
return OK;
}
/*** Returns whether user can modify anything about the group ***/
int cl_group::user_can_modify(cl_user *u)
{
return (type != GROUP_TYPE_SYSTEM &&
(this == u->home_group || u->level >= group_modify_level));
}
/*** Returns whether user can join the group. Return invite number in inv
parameter if only let it because of this ***/
int cl_group::user_can_join(cl_user *u, int *inv)
{
int i;
*inv = -1;
if (this == u->home_group) return 1;
if (this == gone_remote_group || this == prison_group || user_is_banned(u))
return 0;
if (!FLAGISSET(GROUP_FLAG_PRIVATE) || u->level >= group_gatecrash_level)
return 1;
// Group is private. See if user has an invite
for(i=0;i < MAX_INVITES;++i) {
if (u->invite[i].grp == this) {
*inv = i; return 1;
}
}
return 0;
}
/*** Evict someone from the group ***/
void cl_group::evict(cl_user *evictor, cl_user *evictee)
{
evictor->uprintf("You evict user ~FT%04X~RS (%s).\n",evictee->id,evictee->name);
geprintf(
MSG_INFO,evictor,evictee,
"User ~FT%04X~RS (%s) is evicted from this group by ~FT%04X~RS (%s)\n",
evictee->id,evictee->name,evictor->id,evictor->name);
evictee->uprintf(
"\n~OL~FRYou have been evicted from this group by user ~FT%04X~RS (%s)!\n\n",
evictor->id,evictor->name);
evictee->home_group->join(evictee);
evictee->prompt();
}
/*** Ban user using id or ip info. Port must be in network order. ***/
void cl_group::ban(int ban_level, uint16_t uid, uint32_t addr, uint16_t port)
{
st_user_ban *gb;
gb = new st_user_ban;
gb->level = ban_level;
gb->uid = uid; // For remote users this will be orig_id
bzero(&gb->home_addr,sizeof(sockaddr_in));
if (addr) {
gb->utype = USER_TYPE_REMOTE;
gb->user = get_remote_user(uid,addr,port);
gb->home_addr.sin_addr.s_addr = addr;
gb->home_addr.sin_port = port;
}
else {
gb->utype = USER_TYPE_LOCAL;
gb->user = get_user(uid,0);
}
add_list_item(first_ban,last_ban,gb);
}
/*** Ban a user. This saves the info. ***/
int cl_group::ban(int ban_level, cl_user *u)
{
st_user_ban *gb;
int i;
if (type == GROUP_TYPE_SYSTEM) return ERR_SYSTEM_GROUP;
if (u->mon_group == this) u->mon_group = NULL;
// Remove invite to group if it exists and add to banned list
for(i=0;i < MAX_INVITES;++i) {
if (u->invite[i].grp == this) {
u->invite[i].grp = NULL; break;
}
}
gb = new st_user_ban;
gb->level = ban_level;
gb->utype = u->type;
gb->user = u;
if (u->type == USER_TYPE_REMOTE) {
gb->uid = ((cl_remote_user *)u)->orig_id;
gb->home_addr = u->ip_addr;
}
else gb->uid = u->id;
add_list_item(first_ban,last_ban,gb);
return save();
}
/*** Return whether user is banned. For logged on users. ***/
int cl_group::user_is_banned(cl_user *u)
{
st_user_ban *gb;
if (this == u->home_group || u->level >= group_gatecrash_level) return 0;
// Can't just check against the user pointer in the structure since the
// user may have left/logged off then returned.
if (u->type == USER_TYPE_LOCAL) {
FOR_ALL_GROUP_BANS(gb)
if (gb->utype == USER_TYPE_LOCAL &&
u->id == gb->uid) return 1;
return 0;
}
FOR_ALL_GROUP_BANS(gb) {
// Check original id matches as they may have come over multiple hops
if (gb->utype == USER_TYPE_REMOTE &&
gb->uid == ((cl_remote_user *)u)->orig_id &&
gb->home_addr.sin_addr.s_addr == u->ip_addr.sin_addr.s_addr &&
gb->home_addr.sin_port == u->ip_addr.sin_port) return 1;
}
return 0;
}
/*** Return whether user is banned. For remote users trying to connect ***/
int cl_group::user_is_banned(pkt_user_info *pkt)
{
st_user_ban *gb;
FOR_ALL_GROUP_BANS(gb) {
if (gb->utype == USER_TYPE_REMOTE &&
gb->uid == pkt->orig_uid &&
gb->home_addr.sin_addr.s_addr == pkt->home_addr.ip4 &&
gb->home_addr.sin_port == pkt->home_port) return 1;
}
return 0;
}
/*** Log some text. We can't error in this since we'd get an error in the
main log every time someone spoke etc which would be a pain. The
file pointer is re-opened each time so that A) we use up less descriptors
and B) so that the current file can be removed or renamed without
affecting subsequent writes. ***/
void cl_group::grouplog(bool force, char *str)
{
FILE *fp;
char logstr[ARR_SIZE];
char tstr[20];
if ((force || SYS_FLAGISSET(SYS_FLAG_LOG_GROUPS)) &&
(fp = fopen(glogfile,"a"))) {
strftime(tstr,sizeof(tstr),"%d/%m %H:%M:%S: ",&server_time_tms);
snprintf(logstr,ARR_SIZE-20,"%s%s",tstr,str);
fputs(logstr,fp);
fclose(fp);
}
}