Beispiel #1
0
/**
 * Check if a client is listed in a list and store the reason.
 *
 * @param h      List head.
 * @param Client Client to check.
 * @param reason Buffer to store the reason.
 * @param len    Size of the buffer if reason should be saved.
 * @return true if client is listed, false if not.
 */
bool
Lists_CheckReason(struct list_head *h, CLIENT *Client, char *reason, size_t len)
{
	struct list_elem *e, *last, *next;

	assert(h != NULL);

	e = h->first;
	last = NULL;

	while (e) {
		next = e->next;
		if (MatchCaseInsensitive(e->mask, Client_MaskCloaked(Client))) {
			if (len && e->reason)
				strlcpy(reason, e->reason, len);
			if (e->onlyonce) {
				/* Entry is valid only once, delete it */
				LogDebug("Deleted \"%s\" from list (used).",
					 e->mask);
				Lists_Unlink(h, last, e);
			}
			return true;
		}
		last = e;
		e = next;
	}

	return false;
}
Beispiel #2
0
/**
 * Handler for the IRC command "INVITE".
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_INVITE(CLIENT *Client, REQUEST *Req)
{
	CHANNEL *chan;
	CLIENT *target, *from;
	const char *colon_if_necessary;
	bool remember = false;

	assert( Client != NULL );
	assert( Req != NULL );

	_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)

	/* Search user */
	target = Client_Search(Req->argv[0]);
	if (!target || (Client_Type(target) != CLIENT_USER))
		return IRC_WriteErrClient(from, ERR_NOSUCHNICK_MSG,
					  Client_ID(Client), Req->argv[0]);

	chan = Channel_Search(Req->argv[1]);
	if (chan) {
		/* Channel exists. Is the user a valid member of the channel? */
		if (!Channel_IsMemberOf(chan, from))
			return IRC_WriteErrClient(from, ERR_NOTONCHANNEL_MSG,
						  Client_ID(Client),
						  Req->argv[1]);

		/* Is the channel "invite-disallow"? */
		if (Channel_HasMode(chan, 'V'))
			return IRC_WriteErrClient(from, ERR_NOINVITE_MSG,
						  Client_ID(from),
						  Channel_Name(chan));

		/* Is the channel "invite-only"? */
		if (Channel_HasMode(chan, 'i')) {
			/* Yes. The user issuing the INVITE command must be
			 * channel owner/admin/operator/halfop! */
			if (!Channel_UserHasMode(chan, from, 'q') &&
			    !Channel_UserHasMode(chan, from, 'a') &&
			    !Channel_UserHasMode(chan, from, 'o') &&
			    !Channel_UserHasMode(chan, from, 'h'))
				return IRC_WriteErrClient(from,
							  ERR_CHANOPRIVSNEEDED_MSG,
							  Client_ID(from),
							  Channel_Name(chan));
			remember = true;
		}

		/* Is the target user already member of the channel? */
		if (Channel_IsMemberOf(chan, target))
			return IRC_WriteErrClient(from, ERR_USERONCHANNEL_MSG,
						  Client_ID(from),
						  Req->argv[0], Req->argv[1]);

		/* If the target user is banned on that channel: remember invite */
		if (Lists_Check(Channel_GetListBans(chan), target))
			remember = true;

		if (remember) {
			/* We must remember this invite */
			if (!Channel_AddInvite(chan, Client_MaskCloaked(target),
						true))
				return CONNECTED;
		}
	}

	LogDebug("User \"%s\" invites \"%s\" to \"%s\" ...", Client_Mask(from),
		 Req->argv[0], Req->argv[1]);

	/*
	 * RFC 2812 states:
	 * 'There is no requirement that the channel [..] must exist or be a
	 * valid channel'. The problem with this is that this allows the
	 * "channel" to contain spaces, in which case we must prefix its name
	 * with a colon to make it clear that it is only a single argument.
	 */
	colon_if_necessary = strchr(Req->argv[1], ' ') ? ":":"";
	/* Inform target client */
	IRC_WriteStrClientPrefix(target, from, "INVITE %s %s%s", Req->argv[0],
				  colon_if_necessary, Req->argv[1]);

	if (Client_Conn(target) > NONE) {
		/* The target user is local, so we have to send the status code */
		if (!IRC_WriteStrClientPrefix(from, target, RPL_INVITING_MSG,
					       Client_ID(from), Req->argv[0],
					       colon_if_necessary, Req->argv[1]))
			return DISCONNECTED;

		if (Client_HasMode(target, 'a') &&
			!IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from),
					Client_ID(target), Client_Away(target)))
				return DISCONNECTED;
	}
	return CONNECTED;
} /* IRC_INVITE */