#define CMD_PROTO "PROTO"
#define CMD_QUIT "QUIT"
#define CMD_REHASH "REHASH"
+#define CMD_REMOVE "REMOVE"
#define CMD_RESET "RESET"
#define CMD_RESTART "RESTART"
#define CMD_RPING "RPING"
#define CMD_RPONG "RPONG"
+#define CMD_SASL "SASL"
#define CMD_SERVER "SERVER"
#define CMD_SERVLIST "SERVLIST"
#define CMD_SERVSET "SERVSET"
#define CMD_SVSPART "SVSPART"
#define CMD_SVSQUIT "SVSQUIT"
#define CMD_SWHOIS "SWHOIS"
+#define CMD_TEMPSHUN "TEMPSHUN"
#define CMD_TIME "TIME"
#define CMD_TOPIC "TOPIC"
#define CMD_TRACE "TRACE"
#define CMD_WHO "WHO"
#define CMD_WHOIS "WHOIS"
#define CMD_WHOWAS "WHOWAS"
+#define CMD_ZLINE "ZLINE"
/* Tokenized commands. */
#define TOK_ACCOUNT "AC"
#define TOK_PROTO "PROTO"
#define TOK_QUIT "Q"
#define TOK_REHASH "REHASH"
+#define TOK_REMOVE "RM"
#define TOK_RESET "RESET"
#define TOK_RESTART "RESTART"
#define TOK_RPING "RI"
#define TOK_RPONG "RO"
+#define TOK_SASL "SASL"
#define TOK_SERVER "S"
#define TOK_SERVLIST "SERVSET"
#define TOK_SERVSET "SERVSET"
#define TOK_SVSPART "SP"
#define TOK_SVSQUIT "SX"
#define TOK_SWHOIS "SW"
+#define TOK_TEMPSHUN "TS"
#define TOK_TIME "TI"
#define TOK_TOPIC "T"
#define TOK_TRACE "TR"
#define TOK_WHO "H"
#define TOK_WHOIS "W"
#define TOK_WHOWAS "X"
+#define TOK_ZLINE "ZL"
/* Protocol messages; aliased to full commands or tokens depending
on compile-time configuration. ircu prefers tokens WITH THE
#define P10_PROTO TYPE(PROTO)
#define P10_QUIT TYPE(QUIT)
#define P10_REHASH TYPE(REHASH)
+#define P10_REMOVE TYPE(REMOVE)
#define P10_RESET TYPE(RESET)
#define P10_RESTART TYPE(RESTART)
#define P10_RPING TYPE(RPING)
#define P10_RPONG TYPE(RPONG)
+#define P10_SASL TYPE(SASL)
#define P10_SERVER CMD_SERVER
#define P10_SERVLIST TYPE(SERVLIST)
#define P10_SERVSET TYPE(SERVSET)
#define P10_SVSPART TYPE(SVSPART)
#define P10_SVSQUIT TYPE(SVSQUIT)
#define P10_SWHOIS TYPE(SWHOIS)
+#define P10_TEMPSHUN TYPE(TEMPSHUN)
#define P10_TIME TYPE(TIME)
#define P10_TOPIC TYPE(TOPIC)
#define P10_TRACE TYPE(TRACE)
#define P10_WHO TYPE(WHO)
#define P10_WHOIS TYPE(WHOIS)
#define P10_WHOWAS TYPE(WHOWAS)
+#define P10_ZLINE TYPE(ZLINE)
#define P10_EXEMPT TYPE(EXEMPT)
/* Servers claiming to have a boot or link time before PREHISTORY
static const char *his_servercomment;
static int extended_accounts;
-/* These correspond to 1 << X: 012345678901234567 */
-const char irc_user_mode_chars[] = "o iw dkgn I";
+/* These correspond to 1 << X: 01234567890123456789012345 */
+const char irc_user_mode_chars[] = "oOiw dkgh x BnIX azDRWHLq";
static struct userNode *AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip);
inttobase64(extranum, srv->num_mask, (srv->numeric[1] || (srv->num_mask >= 64*64)) ? 3 : 2);
if (srv == self) {
- putsock(P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " J10 %s%s +s6 :%s",
+ putsock(P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " J10 %s%s +s6o :%s",
srv->name, srv->hops+1, srv->boot, srv->link_time, srv->numeric, extranum, srv->description);
} else {
- putsock("%s " P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " %c10 %s%s +s6 :%s",
+ putsock("%s " P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " %c10 %s%s +s6o :%s",
self->numeric, srv->name, srv->hops+1, srv->boot, srv->link_time, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
}
}
do {
if (*input == '_') {
unsigned int left;
- for (left = (25 - strlen(input)) / 3; left; left--)
+ for (left = (25 - strlen(input)) / 3 - pos; left; left--)
ip->in6[pos++] = 0;
input++;
} else {
void
irc_shun(struct server *srv, struct shun *shun)
{
- putsock("%s " P10_SHUN " %s +%s " FMT_TIME_T " :<%s> %s",
- self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, shun->issuer, shun->reason);
+ putsock("%s " P10_SHUN " %s +%s " FMT_TIME_T " " FMT_TIME_T " :<%s> %s",
+ self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, now, shun->issuer, shun->reason);
}
void
void
irc_ungline(const char *mask)
{
- putsock("%s " P10_GLINE " * -%s", self->numeric, mask);
+ putsock("%s " P10_GLINE " * -%s " FMT_TIME_T, self->numeric, mask, now);
}
void
irc_unshun(const char *mask)
{
- putsock("%s " P10_SHUN " * -%s", self->numeric, mask);
+ putsock("%s " P10_SHUN " * -%s " FMT_TIME_T, self->numeric, mask, now);
}
void
if ((n+1)<chan->members.used)
burst_line[pos++] = ',';
}
+
+ if (len > 0 && (chan->banlist.used > 0 || chan->exemptlist.used > 0))
+ burst_line[pos++] = ' ';
+
if (chan->banlist.used) {
/* dump the bans */
first_ban = 1;
}
}
}
+
if (chan->exemptlist.used) {
/* dump the exempts */
first_exempt = 1;
for (n=0; n<chan->exemptlist.used; ) {
if (first_exempt && (pos < 500)) {
- burst_line[pos++] = ' ';
+ if (chan->banlist.used < 1) {
+ burst_line[pos++] = ':';
+ burst_line[pos++] = '%';
+ burst_line[pos++] = ' ';
+ }
burst_line[pos++] = '~';
burst_line[pos++] = ' ';
}
}
void
-irc_svsquit(struct userNode *from, struct userNode *who, char *reason)
+irc_svsquit(struct userNode *from, struct userNode *who, char const *reason)
{
putsock("%s " P10_SVSQUIT " %s :%s", from->uplink->numeric, who->numeric, reason);
}
}
+void
+irc_tempshun(struct userNode *from, struct userNode *target, int remove, const char *reason)
+{
+ putsock("%s " P10_TEMPSHUN " %s %s :%s", from->numeric, (remove ? "-" : "+"), target->numeric, reason);
+}
+
void
irc_part(struct userNode *who, struct chanNode *what, const char *reason)
{
irc_topic(struct userNode *service, struct userNode *who, struct chanNode *what, const char *topic)
{
- int type = 4, host_in_topic = 0, hasident = 0;
- const char *hstr, *tstr;
+ int type = 4, host_in_topic = 0, hasident = 0, hhtype = 0;
+ const char *hstr, *tstr, *hhstr, *htstr;
char *host, *hostmask;
char shost[MAXLEN];
char sident[MAXLEN];
tstr = conf_get_data("server/type", RECDB_QSTRING);
hstr = conf_get_data("server/host_in_topic", RECDB_QSTRING);
+ hhstr = conf_get_data("server/hidden_host", RECDB_QSTRING);
+ htstr = conf_get_data("server/hidden_host_type", RECDB_QSTRING);
if(tstr)
type = atoi(tstr);
else
type = 4;/* default to 040 style topics */
+ if (htstr)
+ hhtype = atoi(htstr);
if (hstr) {
- if (IsFakeHost(who))
+ if (IsHiddenHost(who) && IsFakeHost(who))
safestrncpy(shost, who->fakehost, sizeof(shost));
- else if (IsSetHost(who)) {
+ else if (IsHiddenHost(who) && IsSetHost(who)) {
hostmask = strdup(who->sethost);
if ((host = (strrchr(hostmask, '@')))) {
hasident = 1;
safestrncpy(sident, who->ident, sizeof(shost));
safestrncpy(shost, host, sizeof(shost));
+ } else if (IsHiddenHost(who) && ((hhtype == 1) || (hhtype == 3)) && who->handle_info && hhstr) {
+ snprintf(shost, sizeof(shost), "%s.%s", who->handle_info->handle, hhstr);
+ } else if (IsHiddenHost(who) && ((hhtype == 2) || (hhtype == 3)) && who->crypthost[0]) {
+ safestrncpy(shost, who->crypthost, sizeof(shost));
} else
safestrncpy(shost, who->hostname, sizeof(shost));
irc_mark(struct userNode *user, char *mark)
{
char *host = user->hostname;
+ int type = 4;
+ const char *tstr = NULL;
+ unsigned int ii = 0;
+ int markfound = 0;
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+ else
+ type = 4;
+
+ if (user->marks)
+ for (ii=0; ii<user->marks->used; ii++)
+ if (!irccasecmp(user->marks->list[ii], mark))
+ markfound = 1;
+
+ if (!markfound)
+ {
+ if (!user->marks)
+ user->marks = alloc_string_list(1);
+ string_list_append(user->marks, strdup(mark));
+ }
+
+ if (type >= 9)
+ {
+ putsock("%s " CMD_MARK " %s MARK %s", self->numeric, user->nick, mark);
+ return;
+ }
/* TODO: Allow mark overwrite. If they are marked, and their fakehost is oldmark.hostname, update it to newmark.hostname so mark can be called multiple times. Probably requires ircd modification also */
if(user->mark)
putsock("%s " CMD_SNO " %d :%s", self->numeric, mask, buffer);
}
+void
+irc_sasl(struct server* dest, const char *identifier, const char *subcmd, const char *data)
+{
+ putsock("%s " P10_SASL " %s %s %s %s", self->numeric, dest->numeric, identifier, subcmd, data);
+}
+
static void send_burst(void);
static void
else
irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
- if (IsService(who) || (from == who)) {
+ if (!IsService(who) || (from == who)) {
struct modeNode *mn;
mlen = strlen(self->name) + strlen(from->nick) + 12 + strlen(who->nick);
len = 0;
{
struct server *sender;
dict_iterator_t it;
- unsigned int ii;
if (!(sender = GetServerH(origin)))
return 0;
}
sender->self_burst = 0;
recalc_bursts(sender);
- for (ii=0; ii<slf_used; ii++)
- slf_list[ii](sender);
+ call_server_link_funcs(sender);
/* let auto-routing figure out if we were
* wating on this server to link a child to it */
/* DONT call this if uplink is _US_ */
return 1;
}
+static CMD_FUNC(cmd_sasl)
+{
+ struct server *serv;
+
+ if (argc < 5)
+ return 0;
+
+ serv = GetServerH(origin);
+ if (!serv)
+ return 0;
+
+ call_sasl_input_func(serv, argv[2], argv[3], argv[4], (argc>5 ? argv[argc-1] : NULL));
+
+ return 1;
+}
+
static CMD_FUNC(cmd_ping)
{
struct server *srv;
if(!strcmp(argv[2],"C"))
{
- if((hi = loc_auth(argv[4], argv[5], NULL)))
+ if((hi = loc_auth(NULL, argv[4], argv[5], NULL)))
{
/* Return a AC A */
putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered);
}
else if(!strcmp(argv[2],"H")) /* New enhanced (host) version of C */
{
- if((hi = loc_auth(argv[5], argv[6], argv[4] )))
+ if((hi = loc_auth(NULL, argv[5], argv[6], argv[4] )))
+ {
+ /* Return a AC A */
+ putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered);
+ }
+ else
+ {
+ /* Return a AC D */
+ putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]);
+ }
+ return 1;
+ }
+ else if(!strcmp(argv[2],"S"))
+ {
+ if((hi = loc_auth(argv[5], argv[6], argv[7], argv[4])))
{
/* Return a AC A */
putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered);
P(SHUN), P(LOCAL_SHUN), P(WIDE_SHUN), P(ZLINE),
P(LOCAL_ZLINE), P(WIDE_ZLINE), P(LIST_CHAN), P(WHOIS_NOTICE),
P(HIDE_IDLE), P(XTRAOP), P(HIDE_CHANNELS), P(DISPLAY_MODE),
- P(FREEFORM), P(REMOVE), P(SPAMFILTER),
+ P(FREEFORM), P(REMOVE), P(SPAMFILTER), P(ADMIN),
+ P(APASS_OPMODE), P(HIDE_OPER), P(REMOTE), P(SERVICE),
#undef P
{ 0, 0 }
};
putsock("%s " P10_PRIVS " %s %s%s", self->numeric, target->numeric, (add == PRIV_ADD) ? "+" : "-", flag);
}
+void
+irc_raw_privs(struct userNode *target, const char *privs)
+{
+ putsock("%s " P10_PRIVS " %s %s", self->numeric, target->numeric, privs);
+}
+
static CMD_FUNC(cmd_privs)
{
char *tstr = NULL;
for (tmp = x3_strtok(&p, argv[i], ","); tmp;
tmp = x3_strtok(&p, NULL, ",")) {
if (!strcmp(tmp, "PRIV_NONE")) {
- clear_privs(user);
+ if (now > user->timestamp+5)
+ clear_privs(user);
break;
} else
client_modify_priv_by_name(user, tmp, what);
struct modeNode *mNode;
long mode;
int oplevel = -1;
+ int type = 0;
char *user, *end, sep;
+ char *tstr;
time_t in_timestamp;
char* parm = NULL;
return 0;
modes[0] = 0;
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr) {
+ type = atoi(tstr);
+ }
+
exemptlist[0] = 0;
banlist[0] = 0;
int n_modes;
for (pos=argv[next], n_modes = 1; *pos; pos++)
if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A')
- || (*pos == 'U'))
+ || (*pos == 'U') || ((type > 7) && (*pos == 'L')))
n_modes++;
if (next + n_modes > argc)
n_modes = argc - next;
break;
}
case '%': {
+ ctype = 1;
for(parm = mysep(&argv[next], " "); /* parm = first param */
parm; /* While param is not null */
parm = mysep(&argv[next], " ") /* parm = next param */
)
{
- switch (parm[0]) {
- case '%': {
- ctype = 1;
- break;
- }
- case '~': {
- ctype = 2;
- break;
- }
- default: {
- break;
- }
- }
+ if (0 == strcmp("~", parm))
+ ctype = 2;
if (ctype == 1) {
if (bcheck == 0) {
/* strip % char off start of very first ban */
*/
static CMD_FUNC(cmd_mark)
{
+ const char *tstr;
+ int type = 4;
struct userNode *target;
/*
* log_module(MAIN_LOG, LOG_ERROR, "DEBUG: mark, user %s, type %s, arg %s", argv[1], argv[2], argv[3]);
*/
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+ else
+ type = 4;/* default to 040 style topics */
+
if(argc < 4)
return 0;
if(!strcasecmp(argv[2], "DNSBL")) {
/* DNSBL <modes> */
return 1;
}
- else if(!strcasecmp(argv[2], "DNSBL_DATA")) {
+ else if(!strcasecmp(argv[2], "DNSBL_DATA") || !strcasecmp(argv[2], "MARK")) {
+ int markfound = 0;
+ unsigned int ii = 0;
/* DNSBL_DATA name */
target = GetUserH(argv[1]);
if(!target) {
log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose dnsbl mark is changing.", argv[1]);
return 0;
}
- target->mark = strdup(argv[3]);
+ if (type >= 9) {
+ if (target->marks)
+ for (ii=0; ii<target->marks->used; ii++)
+ if (!irccasecmp(target->marks->list[ii], argv[3]))
+ markfound = 1;
+ if (!markfound)
+ {
+ if (!target->marks)
+ target->marks = alloc_string_list(1);
+ string_list_append(target->marks, strdup(argv[3]));
+ }
+ } else
+ target->mark = strdup(argv[3]);
return 1;
}
else if(!strcasecmp(argv[2], "CVERSION")) {
- /* DNSBL_DATA name */
+ /* CTCP VERSION mark */
target = GetUserH(argv[1]);
if(!target) {
log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose version mark is changing.", argv[1]);
return 1;
}
+ else if(!strcasecmp(argv[2], "SSLCLIFP")) {
+ /* SSL fingerprint mark */
+ target = GetUserH(argv[1]);
+ if(!target) {
+ log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose SSL fingerprint mark is changing.", argv[1]);
+ return 0;
+ }
+
+ char *sslfp = unsplit_string(argv + 3, argc - 3, NULL);
+ if(!sslfp)
+ sslfp = "";
+
+ target->sslfp = strdup(sslfp);
+
+ return 1;
+ }
/* unknown type of mark */
return 1;
}
* Ghost response to a KILL we sent out earlier. So we only
* whine if the target is local.
*/
- if (!strncmp(argv[1], self->numeric, strlen(self->numeric)))
+ if (!strncmp(argv[1], self->numeric, strlen(self->numeric))) {
log_module(MAIN_LOG, LOG_ERROR, "Unable to find kill victim %s", argv[1]);
- return 0;
+ return 0;
+ }
+ return 1;
}
if (IsLocal(user) && IsService(user)) {
if (argc < 2)
return 0;
- user = GetUserN(argv[1]);
+ if (strncmp(argv[1], "*", 2) == 0)
+ {
+ if (!(user = GetUserH(origin))) {
+ log_module(MAIN_LOG, LOG_ERROR, "Could not find SILENCE origin user %s", origin);
+ return 0;
+ }
+ }
+ else
+ user = GetUserN(argv[1]);
/* Sanity, go nuts if this happens */
if (!user)
}
static void
-parse_cleanup(void)
+parse_cleanup(UNUSED_ARG(void *extra))
{
unsigned int nn;
free(of_list);
+ free(of_list_extra);
free(privmsg_funcs);
num_privmsg_funcs = 0;
free(notice_funcs);
}
static void
-remove_unbursted_channel(struct chanNode *cNode) {
+remove_unbursted_channel(struct chanNode *cNode, UNUSED_ARG(void *extra)) {
if (unbursted_channels)
dict_remove(unbursted_channels, cNode->name);
}
dict_insert(irc_func_dict, TOK_SVSPART, cmd_svspart);
dict_insert(irc_func_dict, CMD_SWHOIS, cmd_dummy);
dict_insert(irc_func_dict, TOK_SWHOIS, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_TEMPSHUN, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_TEMPSHUN, cmd_dummy);
dict_insert(irc_func_dict, CMD_WHOIS, cmd_whois);
dict_insert(irc_func_dict, TOK_WHOIS, cmd_whois);
dict_insert(irc_func_dict, CMD_GLINE, cmd_gline);
dict_insert(irc_func_dict, CMD_RPONG, cmd_dummy);
dict_insert(irc_func_dict, TOK_RPONG, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_SASL, cmd_sasl);
+ dict_insert(irc_func_dict, TOK_SASL, cmd_sasl);
+
/* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
* Apparently to obliterate channels from any servers that think they
* exist?
/* We have reliable clock! Always! Wraaa! */
dict_insert(irc_func_dict, CMD_SETTIME, cmd_dummy);
dict_insert(irc_func_dict, TOK_SETTIME, cmd_dummy);
+ /* Ignore ZLINE/ZL/REMOVE/RM */
+ dict_insert(irc_func_dict, CMD_ZLINE, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_ZLINE, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_REMOVE, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_REMOVE, cmd_dummy);
/* ignore /trace and /motd commands targetted at us */
dict_insert(irc_func_dict, TOK_TRACE, cmd_dummy);
memset(notice_funcs, 0, sizeof(privmsg_func_t)*num_notice_funcs);
userList_init(&dead_users);
- reg_del_channel_func(remove_unbursted_channel);
- reg_exit_func(parse_cleanup);
+ reg_del_channel_func(remove_unbursted_channel, NULL);
+ reg_exit_func(parse_cleanup, NULL);
// reg_notice_func(opserv, check_ctcp);
}
if (!hostname)
hostname = self->name;
make_numeric(self, local_num, numeric);
- return AddUser(self, nick, ident, hostname, modes, numeric, desc, now, "AAAAAA");
+ return AddUser(self, nick, ident, hostname, modes, numeric, desc, timestamp, "AAAAAA");
}
struct userNode *
AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip)
{
struct userNode *oldUser, *uNode;
- unsigned int n, ignore_user, dummy;
+ unsigned int ignore_user, dummy;
char *tstr;
int type;
tstr = conf_get_data("server/type", RECDB_QSTRING);
type = atoi(tstr);
- if (type > 6) {
+ if (type == 7) {
if (irc_in_addr_is_ipv4(uNode->ip)) {
make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
}
if (IsLocal(uNode))
irc_user(uNode);
- for (n=0; (n<nuf_used) && !uNode->dead; n++)
- nuf_list[n](uNode);
+ call_new_user_funcs(uNode);
if ((uNode->loc == 1) && (uNode->handle_info))
send_func_list(uNode);
void
DelUser(struct userNode* user, struct userNode *killer, int announce, const char *why)
{
- unsigned int n;
verify(user);
/* Call these in reverse order so ChanServ can update presence
information before NickServ nukes the handle_info. */
- for (n = duf_used; n > 0; )
- duf_list[--n](user, killer, why);
+ call_del_user_funcs(user, killer, why);
user->uplink->clients--;
user->uplink->users[user->num_local] = NULL;
- if (IsOper(user))
+ if (IsOper(user)) {
userList_remove(&curr_opers, user);
+ if (count_opers > 0 && !IsBotM(user) && !IsService(user) && !IsHideOper(user))
+ count_opers--;
+ }
/* remove from global dictionary, but not if after a collide */
if (user == dict_find(clients, user->nick, NULL))
dict_remove(clients, user->nick);
user->version_reply = NULL;
}
+ /* Clean up SSL fingerprint data */
+ if(user->sslfp) {
+ free(user->sslfp);
+ user->sslfp = NULL;
+ }
+
/* clean up mark */
if(user->mark) {
free(user->mark);
user->mark = NULL;
}
+ free_string_list(user->marks);
+ user->marks = NULL;
/* clean up geoip data if any */
if(user->country_code) free(user->country_code);
void mod_usermode(struct userNode *user, const char *mode_change) {
int add = 1;
+ long setmodes = 0;
+ int donemodes = 0;
const char *word = mode_change;
if (!user || !mode_change)
call_user_mode_funcs(user, mode_change);
+ setmodes = user->modes;
+
while (*word != ' ' && *word) word++;
while (*word == ' ') word++;
- while (1) {
+ while (!donemodes) {
#define do_user_mode(FLAG) do { if (add) user->modes |= FLAG; else user->modes &= ~FLAG; } while (0)
switch (*mode_change++) {
- case 0: case ' ': return;
+ case 0: case ' ':
+ donemodes = 1;
+ break;
case '+': add = 1; break;
case '-': add = 0; break;
case 'o':
case 'g': do_user_mode(FLAGS_GLOBAL); break;
case 'B': do_user_mode(FLAGS_BOT); break;
case 'n': do_user_mode(FLAGS_HIDECHANS); break;
+ case 'p': do_user_mode(FLAGS_HIDECHANS); break;
case 'I': do_user_mode(FLAGS_HIDEIDLE); break;
case 'X': do_user_mode(FLAGS_XTRAOP); break;
case 'C': do_user_mode(FLAGS_CLOAKHOST);
assign_fakehost(user, host, 0);
}
break;
+ case 'a': do_user_mode(FLAGS_ADMIN); break;
+ case 'z': do_user_mode(FLAGS_SSL); break;
+ case 'D': do_user_mode(FLAGS_PRIVDEAF); break;
+ case 'R': do_user_mode(FLAGS_ACCOUNTONLY); break;
+ case 'W': do_user_mode(FLAGS_WHOIS); break;
+ case 'H': do_user_mode(FLAGS_HIDEOPER); break;
+ case 'L': do_user_mode(FLAGS_NOLINK); break;
+ case 'q': do_user_mode(FLAGS_COMMONCHANSONLY); break;
}
#undef do_user_mode
}
+
+ // Set user mode +o
+ if (!(setmodes & FLAGS_OPER) && IsOper(user)) {
+ if (!IsBotM(user) && !IsService(user) && !IsHideOper(user))
+ count_opers++;
+ }
+
+ // Set user mode -o
+ if ((setmodes & FLAGS_OPER) && !IsOper(user)) {
+ if (count_opers > 1 && !(setmodes & FLAGS_BOT) &&
+ !(setmodes & FLAGS_SERVICE) && !(setmodes & FLAGS_HIDEOPER))
+ count_opers--;
+ }
+
+ // Set +H, +k or +B
+ if (!(setmodes & FLAGS_HIDEOPER) &&
+ !(setmodes & FLAGS_SERVICE) &&
+ !(setmodes & FLAGS_BOT) &&
+ (IsHideOper(user) || IsService(user) || IsBotM(user))) {
+ if ((setmodes & FLAGS_OPER) && IsOper(user) && count_opers > 0)
+ count_opers--;
+ }
+
+ // Set -H, -k or -B
+ if (((setmodes & FLAGS_HIDEOPER) ||
+ (setmodes & FLAGS_SERVICE) ||
+ (setmodes & FLAGS_BOT)) &&
+ !IsHideOper(user) && !IsService(user) && !IsBotM(user)) {
+ if ((setmodes & FLAGS_OPER) && IsOper(user))
+ count_opers++;
+ }
}
static int
case 'A':
if (add) {
if ((in_arg >= argc)
- || keyncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass)))
+ || keyncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass)))
+ goto error;
change->modes_set |= MODE_APASS;
} else {
change->modes_clear |= MODE_APASS;
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
-#undef DO_MODE_CHAR
- switch (change->modes_set & (MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS)) {
- /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */
- case MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "lkAU %d %s %s %s", change->new_limit, change->new_key,change->new_apass, change->new_upass);
- break;
-
- case MODE_KEY|MODE_LIMIT|MODE_APASS:
- used += sprintf(outbuff+used, "lkA %d %s %s", change->new_limit, change->new_key, change->new_apass);
- break;
- case MODE_KEY|MODE_LIMIT|MODE_UPASS:
- used += sprintf(outbuff+used, "lkU %d %s %s", change->new_limit, change->new_key, change->new_upass);
- break;
- case MODE_KEY|MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "kAU %s %s %s", change->new_key, change->new_apass, change->new_upass);
- break;
-
- case MODE_KEY|MODE_APASS:
- used += sprintf(outbuff+used, "kA %s %s", change->new_key, change->new_apass);
- break;
- case MODE_KEY|MODE_UPASS:
- used += sprintf(outbuff+used, "kU %s %s", change->new_key, change->new_upass);
- break;
- case MODE_KEY|MODE_LIMIT:
- used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
- break;
-
- case MODE_LIMIT|MODE_UPASS:
- used += sprintf(outbuff+used, "lU %d %s", change->new_limit, change->new_upass);
- break;
- case MODE_LIMIT|MODE_APASS:
- used += sprintf(outbuff+used, "lA %d %s", change->new_limit, change->new_apass);
- break;
- case MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "AU %s %s", change->new_apass, change->new_upass);
- case MODE_LIMIT|MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "lAU %d %s %s", change->new_limit, change->new_apass, change->new_upass);
- break;
+ DO_MODE_CHAR(KEY, 'k');
+ DO_MODE_CHAR(LIMIT, 'l');
+ DO_MODE_CHAR(APASS, 'A');
+ DO_MODE_CHAR(UPASS, 'U');
+#undef DO_MODE_CHAR
- case MODE_APASS:
- used += sprintf(outbuff+used, "A %s", change->new_apass);
- break;
- case MODE_UPASS:
- used += sprintf(outbuff+used, "U %s", change->new_upass);
- break;
- case MODE_KEY:
- used += sprintf(outbuff+used, "k %s", change->new_key);
- break;
- case MODE_LIMIT:
- used += sprintf(outbuff+used, "l %d", change->new_limit);
- break;
- }
+#define DO_MODE_PARM(BIT, PARM) if (change->modes_set & MODE_##BIT) used += sprintf(outbuff+used, " %s", PARM);
+ DO_MODE_PARM(KEY, change->new_key);
+ if (change->modes_set & MODE_LIMIT) used += sprintf(outbuff+used, " %d", change->new_limit);
+ DO_MODE_PARM(APASS, change->new_apass);
+ DO_MODE_PARM(UPASS, change->new_upass);
+#undef DO_MODE_PARM
}
outbuff[used] = 0;
return outbuff;