* 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.
- *
- * $Id$
+ */
+/** @file
+ * @brief Miscellaneous user-related helper functions.
+ * @version $Id$
*/
#include "config.h"
#include "hash.h"
#include "ircd.h"
#include "ircd_alloc.h"
+#include "ircd_auth.h"
#include "ircd_chattr.h"
#include "ircd_features.h"
#include "ircd_log.h"
#include "s_serv.h" /* max_client_count */
#include "send.h"
#include "struct.h"
-#include "support.h"
#include "supported.h"
#include "sys.h"
#include "userload.h"
#include "handlers.h" /* m_motd and m_lusers */
-#include <assert.h>
+/* #include <assert.h> -- Now using assert in ircd_log.h */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
-
+/** Count of allocated User structures. */
static int userCount = 0;
-/*
- * 'make_user' add's an User information block to a client
- * if it was not previously allocated.
+/** Makes sure that \a cptr has a User information block.
+ * If cli_user(cptr) != NULL, does nothing.
+ * @param[in] cptr Client to attach User struct to.
+ * @return User struct associated with \a cptr.
*/
struct User *make_user(struct Client *cptr)
{
return cli_user(cptr);
}
-/*
- * free_user
- *
- * Decrease user reference count by one and release block, if count reaches 0.
+/** Dereference \a user.
+ * User structures are reference-counted; if the refcount of \a user
+ * becomes zero, free it.
+ * @param[in] user User to dereference.
*/
void free_user(struct User* user)
{
}
}
+/** Find number of User structs allocated and memory used by them.
+ * @param[out] count_out Receives number of User structs allocated.
+ * @param[out] bytes_out Receives number of bytes used by User structs.
+ */
void user_count_memory(size_t* count_out, size_t* bytes_out)
{
assert(0 != count_out);
}
-/*
- * next_client
- *
- * Local function to find the next matching client. The search
- * can be continued from the specified client entry. Normal
- * usage loop is:
- *
+/** Find the next client (starting at \a next) with a name that matches \a ch.
+ * Normal usage loop is:
* for (x = client; x = next_client(x,mask); x = x->next)
* HandleMatchingClient;
*
+ * @param[in] next First client to check.
+ * @param[in] ch Name mask to check against.
+ * @return Next matching client found, or NULL if none.
*/
struct Client *next_client(struct Client *next, const char* ch)
{
return next;
}
-/*
- * hunt_server
- *
- * Do the basic thing in delivering the message (command)
- * across the relays to the specific server (server) for
- * actions.
+/** Find the destination server for a command, and forward it if that is not us.
*
- * Note: The command is a format string and *MUST* be
- * of prefixed style (e.g. ":%s COMMAND %s ...").
- * Command can have only max 8 parameters.
+ * \a server may be a nickname, server name, server mask (if \a from
+ * is a local user) or server numnick (if \a is a server or remote
+ * user).
*
- * server parv[server] is the parameter identifying the
- * target server. It can be a nickname, servername,
- * or server mask (from a local user) or a server
- * numeric (from a remote server).
- *
- * *WARNING*
- * parv[server] is replaced with the pointer to the
- * real servername from the matched client (I'm lazy
- * now --msa).
- *
- * returns: (see #defines)
+ * @param[in] from Client that sent the command to us.
+ * @param[in] cmd Long-form command text.
+ * @param[in] tok Token-form command text.
+ * @param[in] one Client that originated the command (ignored).
+ * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
+ * @param[in] pattern Format string of arguments to command.
+ * @param[in] server Index of target name or mask in \a parv.
+ * @param[in] parc Number of valid elements in \a parv (must be less than 9).
+ * @param[in] parv Array of arguments to command.
+ * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
*/
int hunt_server_cmd(struct Client *from, const char *cmd, const char *tok,
struct Client *one, int MustBeOper, const char *pattern,
send_reply(from, ERR_NOSUCHSERVER, to);
return (HUNTED_NOSUCH);
}
- } else if (!(acptr = FindNServer(to)))
+ } else if (!(acptr = FindNServer(to))) {
+ send_reply(from, SND_EXPLICIT | ERR_NOSUCHSERVER, "* :Server has disconnected");
return (HUNTED_NOSUCH); /* Server broke off in the meantime */
+ }
if (IsMe(acptr))
return (HUNTED_ISME);
return (HUNTED_PASS);
}
+/** Find the destination server for a command, and forward it (as a
+ * high-priority command) if that is not us.
+ *
+ * \a server may be a nickname, server name, server mask (if \a from
+ * is a local user) or server numnick (if \a is a server or remote
+ * user).
+ * Unlike hunt_server_cmd(), this appends the message to the
+ * high-priority message queue for the destination server.
+ *
+ * @param[in] from Client that sent the command to us.
+ * @param[in] cmd Long-form command text.
+ * @param[in] tok Token-form command text.
+ * @param[in] one Client that originated the command (ignored).
+ * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
+ * @param[in] pattern Format string of arguments to command.
+ * @param[in] server Index of target name or mask in \a parv.
+ * @param[in] parc Number of valid elements in \a parv (must be less than 9).
+ * @param[in] parv Array of arguments to command.
+ * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
+ */
int hunt_server_prio_cmd(struct Client *from, const char *cmd, const char *tok,
struct Client *one, int MustBeOper,
const char *pattern, int server, int parc,
}
-/*
- * clean_user_id
- *
- * Copy `source' to `dest', replacing all occurances of '~' and characters that
- * are not `isIrcUi' by an underscore.
- * Copies at most USERLEN - 1 characters or up till the first control character.
- * If `tilde' is true, then a tilde is prepended to `dest'.
- * Note that `dest' and `source' can point to the same area or to different
- * non-overlapping areas.
+/** Copy a cleaned-up version of a username.
+ * Replace all instances of '~' and "invalid" username characters
+ * (!isIrcUi()) with underscores, truncating at USERLEN or the first
+ * control character. \a dest and \a source may be the same buffer.
+ * @param[out] dest Destination buffer.
+ * @param[in] source Source buffer.
+ * @param[in] tilde If non-zero, prepend a '~' to \a dest.
*/
static char *clean_user_id(char *dest, char *source, int tilde)
{
* this is not fair. It should actually request another
* nick from local user or kill him/her...
*/
+/** Finish registering a user who has sent both NICK and USER.
+ * For local connections, possibly check IAuth; make sure there is a
+ * matching Client config block; clean the username field; check
+ * K/k-lines; check for "hacked" looking usernames; assign a numnick;
+ * and send greeting (WELCOME, ISUPPORT, MOTD, etc).
+ * For all connections, update the invisible user and operator counts;
+ * run IPcheck against their address; and forward the NICK.
+ *
+ * @param[in] cptr Client who introduced the user.
+ * @param[in,out] sptr Client who has been fully introduced.
+ * @param[in] nick Client's new nickname.
+ * @param[in] username Client's username.
+ * @return Zero or CPTR_KILLED.
+ */
int register_user(struct Client *cptr, struct Client *sptr,
const char *nick, char *username)
{
short digitgroups = 0;
struct User* user = cli_user(sptr);
int killreason;
- char ip_base64[8];
+ char ip_base64[25];
user->last = CurrentTime;
parv[0] = cli_name(sptr);
static time_t last_too_many2;
assert(cptr == sptr);
+ assert(cli_unreg(sptr) == 0);
+ if (!IsIAuthed(sptr)) {
+ if (iauth_active)
+ return iauth_start_client(iauth_active, sptr);
+ else
+ SetIAuthed(sptr);
+ }
switch (conf_check_client(sptr))
{
case ACR_OK:
get_client_name(sptr, SHOW_IP));
}
++ServerStats->is_ref;
- IPcheck_connect_fail(cli_ip(sptr));
+ IPcheck_connect_fail(&cli_ip(sptr));
return exit_client(cptr, sptr, &me,
"Sorry, your connection class is full - try "
"again later or try another server");
/* Can this ever happen? */
case ACR_BAD_SOCKET:
++ServerStats->is_ref;
- IPcheck_connect_fail(cli_ip(sptr));
+ IPcheck_connect_fail(&cli_ip(sptr));
return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
}
ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
if (feature_bool(FEAT_CONNEXIT_NOTICES))
sendto_opmask_butone(0, SNO_CONNEXIT,
- "Client connecting: %s (%s@%s) [%s] {%d} [%s] <%s%s>",
+ "Client connecting: %s (%s@%s) [%s] {%s} [%s] <%s%s>",
cli_name(sptr), user->username, user->host,
cli_sock_ip(sptr), get_client_class(sptr),
cli_info(sptr), NumNick(cptr) /* two %s's */);
}
}
tmpstr = umode_str(sptr);
- sendcmdto_serv_butone(user->server, CMD_NICK, cptr,
- "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
- nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
- user->username, user->realhost,
- *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
- inttobase64(ip_base64, ntohl(cli_ip(sptr).s_addr), 6),
- NumNick(sptr), cli_info(sptr));
-
+ /* Send full IP address to IPv6-grokking servers. */
+ sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
+ FLAG_IPV6, FLAG_LAST_FLAG,
+ "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
+ nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
+ user->username, user->realhost,
+ *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
+ iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
+ NumNick(sptr), cli_info(sptr));
+ /* Send fake IPv6 addresses to pre-IPv6 servers. */
+ sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
+ FLAG_LAST_FLAG, FLAG_IPV6,
+ "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
+ nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
+ user->username, user->realhost,
+ *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
+ iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
+ NumNick(sptr), cli_info(sptr));
+
/* Send server notice mask to client */
if (MyUser(sptr) && (cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
return 0;
}
-
+/** List of user mode characters. */
static const struct UserMode {
- unsigned int flag;
- char c;
+ unsigned int flag; /**< User mode constant. */
+ char c; /**< Character corresponding to the mode. */
} userModeList[] = {
{ FLAG_OPER, 'o' },
{ FLAG_LOCOP, 'O' },
{ FLAG_HIDDENHOST, 'x' }
};
+/** Length of #userModeList. */
#define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode)
/*
* XXX - find a way to get rid of this
*/
+/** Nasty global buffer used for communications with umode_str() and others. */
static char umodeBuf[BUFSIZE];
+/** Try to set a user's nickname.
+ * If \a sptr is a server, the client is being introduced for the first time.
+ * @param[in] cptr Client to set nickname.
+ * @param[in] sptr Client sending the NICK.
+ * @param[in] nick New nickname.
+ * @param[in] parc Number of arguments to NICK.
+ * @param[in] parv Argument list to NICK.
+ * @return CPTR_KILLED if \a cptr was killed, else 0.
+ */
int set_nick_name(struct Client* cptr, struct Client* sptr,
const char* nick, int parc, char* parv[])
{
/*
* IP# of remote client
*/
- cli_ip(new_client).s_addr = htonl(base64toint(parv[parc - 3]));
+ base64toip(parv[parc - 3], &cli_ip(new_client));
add_client_to_list(new_client);
hAddClient(new_client);
}
hAddClient(sptr);
+ cli_unreg(sptr) &= ~CLIREG_NICK; /* nickname now set */
+
/*
* If the client hasn't gotten a cookie-ping yet,
* choose a cookie and send it. -record!jegelhof@cloud9.net
} while (!cli_cookie(sptr));
sendrawto_one(cptr, MSG_PING " :%u", cli_cookie(sptr));
}
- else if (*(cli_user(sptr))->host && cli_cookie(sptr) == COOKIE_VERIFIED) {
+ else if (!cli_unreg(sptr)) {
/*
* USER and PONG already received, now we have NICK.
* register_user may reject the client and call exit_client
return 0;
}
+/** Calculate the hash value for a target.
+ * @param[in] target Pointer to target, cast to unsigned int.
+ * @return Hash value constructed from the pointer.
+ */
static unsigned char hash_target(unsigned int target)
{
return (unsigned char) (target >> 16) ^ (target >> 8);
}
-/*
- * add_target
- *
- * sptr must be a local client!
- *
- * Cannonifies target for client `sptr'.
+/** Records \a target as a recent target for \a sptr.
+ * @param[in] sptr User who has sent to a new target.
+ * @param[in] target Target to add.
*/
void
add_target(struct Client *sptr, void *target)
targets[RESERVEDTARGETS] = hash;
}
-/*
- * check_target_limit
- *
- * sptr must be a local client !
- *
- * Returns 'true' (1) when too many targets are addressed.
- * Returns 'false' (0) when it's ok to send to this target.
+/** Check whether \a sptr can send to or join \a target yet.
+ * @param[in] sptr User trying to join a channel or send a message.
+ * @param[in] target Target of the join or message.
+ * @param[in] name Name of the target.
+ * @param[in] created If non-zero, trying to join a new channel.
+ * @return Non-zero if too many target changes; zero if okay to send.
*/
int check_target_limit(struct Client *sptr, void *target, const char *name,
int created)
return 0;
}
-/*
- * whisper - called from m_cnotice and m_cprivmsg.
- *
- * parv[0] = sender prefix
- * parv[1] = nick
- * parv[2] = #channel
- * parv[3] = Private message text
- *
- * Added 971023 by Run.
- * Reason: Allows channel operators to sent an arbitrary number of private
- * messages to users on their channel, avoiding the max.targets limit.
- * Building this into m_private would use too much cpu because we'd have
- * to a cross channel lookup for every private message!
- * Note that we can't allow non-chan ops to use this command, it would be
- * abused by mass advertisers.
- *
+/** Allows a channel operator to avoid target change checks when
+ * sending messages to users on their channel.
+ * @param[in] source User sending the message.
+ * @param[in] nick Destination of the message.
+ * @param[in] channel Name of channel being sent to.
+ * @param[in] text Message to send.
+ * @param[in] is_notice If non-zero, use CNOTICE instead of CPRIVMSG.
*/
+/* Added 971023 by Run. */
int whisper(struct Client* source, const char* nick, const char* channel,
const char* text, int is_notice)
{
}
-/*
- * added Sat Jul 25 07:30:42 EST 1992
+/** Send a user mode change for \a cptr to neighboring servers.
+ * @param[in] cptr User whose mode is changing.
+ * @param[in] sptr Client who sent us the mode change message.
+ * @param[in] old Prior set of user flags.
+ * @param[in] prop If non-zero, also include FLAG_OPER.
*/
void send_umode_out(struct Client *cptr, struct Client *sptr,
struct Flags *old, int prop)
}
-/*
- * send_user_info - send user info userip/userhost
- * NOTE: formatter must put info into buffer and return a pointer to the end of
- * the data it put in the buffer.
+/** Call \a fmt for each Client named in \a names.
+ * @param[in] sptr Client requesting information.
+ * @param[in] names Space-delimited list of nicknames.
+ * @param[in] rpl Base reply string for messages.
+ * @param[in] fmt Formatting callback function.
*/
void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt)
{
msgq_clean(mb);
}
-/*
- * hide_hostmask()
- *
- * If, after setting the flags, the user has both HiddenHost and Account
- * set, its hostmask is changed.
+/** Set \a flag on \a cptr and possibly hide the client's hostmask.
+ * @param[in,out] cptr User who is getting a new flag.
+ * @param[in] flag Some flag that affects host-hiding (FLAG_HIDDENHOST, FLAG_ACCOUNT).
+ * @return Zero.
*/
int
hide_hostmask(struct Client *cptr, unsigned int flag)
{
struct Membership *chan;
- if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING) &&
- flag == FLAG_HIDDENHOST)
+ switch (flag) {
+ case FLAG_HIDDENHOST:
+ /* Local users cannot set +x unless FEAT_HOST_HIDING is true. */
+ if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING))
+ return 0;
+ break;
+ case FLAG_ACCOUNT:
+ /* Invalidate all bans against the user so we check them again */
+ for (chan = (cli_user(cptr))->channel; chan;
+ chan = chan->next_channel)
+ ClearBanValid(chan);
+ break;
+ default:
return 0;
-
-/* Invalidate all bans against the user so we check them again */
- for (chan = (cli_user(cptr))->channel; chan;
- chan = chan->next_channel)
- ClearBanValid(chan);
+ }
SetFlag(cptr, flag);
if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT))
{
if (IsZombie(chan))
continue;
- /* For a user with no modes in a join-delayed channel, do not show
- * the rejoin. */
- if (!IsChanOp(chan) && !HasVoice(chan)
- && (chan->channel->mode.mode & MODE_DELJOINS))
- SetDelayedJoin(chan);
- else
+ /* Send a JOIN unless the user's join has been delayed. */
+ if (!IsDelayedJoin(chan))
sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
"%H", chan->channel);
if (IsChanOp(chan) && HasVoice(chan))
return 0;
}
-/*
- * set_user_mode() added 15/10/91 By Darren Reed.
+/** Set a user's mode. This function checks that \a cptr is trying to
+ * set his own mode, prevents local users from setting inappropriate
+ * modes through this function, and applies any other side effects of
+ * a successful mode change.
*
- * parv[0] - sender
- * parv[1] - username to change mode for
- * parv[2] - modes to change
+ * @param[in,out] cptr User setting someone's mode.
+ * @param[in] sptr Client who sent the mode change message.
+ * @param[in] parc Number of parameters in \a parv.
+ * @param[in] parv Parameters to MODE.
+ * @return Zero.
*/
int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
return 0;
}
-/*
- * Build umode string for BURST command
- * --Run
+/** Build a mode string to describe modes for \a cptr.
+ * @param[in] cptr Some user.
+ * @return Pointer to a static buffer.
*/
char *umode_str(struct Client *cptr)
{
overwritten by send_umode() */
}
-/*
- * Send the MODE string for user (user) to connection cptr
- * -avalon
+/** Send a mode change string for \a sptr to \a cptr.
+ * @param[in] cptr Destination of mode change message.
+ * @param[in] sptr User whose mode has changed.
+ * @param[in] old Pre-change set of modes for \a sptr.
+ * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
+ * SEND_UMODES, to select which changed user modes to send.
*/
void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
int sendset)
sendcmdto_one(sptr, CMD_MODE, cptr, "%s :%s", cli_name(sptr), umodeBuf);
}
-/*
+/**
* Check to see if this resembles a sno_mask. It is if 1) there is
* at least one digit and 2) The first digit occurs before the first
* alphabetic character.
+ * @param[in] word Word to check for sno_mask-ness.
+ * @return Non-zero if \a word looks like a server notice mask; zero if not.
*/
int is_snomask(char *word)
{
return 0;
}
-/*
- * If it begins with a +, count this as an additive mask instead of just
- * a replacement. If what == MODE_DEL, "+" has no special effect.
+/** Update snomask \a oldmask according to \a arg and \a what.
+ * @param[in] oldmask Original user mask.
+ * @param[in] arg Update string (either a number or '+'/'-' followed by a number).
+ * @param[in] what MODE_ADD if adding the mask.
+ * @return New value of service notice mask.
*/
unsigned int umode_make_snomask(unsigned int oldmask, char *arg, int what)
{
return newmask;
}
+/** Remove \a cptr from the singly linked list \a list.
+ * @param[in] cptr Client to remove from list.
+ * @param[in,out] list Pointer to head of list containing \a cptr.
+ */
static void delfrom_list(struct Client *cptr, struct SLink **list)
{
struct SLink* tmp;
}
}
-/*
- * This function sets a Client's server notices mask, according to
- * the parameter 'what'. This could be even faster, but the code
- * gets mighty hard to read :)
+/** Set \a cptr's server notice mask, according to \a what.
+ * @param[in,out] cptr Client whose snomask is updating.
+ * @param[in] newmask Base value for new snomask.
+ * @param[in] what One of SNO_ADD, SNO_DEL, SNO_SET, to choose operation.
*/
void set_snomask(struct Client *cptr, unsigned int newmask, int what)
{
cli_snomask(cptr) = newmask;
}
-/*
- * is_silenced : Does the actual check wether sptr is allowed
- * to send a message to acptr.
- * Both must be registered persons.
- * If sptr is silenced by acptr, his message should not be propagated,
- * but more over, if this is detected on a server not local to sptr
- * the SILENCE mask is sent upstream.
+/** Check whether \a sptr is allowed to send a message to \a acptr.
+ * If \a sptr is a remote user, it means some server has an outdated
+ * SILENCE list for \a acptr, so send the missing SILENCE mask(s) back
+ * in the direction of \a sptr. Skip the check if \a sptr is a server.
+ * @param[in] sptr Client trying to send a message.
+ * @param[in] acptr Destination of message.
+ * @return Non-zero if \a sptr is SILENCEd by \a acptr, zero if not.
*/
int is_silenced(struct Client *sptr, struct Client *acptr)
{
- struct SLink *lp;
+ struct Ban *found;
struct User *user;
- static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
- static char senderip[16 + NICKLEN + USERLEN + 5];
- static char senderh[HOSTLEN + ACCOUNTLEN + USERLEN + 6];
+ size_t buf_used, slen;
+ char buf[BUFSIZE];
- if (!cli_user(acptr) || !(lp = cli_user(acptr)->silence) || !(user = cli_user(sptr)))
+ if (IsServer(sptr) || !(user = cli_user(acptr))
+ || !(found = find_ban(sptr, user->silence)))
return 0;
- ircd_snprintf(0, sender, sizeof(sender), "%s!%s@%s", cli_name(sptr),
- user->username, user->host);
- ircd_snprintf(0, senderip, sizeof(senderip), "%s!%s@%s", cli_name(sptr),
- user->username, ircd_ntoa((const char*) &(cli_ip(sptr))));
- if (HasHiddenHost(sptr))
- ircd_snprintf(0, senderh, sizeof(senderh), "%s!%s@%s", cli_name(sptr),
- user->username, user->realhost);
- for (; lp; lp = lp->next)
- {
- if ((!(lp->flags & CHFL_SILENCE_IPMASK) && (!match(lp->value.cp, sender) ||
- (HasHiddenHost(sptr) && !match(lp->value.cp, senderh)))) ||
- ((lp->flags & CHFL_SILENCE_IPMASK) && !match(lp->value.cp, senderip)))
- {
- if (!MyConnect(sptr))
- {
- sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr,
- lp->value.cp);
+ assert(!(found->flags & BAN_EXCEPTION));
+ if (!MyConnect(sptr)) {
+ /* Buffer positive silence to send back. */
+ buf_used = strlen(found->banstr);
+ memcpy(buf, found->banstr, buf_used);
+ /* Add exceptions to buffer. */
+ for (found = user->silence; found; found = found->next) {
+ if (!(found->flags & BAN_EXCEPTION))
+ continue;
+ slen = strlen(found->banstr);
+ if (buf_used + slen + 4 > 400) {
+ buf[buf_used] = '\0';
+ sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
+ buf_used = 0;
}
- return 1;
+ if (buf_used)
+ buf[buf_used++] = ',';
+ buf[buf_used++] = '+';
+ buf[buf_used++] = '~';
+ memcpy(buf + buf_used, found->banstr, slen);
+ buf_used += slen;
}
- }
- return 0;
-}
-
-/*
- * del_silence
- *
- * Removes all silence masks from the list of sptr that fall within `mask'
- * Returns -1 if none where found, 0 otherwise.
- */
-int del_silence(struct Client *sptr, char *mask)
-{
- struct SLink **lp;
- struct SLink *tmp;
- int ret = -1;
-
- for (lp = &(cli_user(sptr))->silence; *lp;) {
- if (!mmatch(mask, (*lp)->value.cp))
- {
- tmp = *lp;
- *lp = tmp->next;
- MyFree(tmp->value.cp);
- free_link(tmp);
- ret = 0;
- }
- else
- lp = &(*lp)->next;
- }
- return ret;
-}
-
-int add_silence(struct Client* sptr, const char* mask)
-{
- struct SLink *lp, **lpp;
- int cnt = 0, len = strlen(mask);
- char *ip_start;
-
- for (lpp = &(cli_user(sptr))->silence, lp = *lpp; lp;)
- {
- if (0 == ircd_strcmp(mask, lp->value.cp))
- return -1;
- if (!mmatch(mask, lp->value.cp))
- {
- struct SLink *tmp = lp;
- *lpp = lp = lp->next;
- MyFree(tmp->value.cp);
- free_link(tmp);
- continue;
+ /* Flush silence buffer. */
+ if (buf_used) {
+ buf[buf_used] = '\0';
+ sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
+ buf_used = 0;
}
- if (MyUser(sptr))
- {
- len += strlen(lp->value.cp);
- if ((len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXSILES))) ||
- (++cnt >= feature_int(FEAT_MAXSILES)))
- {
- send_reply(sptr, ERR_SILELISTFULL, mask);
- return -1;
- }
- else if (!mmatch(lp->value.cp, mask))
- return -1;
- }
- lpp = &lp->next;
- lp = *lpp;
}
- lp = make_link();
- memset(lp, 0, sizeof(struct SLink));
- lp->next = cli_user(sptr)->silence;
- lp->value.cp = (char*) MyMalloc(strlen(mask) + 1);
- assert(0 != lp->value.cp);
- strcpy(lp->value.cp, mask);
- if ((ip_start = strrchr(mask, '@')) && check_if_ipmask(ip_start + 1))
- lp->flags = CHFL_SILENCE_IPMASK;
- cli_user(sptr)->silence = lp;
- return 0;
+ return 1;
}
+/** Send RPL_ISUPPORT lines to \a cptr.
+ * @param[in] cptr Client to send ISUPPORT to.
+ * @return Zero.
+ */
int
send_supported(struct Client *cptr)
{