/* * flags.c - all the flag matching/conversion functions in one neat * package :) */ /* * see main.c for licencing info */ #include "main.h" extern int use_console_r; extern int debug_output; extern int require_p; extern struct userrec * userlist; extern struct chanset_t * chanset; extern struct dcc_t * dcc; extern int noshare; extern int allow_dk_cmds; /* allow users to set their console +r */ int use_console_r = 0; int logmodes (char * s) { int i; int res = 0; for (i = 0; i < strlen(s); i++) switch (s[i]) { case 'm': case 'M': res |= LOG_MSGS; break; case 'p': case 'P': res |= LOG_PUBLIC; break; case 'j': case 'J': res |= LOG_JOIN; break; case 'k': case 'K': res |= LOG_MODES; break; case 'c': case 'C': res |= LOG_CMDS; break; case 'o': case 'O': res |= LOG_MISC; break; case 'b': case 'B': res |= LOG_BOTS; break; case 'r': case 'R': res |= use_console_r ? LOG_RAW : 0; break; case 'w': case 'W': res |= LOG_WALL; break; case 'x': case 'X': res |= LOG_FILES; break; case 's': case 'S': res |= LOG_SERV; break; case 'd': case 'D': res |= LOG_DEBUG; break; case 'v': case 'V': res |= debug_output ? LOG_SRVOUT : 0; break; case 't': case 'T': res |= debug_output ? LOG_BOTNET : 0; break; case 'h': case 'H': res |= debug_output ? LOG_BOTSHARE : 0; break; case '1': res |= LOG_LEV1; break; case '2': res |= LOG_LEV2; break; case '3': res |= LOG_LEV3; break; case '4': res |= LOG_LEV4; break; case '5': res |= LOG_LEV5; break; case '6': res |= LOG_LEV6; break; case '7': res |= LOG_LEV7; break; case '8': res |= LOG_LEV8; break; case '*': res |= LOG_ALL; break; } return res; } char *masktype (int x) { static char s[20]; char *p = s; if (x & LOG_MSGS) *p++ = 'm'; if (x & LOG_PUBLIC) *p++ = 'p'; if (x & LOG_JOIN) *p++ = 'j'; if (x & LOG_MODES) *p++ = 'k'; if (x & LOG_CMDS) *p++ = 'c'; if (x & LOG_MISC) *p++ = 'o'; if (x & LOG_BOTS) *p++ = 'b'; if ((x & LOG_RAW) && use_console_r) *p++ = 'r'; if (x & LOG_FILES) *p++ = 'x'; if (x & LOG_SERV) *p++ = 's'; if (x & LOG_DEBUG) *p++ = 'd'; if (x & LOG_WALL) *p++ = 'w'; if ((x & LOG_SRVOUT) && debug_output) *p++ = 'v'; if ((x & LOG_BOTNET) && debug_output) *p++ = 't'; if ((x & LOG_BOTSHARE) && debug_output) *p++ = 'h'; if (x & LOG_LEV1) *p++ = '1'; if (x & LOG_LEV2) *p++ = '2'; if (x & LOG_LEV3) *p++ = '3'; if (x & LOG_LEV4) *p++ = '4'; if (x & LOG_LEV5) *p++ = '5'; if (x & LOG_LEV6) *p++ = '6'; if (x & LOG_LEV7) *p++ = '7'; if (x & LOG_LEV8) *p++ = '8'; if (p == s) *p++ = '-'; *p = 0; return s; } char *maskname (int x) { static char s[161]; int i = 0; s[0] = 0; if (x & LOG_MSGS) i += my_strcpy(s, "msgs, "); if (x & LOG_PUBLIC) i += my_strcpy(s + i, "public, "); if (x & LOG_JOIN) i += my_strcpy(s + i, "joins, "); if (x & LOG_MODES) i += my_strcpy(s + i, "kicks/modes, "); if (x & LOG_CMDS) i += my_strcpy(s + i, "cmds, "); if (x & LOG_MISC) i += my_strcpy(s + i, "misc, "); if (x & LOG_BOTS) i += my_strcpy(s + i, "bots, "); if ((x & LOG_RAW) && use_console_r) i += my_strcpy(s + i, "raw, "); if (x & LOG_FILES) i += my_strcpy( s + i, "files, "); if (x & LOG_SERV) i += my_strcpy( s + i, "server, "); if (x & LOG_DEBUG) i += my_strcpy( s + i, "debug, "); if (x & LOG_WALL) i += my_strcpy( s + i, "wallops, "); if ((x & LOG_SRVOUT) && debug_output) i += my_strcpy( s + i, "server output, "); if ((x & LOG_BOTNET) && debug_output) i += my_strcpy( s + i, "botnet traffic, "); if ((x & LOG_BOTSHARE) && debug_output) i += my_strcpy( s + i, "share traffic, "); if (x & LOG_LEV1) i += my_strcpy( s + i, "level 1, "); if (x & LOG_LEV2) i += my_strcpy( s + i, "level 2, "); if (x & LOG_LEV3) i += my_strcpy( s + i, "level 3, "); if (x & LOG_LEV4) i += my_strcpy( s + i, "level 4, "); if (x & LOG_LEV5) i += my_strcpy( s + i, "level 5, "); if (x & LOG_LEV6) i += my_strcpy( s + i, "level 6, "); if (x & LOG_LEV7) i += my_strcpy( s + i, "level 7, "); if (x & LOG_LEV8) i += my_strcpy( s + i, "level 8, "); if (i) s[i-2] = 0; else strcpy(s,"none"); return s; } /* some flags are mutually exclusive -- this roots them out */ int sanity_check(int atr) { if ((atr & USER_BOT) && (atr & (USER_PARTY | USER_MASTER | USER_COMMON | USER_OWNER))) atr &= ~(USER_PARTY | USER_MASTER | USER_COMMON | USER_OWNER); if ((atr & USER_OP) && (atr & USER_DEOP)) atr &= ~(USER_OP | USER_DEOP); if ((atr & USER_VOICE) && (atr & USER_QUIET)) atr &= ~(USER_VOICE | USER_QUIET); /* can't be owner without also being master */ if (atr & USER_OWNER) atr |= USER_MASTER; /* master implies botmaster, op & friend */ if (atr & USER_MASTER) atr |= USER_BOTMAST|USER_OP|USER_FRIEND|USER_JANITOR; /* can't be botnet master without party-line access */ if (atr & USER_BOTMAST) atr |= USER_PARTY; /* janitors can use the file area */ if (atr & USER_JANITOR) atr |= USER_XFER; return atr; } /* sanity check on channel attributes */ int chan_sanity_check(int chatr, int atr) { if ((chatr & USER_OP) && (chatr & USER_DEOP)) chatr &= ~(USER_OP | USER_DEOP); if ((chatr & USER_VOICE) && (chatr & USER_QUIET)) chatr &= ~(USER_VOICE | USER_QUIET); /* can't be channel owner without also being channel master */ if (chatr & USER_OWNER) chatr |= USER_MASTER; /* master implies friend & op */ if (chatr & USER_MASTER) chatr |= USER_OP|USER_FRIEND; /* can't be +s on chan unless you're a bot */ if (!(atr & USER_BOT)) chatr &= ~BOT_SHARE; return chatr; } /* get icon symbol for a user (depending on access level) */ /* (*)owner on any channel (+)master on any channel (%) botnet master */ /* (@)op on any channel (-)other */ char geticon (int idx) { struct flag_record fr = {FR_GLOBAL|FR_CHAN|FR_ANYWH,0,0,0,0,0}; if (!dcc[idx].user) return '-'; get_user_flagrec(dcc[idx].user,&fr,0); if (chan_owner(fr)) return '*'; if (chan_master(fr)) return '+'; if (glob_botmast(fr)) return '%'; if (chan_op(fr)) return '@'; return '-'; } void break_down_flags (char * string, struct flag_record * plus, struct flag_record * minus) { struct flag_record * which = plus; int mode = 0; /* 0 = glob, 1 = chan, 2 = bot */ int flags = plus->match; if (!(flags & FR_GLOBAL)) { if (flags & FR_BOT) mode = 2; else if (flags & FR_CHAN) mode = 1; else return; /* we dont actually want any..huh?*/ } bzero(plus,sizeof(struct flag_record)); if (minus) bzero(minus,sizeof(struct flag_record)); plus->match = FR_OR; /* befault binding type OR */ while (*string) { switch (*string) { case '+': which = plus; break; case '-': which = minus ? minus : plus; break; case '|': case '&': if (mode == 0) { if (*string == '|') plus->match = FR_OR; else plus->match = FR_AND; } which = plus; mode++; if ((mode == 2) && !(flags & (FR_CHAN|FR_BOT))) string = ""; else if (mode == 3) mode = 1; break; default: if ((*string >= 'a') && (*string <= 'z')) { switch (mode) { case 0: which->global |= 1 << (*string - 'a'); break; case 1: which->chan |= 1 << (*string - 'a'); break; case 2: which->bot |= 1 << (*string - 'a'); } } else if ((*string >= 'A') && (*string <= 'Z')) { switch (mode) { case 0: which->udef_global |= 1 << (*string - 'A'); break; case 1: which->udef_chan |= 1 << (*string - 'A'); break; } } else if ((*string >= '0') && (*string <= '9')) { switch (mode) { /* map 0->9 to A->K for glob/chan so they are not lost */ case 0: which->udef_global |= 1 << (*string - '0'); break; case 1: which->udef_chan |= 1 << (*string - '0'); break; case 2: which->bot |= BOT_FLAG0 << (*string - '0'); break; } } } string++; } for (which = plus;which;which=(which==plus?minus:0)) { which->global &= USER_VALID; which->udef_global &= 0x03ffffff; which->chan &= CHAN_VALID; which->udef_chan &= 0x03ffffff; which->bot &= BOT_VALID; } plus->match |= flags; if (minus) { minus->match |= flags; if (!(plus->match & (FR_AND|FR_OR))) plus->match |= FR_OR; } } static int flag2str(char * string, int bot, int udef) { char x = 'a', *old = string; while (bot && (x <= 'z')) { if (bot & 1) *string ++ = x; x++; bot = bot >> 1; } x = 'A'; while (udef && (x <= 'Z')) { if (udef & 1) *string ++ = x; udef = udef >> 1; x++; } if (string == old) *string++ = '-'; return string - old; } static int bot2str(char * string, int bot) { char x = 'a',*old = string; while (x < 'v') { if (bot & 1) *string ++ = x; x++; bot >>= 1; } x = '0'; while (x <= '9') { if (bot & 1) *string ++ = x; x++; bot >>= 1; } return string -old; } int build_flags (char * string, struct flag_record * plus, struct flag_record * minus) { char * old = string; if (plus->match & FR_GLOBAL) { if (minus && (plus->global || plus->udef_global)) *string ++ = '+'; string += flag2str(string, plus->global, plus->udef_global); if (minus && (minus->global || minus->udef_global)) { *string ++ = '-'; string += flag2str(string, minus->global, minus->udef_global); } } else if (plus->match & FR_BOT) { if (minus && plus->bot) *string ++ = '+'; string += bot2str(string,plus->bot); if (minus && minus->bot) { *string ++ = '-'; string += bot2str(string,minus->bot); } } if (plus->match & FR_CHAN) { if (plus->match & (FR_GLOBAL|FR_BOT)) *string ++ = (plus->match & FR_AND) ? '&' : '|'; if (minus && (plus->chan || plus->udef_chan)) *string ++ = '+'; string += flag2str(string, plus->chan, plus->udef_chan); if (minus && (minus->chan || minus->udef_chan)) { *string ++ = '-'; string += flag2str(string, minus->global, minus->udef_chan); } } if ((plus->match & (FR_BOT|FR_CHAN)) == (FR_BOT|FR_CHAN)) { *string ++ = (plus->match & FR_AND) ? '&' : '|'; if (minus && plus->bot) *string ++ = '+'; string += bot2str(string,plus->bot); if (minus && minus->bot) { *string ++ = '-'; string += bot2str(string,minus->bot); } } if (string == old) { *string ++ = '-'; *string = 0; return 0; } *string = 0; return string-old; } int flagrec_ok (struct flag_record * req, struct flag_record * have) { if (req->match & FR_AND) { return flagrec_eq(req,have); } else if (req->match & FR_OR) { int hav = have->global; /* exception 1 - global +d/+k cant use -|-, unless they are +p */ if (!req->chan && !req->global && !req->udef_global && !req->udef_chan) { if (!allow_dk_cmds) { if (glob_party(*have)) return 1; if (glob_kick(*have) || chan_kick(*have)) return 0; /* +k cant use -|- commands */ if (chan_deop(*have) || (glob_deop(*have) && !chan_deop(*have))) return 0; /* neither can +d's */ } return 1; } /* the +n/+m checks arent needed anymore since +n/+m * automatically add lower flags */ if (!require_p && ((hav & USER_OP) || (have->chan & USER_OWNER))) hav |= USER_PARTY; if (hav & req->global) return 1; if (have->chan & req->chan) return 1; if (have->udef_global & req->udef_global) return 1; if (have->udef_chan & req->udef_chan) return 1; return 0; } return 0; /* fr0k3 binding, dont pass it */ } int flagrec_eq (struct flag_record * req, struct flag_record * have) { if (req->match & FR_AND) { if (req->match & FR_GLOBAL) { if ((req->global & have->global) != req->global) return 0; if ((req->udef_global & have->udef_global) != req->udef_global) return 0; } if (req->match & FR_BOT) if ((req->bot & have->bot) != req->bot) return 0; if (req->match & FR_CHAN) { if ((req->chan & have->chan) != req->chan) return 0; if ((req->udef_chan & have->udef_chan) != req->udef_chan) return 0; } return 1; } else if (req->match & FR_OR) { if (!req->chan && !req->global && !req->udef_chan && !req->udef_global && !req->bot) return 1; if (req->match & FR_GLOBAL) { if (have->global & req->global) return 1; if (have->udef_global & req->udef_global) return 1; } if (req->match & FR_BOT) if (have->bot & req->bot) return 1; if (req->match & FR_CHAN) { if (have->chan & req->chan) return 1; if (have->udef_chan & req->udef_chan) return 1; } return 0; } return 0; /* fr0k3 binding, dont pass it */ } void set_user_flagrec (struct userrec * u, struct flag_record * fr, char * chname) { struct chanuserrec * cr; int oldflags = fr->match; char buffer[100]; struct chanset_t * ch; if (!u) return; if (oldflags & FR_GLOBAL) { u->flags = fr->global; u->flags_udef = fr->udef_global; if (!noshare && !(u->flags & USER_UNSHARED)) { fr->match = FR_GLOBAL; build_flags(buffer,fr,NULL); shareout(NULL,"a %s %s\n",u->handle,buffer); } } if ((oldflags & FR_BOT) && (u->flags & USER_BOT)) set_user(&USERENTRY_BOTFL,u,(void *)fr->bot); /* dont share bot attrs */ if ((oldflags & FR_CHAN) && chname) { for (cr = u->chanrec;cr;cr = cr->next) if (!strcasecmp(chname,cr->channel)) break; ch = findchan(chname); if (!cr && ch) { cr = user_malloc(sizeof(struct chanuserrec)); bzero(cr,sizeof(struct chanuserrec)); cr->next = u->chanrec; u->chanrec = cr; strncpy(cr->channel, chname, 80); cr->channel[80] = 0; } if (cr && ch) { cr->flags = fr->chan; cr->flags_udef = fr->udef_chan; if (!noshare && !(u->flags & USER_UNSHARED) && channel_shared(ch)) { fr->match = FR_CHAN; build_flags(buffer,fr,NULL); shareout(ch,"a %s %s %s\n",u->handle,buffer,chname); } } } fr->match = oldflags; } void get_user_flagrec (struct userrec * u, struct flag_record * fr, char * chname) { struct chanuserrec * cr; if (!u) { fr->global = fr->udef_global = fr->chan = fr->udef_chan = fr->bot = 0; return; } if (fr->match & FR_GLOBAL) { fr->global = u->flags; fr->udef_global = u->flags_udef; } else { fr->global = 0; fr->udef_global = 0; } if (fr->match & FR_BOT) { fr->bot = (long)get_user(&USERENTRY_BOTFL,u); } else fr->bot = 0; if (fr->match & FR_CHAN) { if (fr->match & FR_ANYWH) { fr->chan = u->flags; fr->udef_chan = u->flags_udef; for (cr = u->chanrec;cr;cr = cr->next) if (findchan(cr->channel)) { fr->chan |= cr->flags; fr->udef_chan |= cr->flags_udef; } } else { if (chname) for (cr = u->chanrec;cr;cr = cr->next) if (!strcasecmp(chname,cr->channel)) break; if (chname && cr) { fr->chan = cr->flags; fr->udef_chan = cr->flags_udef; } else { fr->chan = 0; fr->udef_chan =0; } } } } static int botfl_unpack (struct userrec * u, struct user_entry * e) { struct flag_record fr = {FR_BOT,0,0,0,0,0}; context; if (e->name) { char * p; p = e->u.list->extra; e->u.list->extra = NULL; list_type_kill(e->u.list); break_down_flags(p,&fr,NULL); e->u.ulong = fr.bot; nfree(p); } return 1; } static int botfl_pack (struct userrec * u, struct user_entry * e) { char x[100]; struct flag_record fr = {FR_BOT,0,0,0,0,0}; int l; if (!e->name) { char * p; e->name = user_malloc(strlen(e->type->name)+1); strcpy(e->name,e->type->name); fr.bot = e->u.ulong; l = build_flags(x,&fr,NULL); p = user_malloc(l+1); e->u.list = user_malloc(sizeof(struct list_type)); e->u.list->next = NULL; e->u.list->extra = p; strcpy(p,x); } return 1; } static int botfl_kill (struct user_entry * e) { context; nfree(e); return 1; } static int botfl_write_userfile (FILE * f, struct userrec * u, struct user_entry * e) { char x[100]; struct flag_record fr = {FR_BOT,0,0,0,0,0}; context; fr.bot = e->u.ulong; build_flags(x,&fr,NULL); if (fprintf(f,"--%s %s\n",e->type->name,x)==EOF) return 0; return 1; } static int botfl_set (struct userrec * u, struct user_entry * e, void * buf) { register long atr = ((long)buf & BOT_VALID); context; if (!(u->flags & USER_BOT)) return 1; /* don't even bother trying to set the flags for a non-bot */ if ((atr & BOT_HUB) && (atr & BOT_ALT)) atr &= ~BOT_ALT; if (atr & BOT_REJECT) { if (atr & BOT_SHARE) atr &= ~(BOT_SHARE | BOT_REJECT); if (atr & BOT_HUB) atr &= ~(BOT_HUB | BOT_REJECT); if (atr & BOT_ALT) atr &= ~(BOT_ALT | BOT_REJECT); } e->u.ulong = atr; context; return 1; } static int botfl_tcl_get (Tcl_Interp * interp, struct userrec * u, struct user_entry * e,int argc, char ** argv) { char x[100]; struct flag_record fr = {FR_BOT,0,0,0,0,0}; build_flags(x,&fr,NULL); Tcl_AppendResult(interp, x, NULL); return TCL_OK; } static int botfl_tcl_set (Tcl_Interp * irp, struct userrec * u, struct user_entry * e, int argc, char ** argv) { struct flag_record fr = {FR_BOT,0,0,0,0,0}; BADARGS(4,4," handle BOTFL flags"); if (u->flags & USER_BOT) { /* silently ignore for users */ break_down_flags(argv[3],&fr,NULL); def_set(u,e,(void *)fr.bot); } return TCL_OK; } static int botfl_expmem (struct user_entry * e) { context; return 0; } static void botfl_display (int idx, struct user_entry * e) { struct flag_record fr = {FR_BOT,0,0,0,0,0}; char x[100]; context; fr.bot = e->u.ulong; build_flags(x,&fr,NULL); dprintf(idx," BOT FLAGS: %s\n", x); } struct user_entry_type USERENTRY_BOTFL = { 0, /* always 0 ;) */ 0, def_dupuser, botfl_unpack, botfl_pack, botfl_write_userfile, botfl_kill, def_get, botfl_set, botfl_tcl_get, botfl_tcl_set, botfl_expmem, botfl_display, "BOTFL" };