#define MODE_AUDITORIUM 0x200000000LLU /**< +u Auditorium */
#define MODE_NOFLOOD 0x400000000LLU /**< +f NoFlood */
#define MODE_SSLCHAN 0x800000000LLU /**< +S SSL Channel */
+#define MODE_BANEXCEPTION 0x1000000000LLU /**< +e Ban exception */
/** mode flags which take another parameter (With PARAmeterS)
*/
-#define MODE_WPARAS (MODE_CHANOP|MODE_HALFOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS|MODE_ALTCHAN|MODE_ACCESS|MODE_NOFLOOD)
+#define MODE_WPARAS (MODE_CHANOP|MODE_HALFOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS|MODE_ALTCHAN|MODE_ACCESS|MODE_NOFLOOD|MODE_BANEXCEPTION)
/** Available Channel modes */
-#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AcCbhiklmMnNopsStuUvrDRzQu" : "cCbhiklmMnNopsStuvrDRzQu"
+#define infochanmodes feature_bool(FEAT_OPLEVELS) ? "AcCbehiklmMnNopsStuUvrDRzQu" : "cCbehiklmMnNopsStuvrDRzQu"
/** Available Channel modes that take parameters */
-#define infochanmodeswithparams feature_bool(FEAT_OPLEVELS) ? "AbfhkloUvFa" : "bfhklovFa"
+#define infochanmodeswithparams feature_bool(FEAT_OPLEVELS) ? "AbefhkloUvFa" : "befhklovFa"
#define HoldChannel(x) (!(x))
/** name invisible */
extern int m_time(struct Client*, struct Client*, int, char*[]);
extern int m_topic(struct Client*, struct Client*, int, char*[]);
extern int m_trace(struct Client*, struct Client*, int, char*[]);
+extern int m_uninvite(struct Client*, struct Client*, int, char*[]);
extern int m_unregistered(struct Client*, struct Client*, int, char*[]);
extern int m_unsupported(struct Client*, struct Client*, int, char*[]);
extern int m_user(struct Client*, struct Client*, int, char*[]);
extern int ms_topic(struct Client*, struct Client*, int, char*[]);
extern int ms_trace(struct Client*, struct Client*, int, char*[]);
extern int ms_unzombie(struct Client*, struct Client*, int, char*[]);
+extern int ms_uninvite(struct Client*, struct Client*, int, char*[]);
extern int ms_uping(struct Client*, struct Client*, int, char*[]);
extern int ms_version(struct Client*, struct Client*, int, char*[]);
extern int ms_wallchops(struct Client*, struct Client*, int, char*[]);
#define TOK_INVITE "I"
#define CMD_INVITE MSG_INVITE, TOK_INVITE
+#define MSG_UNINVITE "UNINVITE" /* INVI */
+#define TOK_UNINVITE "UI"
+#define CMD_UNINVITE MSG_UNINVITE, TOK_UNINVITE
+
#define MSG_VERSION "VERSION" /* VERS */
#define TOK_VERSION "V"
#define CMD_VERSION MSG_VERSION, TOK_VERSION
#define RPL_USERIP 340 /* Undernet extension */
#define RPL_INVITING 341
/* RPL_SUMMONING 342 removed from RFC1459 */
+#define RPL_UNINVITE 343
#define RPL_ISSUEDINVITE 345 /* Undernet extension */
#define RPL_INVITELIST 346 /* IRCnet, Undernet extension */
#define RPL_ENDOFINVITELIST 347 /* IRCnet, Undernet extension */
-/* RPL_EXCEPTLIST 348 IRCnet extension */
-/* RPL_ENDOFEXCEPTLIST 349 IRCnet extension */
+#define RPL_EXCEPTLIST 348 /* IRCnet extension */
+#define RPL_ENDOFEXCEPTLIST 349 /* IRCnet extension */
#define RPL_VERSION 351
#define RPL_WHOREPLY 352 /* See also RPL_ENDOFWHO */
/* ERR_SUMMONDISABLED 445 removed from RFC1459 */
/* ERR_USERSDISABLED 446 removed from RFC1459 */
/* ERR_NONICKCHANGE 447 unreal */
+#define ERR_USERNOTINVITED 448
#define ERR_NOTREGISTERED 451
/* ERR_IDCOLLISION 452 IRCnet extension ? */
#define FEATURESVALUES2 NICKLEN, TOPICLEN, AWAYLEN, TOPICLEN, \
feature_int(FEAT_CHANNELLEN), CHANNELLEN, \
(feature_bool(FEAT_LOCAL_CHANNELS) ? "#&" : "#"), "(ohv)@%+", "@%+", \
- (feature_bool(FEAT_OPLEVELS) ? "b,AkU,alfF,cCimMnNprstuDdRz" : "b,k,alfF,cCimMnNprstuDdRz"), \
+ (feature_bool(FEAT_OPLEVELS) ? "be,AkU,alfF,cCimMnNprstuDdRz" : "be,k,alfF,cCimMnNprstuDdRz"), \
"rfc1459", feature_str(FEAT_NETWORK)
#endif /* INCLUDED_supported_h */
m_topic.c \
m_trace.c \
m_unzombie.c \
+ m_uninvite.c \
m_uping.c \
m_user.c \
m_userhost.c \
assert(0 != chptr);
for (lp = chptr->banlist; lp; lp = lp->next)
- send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr, lp->who, lp->when);
+ if ((lp->flags & BAN_EXCEPTION) != BAN_EXCEPTION)
+ send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr, lp->who, lp->when);
send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
}
+/** send an exception list to a client for a channel
+ *
+ * @param cptr Client to send the banlist to.
+ * @param chptr Channel whose exception list to send.
+ */
+static void send_exception_list(struct Client* cptr, struct Channel* chptr)
+{
+ struct Ban* lp;
+
+ assert(0 != cptr);
+ assert(0 != chptr);
+
+ for (lp = chptr->banlist; lp; lp = lp->next)
+ if ((lp->flags & BAN_EXCEPTION) == BAN_EXCEPTION)
+ send_reply(cptr, RPL_EXCEPTLIST, chptr->chname, lp->banstr, lp->who, lp->when);
+
+ send_reply(cptr, RPL_ENDOFEXCEPTLIST, chptr->chname);
+}
+
/** Get a channel block, creating if necessary.
* Get Channel block for chname (and allocate a new channel
* block, if it didn't exists before).
MODE_QUARANTINE, 'Q',
MODE_AUDITORIUM, 'u',
MODE_SSLCHAN, 'S',
+/* MODE_BANEXCEPTION 'e', */
0x0, 0x0
};
static ulong64 local_flags[] = {
bufptr[(*bufptr_i)++] = 'v';
totalbuflen -= IRCD_MAX(9, tmp) + 1;
}
- } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD)) {
+ } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION)) {
tmp = strlen(MB_STRING(mbuf, i));
if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
else {
char mode_char;
- switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD))
+ switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION))
{
case MODE_APASS:
mode_char = 'A';
case MODE_NOFLOOD:
mode_char = 'f';
break;
+ case MODE_BAN:
+ mode_char = 'b';
+ break;
default:
- mode_char = 'b';
+ mode_char = 'e';
break;
}
bufptr[(*bufptr_i)++] = mode_char;
build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
/* deal with bans... */
- else if (MB_TYPE(mbuf, i) & (MODE_BAN))
+ else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_BANEXCEPTION))
build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
/* deal with keys... */
build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
/* deal with modes that take strings */
- else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD))
+ else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD | MODE_BANEXCEPTION))
build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
/*
MODE_AUDITORIUM, 'u',
MODE_SSLCHAN, 'S',
MODE_NOFLOOD, 'f',
+/* MODE_BANEXCEPTION, 'e', */
0x0, 0x0
};
ulong64 add;
#define DONE_ALTCHAN 0x800 /**< We've set the altchan */
#define DONE_ACCESS 0x1000 /**< We've set the access */
#define DONE_NOFLOOD 0x2000 /**< We've set the noflood options */
+#define DONE_EXCEPTLIST 0x4000 /**< We've sent the exception list */
struct ParseState {
struct ModeBuf *mbuf;
struct Ban *ban, *newban;
if (state->parc <= 0) { /* Not enough args, send ban list */
- if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
- send_ban_list(state->sptr, state->chptr);
- state->done |= DONE_BANLIST;
+ if (MyUser(state->sptr)) {
+ if (*flag_p == MODE_BANEXCEPTION && !(state->done & DONE_EXCEPTLIST)) {
+ send_exception_list(state->sptr, state->chptr);
+ state->done |= DONE_EXCEPTLIST;
+ } else if (*flag_p == MODE_BAN && !(state->done & DONE_BANLIST)) {
+ send_ban_list(state->sptr, state->chptr);
+ state->done |= DONE_BANLIST;
+ }
}
return;
}
if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
if (prevban)
- prevban->next = 0; /* Break the list; ban isn't a real ban */
+ prevban->next = 0; /* Break the list; ban isn't a real ban */
else
- state->chptr->banlist = 0;
+ state->chptr->banlist = 0;
count--;
len -= banlen;
} else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
char *bandup;
DupString(bandup, ban->banstr);
- modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN, bandup, 1);
+ modebuf_mode_string(state->mbuf, MODE_DEL | ((ban->flags & BAN_EXCEPTION) ? MODE_BANEXCEPTION : MODE_BAN), bandup, 1);
if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
- if (prevban) /* clip it out of the list... */
- prevban->next = ban->next;
- else
- state->chptr->banlist = ban->next;
+ if (prevban) /* clip it out of the list... */
+ prevban->next = ban->next;
+ else
+ state->chptr->banlist = ban->next;
- count--;
- len -= banlen;
+ count--;
+ len -= banlen;
free_ban(ban);
- changed++;
- continue; /* next ban; keep prevban like it is */
+ changed++;
+ continue; /* next ban; keep prevban like it is */
} else
- ban->flags &= BAN_IPMASK; /* unset other flags */
+ ban->flags &= (BAN_IPMASK | BAN_EXCEPTION); /* unset other flags */
} else if (ban->flags & BAN_ADD) { /* adding a ban? */
if (prevban)
- prevban->next = 0; /* Break the list; ban isn't a real ban */
+ prevban->next = 0; /* Break the list; ban isn't a real ban */
else
- state->chptr->banlist = 0;
+ state->chptr->banlist = 0;
/* If we're supposed to ignore it, do so. */
- if (ban->flags & BAN_OVERLAPPED &&
- !(state->flags & MODE_PARSE_BOUNCE)) {
- count--;
- len -= banlen;
+ if (ban->flags & BAN_OVERLAPPED && !(state->flags & MODE_PARSE_BOUNCE)) {
+ count--;
+ len -= banlen;
} else {
- if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
- (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
- count > feature_int(FEAT_MAXBANS))) {
- send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
- ban->banstr);
- count--;
- len -= banlen;
- } else {
+ if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
+ (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
+ count > feature_int(FEAT_MAXBANS))) {
+ send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname, ban->banstr);
+ count--;
+ len -= banlen;
+ } else {
char *bandup;
- /* add the ban to the buffer */
+ /* add the ban to the buffer */
DupString(bandup, ban->banstr);
- modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN, bandup, 1);
+ modebuf_mode_string(state->mbuf, MODE_ADD | ((ban->flags & BAN_EXCEPTION) ? MODE_BANEXCEPTION : MODE_BAN), bandup, 1);
- if (state->flags & MODE_PARSE_SET) { /* create a new ban */
- newban = make_ban(ban->banstr);
+ if (state->flags & MODE_PARSE_SET) { /* create a new ban */
+ newban = make_ban(ban->banstr);
strcpy(newban->who, ban->who);
- newban->when = ban->when;
- newban->flags = ban->flags & BAN_IPMASK;
+ newban->when = ban->when;
+ newban->flags = ban->flags & (BAN_IPMASK | BAN_EXCEPTION);
- newban->next = state->chptr->banlist; /* and link it in */
- state->chptr->banlist = newban;
+ newban->next = state->chptr->banlist; /* and link it in */
+ state->chptr->banlist = newban;
- changed++;
- }
- }
+ changed++;
+ }
+ }
}
}
MODE_AUDITORIUM, 'u',
MODE_SSLCHAN, 'S',
MODE_NOFLOOD, 'f',
+ MODE_BANEXCEPTION, 'e',
MODE_ADD, '+',
MODE_DEL, '-',
0x0, 0x0
mode_parse_upass(&state, flag_p);
break;
case 'b': /* deal with bans */
+ case 'e': /* and exceptions */
mode_parse_ban(&state, flag_p);
break;
MODE_NOCOLOUR, 'c',
MODE_NOCTCP, 'C',
MODE_NOAMSGS, 'M',
+ MODE_BANEXCEPTION, 'e',
0x0, 0x0
};
int *flag_p;
}
/* Deal with users on the channel */
- if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_HALFOP | MODE_VOICE))
+ if (del_mode & (MODE_BAN | MODE_BANEXCEPTION | MODE_CHANOP | MODE_HALFOP | MODE_VOICE))
for (member = chptr->members; member; member = member->next_member) {
if (IsZombie(member)) /* we ignore zombies */
continue;
- if (del_mode & MODE_BAN) /* If we cleared bans, clear the valid flags */
+ if (del_mode & (MODE_BAN | MODE_BANEXCEPTION)) /* If we cleared bans, clear the valid flags */
ClearBanValid(member);
/* Drop channel operator status */
mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
struct Channel *chptr;
- char *control = "ovpsmikbl"; /* default control string */
+ char *control = "ovpsmikble"; /* default control string */
const char *chname, *qreason;
int force = 0;
static void loc_handler_LR(const char *num, char *parv[], signed int parc) {
if(num[0] != '!') return;
- if(parc > 0)
- auth_loc_reply(&num[3], NULL, NULL, NULL, 0);
- else
- auth_loc_reply(&num[3], NULL, NULL, &parv[0] , parc);
+ if(parc > 0)
+ auth_loc_reply(&num[3], NULL, NULL, NULL, 0);
+ else
+ auth_loc_reply(&num[3], NULL, NULL, &parv[0] , parc);
}
static void loc_handler_LA(const char *num, char *parv[], signed int parc) {
if(num[0] != '!' || parc < 1) return;
- char *fakehost = NULL;
- if (parc > 1 && strcmp(parv[1], "0") != 0) // 0 = no fakehost
- fakehost=parv[1];
+ char *fakehost = NULL;
+ if (parc > 1 && strcmp(parv[1], "0") != 0) // 0 = no fakehost
+ fakehost=parv[1];
if(parc > 2)
auth_loc_reply(&num[3], parv[0], fakehost, &parv[2] , parc - 2);
struct Channel *chptr;
if (!(chptr = FindChannel(channel))) {
if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
- //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
+ //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
} else if ((chptr = get_channel(cptr, channel, CGT_CREATE))) {
- struct JoinBuf create;
- joinbuf_init(&create, cptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
- joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
- do_names(cptr, chptr, NAMES_ALL|NAMES_EON);
- joinbuf_flush(&create);
- }
- } else {
+ struct JoinBuf create;
+ joinbuf_init(&create, cptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
+ joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+ do_names(cptr, chptr, NAMES_ALL|NAMES_EON);
+ joinbuf_flush(&create);
+ }
+ } else {
struct JoinBuf join;
+ if(find_member_link(chptr, cptr))
+ return; //we have already joined this channel
joinbuf_init(&join, cptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
- joinbuf_join(&join, chptr, flags);
- del_invite(cptr, chptr);
+ joinbuf_join(&join, chptr, flags);
+ del_invite(cptr, chptr);
if (chptr->topic[0]) {
send_reply(cptr, RPL_TOPIC, chptr->chname, chptr->topic);
send_reply(cptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time);
}
do_names(cptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
joinbuf_flush(&join);
- }
+ }
}
static void mode_a_check_altchan(struct Client* sptr, char *channel) {
- struct Channel *chptrb;
- if (!(chptrb = FindChannel(channel))) {
- if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
- //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
- } else if ((chptrb = get_channel(sptr, channel, CGT_CREATE))) {
- struct JoinBuf create;
- joinbuf_init(&create, sptr, sptr, JOINBUF_TYPE_CREATE, 0, TStime());
- joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
- do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
- joinbuf_flush(&create);
- }
- } else {
- if(find_member_link(chptrb, sptr))
- return; //we have already joined this channel
- //first of all check if we may even join this channel
- int err2 = 0;
- int flags = 0;
- if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
- /* Joining a zombie channel (zannel): give ops and increment TS. */
- flags = CHFL_CHANOP;
- chptrb->creationtime++;
- } else if (IsInvited(sptr, chptrb)) {
- /* Invites and key=OVERRIDE bypass these other checks. */
- } else if (chptrb->mode.mode & MODE_INVITEONLY)
- err2 = ERR_INVITEONLYCHAN;
- else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
- err2 = ERR_CHANNELISFULL;
- else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
- err2 = ERR_NEEDREGGEDNICK;
- else if ((chptrb->mode.mode & MODE_SSLCHAN) && !IsSSL(sptr))
- err2 = ERR_SSLCHANNEL;
- else if (find_ban(sptr, chptrb->banlist))
- err2 = ERR_BANNEDFROMCHAN;
- else if (*chptrb->mode.key) //Fix this!
- err2 = ERR_BADCHANNELKEY;
- if(!err2) {
- struct JoinBuf join;
- joinbuf_init(&join, sptr, sptr, JOINBUF_TYPE_JOIN, 0, 0);
- joinbuf_join(&join, chptrb, flags);
- del_invite(sptr, chptrb);
- if (chptrb->topic[0]) {
- send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
- send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
+ struct Channel *chptrb;
+ if (!(chptrb = FindChannel(channel))) {
+ if (((channel[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(channel) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
+ //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
+ } else if ((chptrb = get_channel(sptr, channel, CGT_CREATE))) {
+ struct JoinBuf create;
+ joinbuf_init(&create, sptr, sptr, JOINBUF_TYPE_CREATE, 0, TStime());
+ joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
+ do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
+ joinbuf_flush(&create);
+ }
+ } else {
+ if(find_member_link(chptrb, sptr))
+ return; //we have already joined this channel
+ //first of all check if we may even join this channel
+ int err2 = 0;
+ int flags = 0;
+ if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
+ /* Joining a zombie channel (zannel): give ops and increment TS. */
+ flags = CHFL_CHANOP;
+ chptrb->creationtime++;
+ } else if (IsInvited(sptr, chptrb)) {
+ /* Invites and key=OVERRIDE bypass these other checks. */
+ } else if (chptrb->mode.mode & MODE_INVITEONLY)
+ err2 = ERR_INVITEONLYCHAN;
+ else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
+ err2 = ERR_CHANNELISFULL;
+ else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
+ err2 = ERR_NEEDREGGEDNICK;
+ else if ((chptrb->mode.mode & MODE_SSLCHAN) && !IsSSL(sptr))
+ err2 = ERR_SSLCHANNEL;
+ else if (find_ban(sptr, chptrb->banlist))
+ err2 = ERR_BANNEDFROMCHAN;
+ else if (*chptrb->mode.key) //Fix this!
+ err2 = ERR_BADCHANNELKEY;
+ if(!err2) {
+ struct JoinBuf join;
+ joinbuf_init(&join, sptr, sptr, JOINBUF_TYPE_JOIN, 0, 0);
+ joinbuf_join(&join, chptrb, flags);
+ del_invite(sptr, chptrb);
+ if (chptrb->topic[0]) {
+ send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
+ send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
+ }
+ do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
+ joinbuf_flush(&join);
}
- do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
- joinbuf_flush(&join);
- }
- }
+ }
}
/** RELAY
}
/* Call subcommand handler. */
- if(strcmp("LR", parv[2]) == 0) loc_handler_LR(parv[1], &parv[3], parc - 3);
- else if(strcmp("LA", parv[2]) == 0 && parc > 3) loc_handler_LA(parv[1], &parv[3], parc - 3);
- else if(strcmp("SM", parv[2]) == 0 && parc > 3) {
- #ifndef UNRESTRICTED_SERV
- struct Client *acptr;
- if(acptr = findNUser(parv[3])) {
- if (IsChannelPrefix(*parv[4])) {
- relay_channel_message(acptr, parv[4], parv[parc - 1], 1);
- } else {
- relay_private_message(acptr, parv[4], parv[parc - 1]);
- }
- }
- #endif
- } else if(strcmp("UC", parv[2]) == 0 && parc > 3) {
- struct Client *acptr;
- if(acptr = findNUser(parv[3])) {
- send_reply(acptr, ERR_UNKNOWNCOMMAND, parv[4]);
- }
- } else if(strcmp("SI", parv[2]) == 0 && parc > 3) {
- #ifndef UNRESTRICTED_SERV
- struct Client *acptr;
- if(acptr = findNUser(parv[3])) {
- parse_simul_client(acptr, parv[parc - 1]);
- }
- #endif
- } else if(strcmp("JAA", parv[2]) == 0 && parc > 2) {
- struct Client *acptr;
- if(acptr = findNUser(parv[1])) {
- mode_a_join(acptr,parv[3],strtoul(parv[4], 0, 10));
- }
- } else if(strcmp("JAR", parv[2]) == 0 && parc > 2) {
- struct Client *acptr;
- struct Channel *chptr;
- if(acptr = findNUser(parv[1])) {
- if(IsChannelName(parv[3]) && strIsIrcCh(parv[3]) &&
- (chptr = FindChannel(parv[3])) && chptr->mode.altchan &&
- IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
- mode_a_check_altchan(acptr,chptr->mode.altchan);
- }
- send_reply(acptr, ERR_JOINACCESS, parv[3], feature_str(FEAT_ERR_JOINACCESS));
- }
- }
+ if(strcmp("LR", parv[2]) == 0)
+ loc_handler_LR(parv[1], &parv[3], parc - 3);
+ else if(strcmp("LA", parv[2]) == 0 && parc > 3)
+ loc_handler_LA(parv[1], &parv[3], parc - 3);
+ else if(strcmp("SM", parv[2]) == 0 && parc > 3) {
+#ifndef UNRESTRICTED_SERV
+ struct Client *acptr;
+ if(acptr = findNUser(parv[3])) {
+ if (IsChannelPrefix(*parv[4]))
+ relay_channel_message(acptr, parv[4], parv[parc - 1], 1);
+ else
+ relay_private_message(acptr, parv[4], parv[parc - 1]);
+ }
+#endif
+ } else if(strcmp("UC", parv[2]) == 0 && parc > 3) {
+ struct Client *acptr;
+ if(acptr = findNUser(parv[3]))
+ send_reply(acptr, ERR_UNKNOWNCOMMAND, parv[4]);
+ } else if(strcmp("SI", parv[2]) == 0 && parc > 3) {
+#ifndef UNRESTRICTED_SERV
+ struct Client *acptr;
+ if(acptr = findNUser(parv[3]))
+ parse_simul_client(acptr, parv[parc - 1]);
+#endif
+ } else if(strcmp("JAA", parv[2]) == 0 && parc > 2) {
+ struct Client *acptr;
+ if(acptr = findNUser(parv[1]))
+ mode_a_join(acptr,parv[3],strtoul(parv[4], 0, 10));
+ } else if(strcmp("JAR", parv[2]) == 0 && parc > 2) {
+ struct Client *acptr;
+ struct Channel *chptr;
+ if(acptr = findNUser(parv[1])) {
+ if(IsChannelName(parv[3]) && strIsIrcCh(parv[3]) &&
+ (chptr = FindChannel(parv[3])) && chptr->mode.altchan &&
+ IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan))
+ mode_a_check_altchan(acptr,chptr->mode.altchan);
+ send_reply(acptr, ERR_JOINACCESS, parv[3], feature_str(FEAT_ERR_JOINACCESS));
+ }
+ }
return 0;
}
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, ircd/m_uninvite.c
+ * Written by Philipp Kreil.
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * 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 1, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ * cptr is always NON-NULL, pointing to a *LOCAL* client
+ * structure (with an open socket connected!). This
+ * identifies the physical socket where the message
+ * originated (or which caused the m_function to be
+ * executed--some m_functions may call others...).
+ *
+ * sptr is the source of the message, defined by the
+ * prefix part of the message if present. If not
+ * or prefix not found, then sptr==cptr.
+ *
+ * (!IsServer(cptr)) => (cptr == sptr), because
+ * prefixes are taken *only* from servers...
+ *
+ * (IsServer(cptr))
+ * (sptr == cptr) => the message didn't
+ * have the prefix.
+ *
+ * (sptr != cptr && IsServer(sptr) means
+ * the prefix specified servername. (?)
+ *
+ * (sptr != cptr && !IsServer(sptr) means
+ * that message originated from a remote
+ * user (not local).
+ *
+ * combining
+ *
+ * (!IsServer(sptr)) means that, sptr can safely
+ * taken as defining the target structure of the
+ * message in this server.
+ *
+ * *Always* true (if 'parse' and others are working correct):
+ *
+ * 1) sptr->from == cptr (note: cptr->from == cptr)
+ *
+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ * *cannot* be a local connection, unless it's
+ * actually cptr!). [MyConnect(x) should probably
+ * be defined as (x == x->from) --msa ]
+ *
+ * parc number of variable parameter strings (if zero,
+ * parv is allowed to be NULL)
+ *
+ * parv a NULL terminated list of parameter pointers,
+ *
+ * parv[0], sender (prefix string), if not present
+ * this points to an empty string.
+ * parv[1]...parv[parc-1]
+ * pointers to additional parameters
+ * parv[parc] == NULL, *always*
+ *
+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
+ * non-NULL pointers.
+ */
+#include "config.h"
+
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+/* #include <assert.h> -- Now using assert in ircd_log.h */
+
+/*
+ * m_uninvite - generic message handler
+ *
+ * parv[0] - sender prefix
+ * parv[1] - user to uninvite
+ * parv[2] - channel name
+ *
+ */
+int m_uninvite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+ struct Client *acptr;
+ struct Channel *chptr;
+
+ if (parc < 3 || EmptyString(parv[2]))
+ return need_more_params(sptr, "UNINVITE");
+
+ if (!(acptr = FindUser(parv[1]))) {
+ send_reply(sptr, ERR_NOSUCHNICK, parv[1]);
+ return 0;
+ }
+
+ if (!IsChannelName(parv[2])
+ || !strIsIrcCh(parv[2])
+ || !(chptr = FindChannel(parv[2]))) {
+ send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]);
+ return 0;
+ }
+
+ if (!find_channel_member(sptr, chptr)) {
+ send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+ return 0;
+ }
+
+ if (find_channel_member(acptr, chptr)) {
+ send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname);
+ return 0;
+ }
+
+ if (!is_chan_op(sptr, chptr) && !is_halfop(sptr, chptr)) {
+ send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
+ return 0;
+ }
+
+ if(!IsInvited(acptr, chptr)) {
+ send_reply(sptr, ERR_USERNOTINVITED, cli_name(acptr), chptr->chname);
+ return 0;
+ }
+
+ /* If we get here, it was a VALID and meaningful UNINVITE */
+
+ send_reply(sptr, RPL_UNINVITE, cli_name(acptr), chptr->chname);
+
+ if (MyConnect(acptr)) {
+ del_invite(acptr, chptr);
+ sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H", cli_name(acptr), chptr);
+ } else if (!IsLocalChannel(chptr->chname)) {
+ sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime);
+ }
+
+ return 0;
+}
+
+/*
+ * ms_uninvite - server message handler
+ *
+ * parv[0] - sender prefix
+ * parv[1] - user to invite
+ * parv[2] - channel name
+ * parv[3] - (optional) channel timestamp
+ *
+ */
+int ms_uninvite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+ struct Client *acptr;
+ struct Channel *chptr;
+ time_t uninvite_ts;
+
+ if (IsServer(sptr)) {
+ /*
+ * this will blow up if we get an uninvite from a server
+ * we look for channel membership in sptr below.
+ */
+ return protocol_violation(sptr,"Server attempting to uninvite");
+ }
+ if (parc < 3 || EmptyString(parv[2])) {
+ /*
+ * should have been handled upstream, ignore it.
+ */
+ protocol_violation(sptr,"Too few arguments to uninvite");
+ return need_more_params(sptr,"UNINVITE");
+ }
+ if (!IsGlobalChannel(parv[2])) {
+ /*
+ * should not be sent
+ */
+ return protocol_violation(sptr, "Uninvite from a non-standard channel %s",parv[2]);
+ }
+ if (!(acptr = FindUser(parv[1]))) {
+ send_reply(sptr, ERR_NOSUCHNICK, parv[1]);
+ return 0;
+ }
+
+ if (!(chptr = FindChannel(parv[2]))) {
+ send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]);
+ return 0;
+ }
+
+ if (parc > 3) {
+ uninvite_ts = atoi(parv[3]);
+ if (uninvite_ts > chptr->creationtime)
+ return 0;
+ } else if (IsBurstOrBurstAck(cptr))
+ return 0;
+
+ if (!IsChannelService(sptr) && !find_channel_member(sptr, chptr)) {
+ send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname);
+ return 0;
+ }
+
+ if (find_channel_member(acptr, chptr)) {
+ send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname);
+ return 0;
+ }
+
+ if(!IsInvited(acptr, chptr)) {
+ send_reply(sptr, ERR_USERNOTINVITED, cli_name(acptr), chptr->chname);
+ return 0;
+ }
+
+ if (MyConnect(acptr)) {
+ del_invite(acptr, chptr);
+ sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H", cli_name(acptr), chptr);
+ } else {
+ sendcmdto_one(sptr, CMD_UNINVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr,
+ chptr->creationtime);
+ }
+
+ return 0;
+}
/* UNREG, CLIENT, SERVER, OPER, SERVICE */
{ m_unregistered, m_invite, ms_invite, m_invite, m_ignore }
},
+ {
+ MSG_UNINVITE,
+ TOK_UNINVITE,
+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
+ /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+ { m_unregistered, m_uninvite, ms_uninvite, m_uninvite, m_ignore }
+ },
{
MSG_KICK,
TOK_KICK,
/* 342 */
{ 0 },
/* 343 */
- { 0 },
+ { RPL_UNINVITE, "%s %s", "343" },
/* 344 */
{ 0 },
/* 345 */
/* 347 */
{ RPL_ENDOFINVITELIST, ":End of Invite List", "347" },
/* 348 */
- { 0 },
+ { RPL_EXCEPTLIST, "%s %s %s %Tu", "348" },
/* 349 */
- { 0 },
+ { RPL_ENDOFEXCEPTLIST, "%s :End of Channel Exception List", "349" },
/* 350 */
{ 0 },
/* 351 */
/* 447 */
{ 0 },
/* 448 */
- { 0 },
+ { ERR_USERNOTINVITED, "%s %s :is not invited to channel", "448" },
/* 449 */
{ 0 },
/* 450 */
else {
SetDelayedJoin(chan);
}
+
+ /*
+ * Check if the client is actually overriding a ban with the
+ * mask change, if so, kick him out of the channel.
+ * We have to proceed that way to ensure data consistency (join + kick)
+ */
+ if (find_ban(cptr, chan->channel->banlist)) {
+ /* Silentely kick in case of delayed join */
+ if (chan->channel->mode.mode & MODE_DELJOINS) {
+ sendcmdto_one(&his, CMD_KICK, cptr, "%H %C :Ban override", chan->channel, cptr);
+ CheckDelayedJoins(chan->channel);
+
+ } else {
+ /* Otherwise publicly kick */
+ sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Ban override", chan->channel, cptr);
+ sendcmdto_channel_butserv_butone(&his, CMD_KICK, chan->channel, NULL, 0, "%H %C :Ban override", chan->channel, cptr);
+ make_zombie(chan, cptr, &me, &me, chan->channel);
+ }
+ }
}
return 0;
}