예제 #1
0
파일: client.c 프로젝트: kazcw/pande
/**
 * Introduce a new user or service client in the network.
 *
 * @param From Remote server introducing the client or NULL (local).
 * @param Client New client.
 * @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
 */
GLOBAL void
Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
{
	/* Set client type (user or service) */
	Client_SetType(Client, Type);

	if (From) {
		if (Conf_NickIsService(Conf_GetServer(Client_Conn(From)),
				   Client_ID(Client)))
			Client_SetType(Client, CLIENT_SERVICE);
		LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
			 Client_TypeText(Client), Client_Mask(Client),
			 Client_Modes(Client), Client_ID(From),
			 Client_ID(Client_Introducer(Client)),
			 Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
	} else {
		Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
		    Client_TypeText(Client), Client_Mask(Client),
		    Client_Conn(Client));
		Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
			         Client_ID(Client), Client_User(Client),
				 Client_Hostname(Client),
				 Conn_IPA(Client_Conn(Client)),
				 Client_TypeText(Client));
	}

	/* Inform other servers */
	IRC_WriteStrServersPrefixFlag_CB(From,
				From != NULL ? From : Client_ThisServer(),
				'\0', cb_introduceClient, (void *)Client);
} /* Client_Introduce */
예제 #2
0
파일: irc.c 프로젝트: mguindin/ngircd
static bool
Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors)
{
	CLIENT *cl, *from;
	CL2CHAN *cl2chan;
	CHANNEL *chan;
	char *currentTarget = Req->argv[0];
	char *lastCurrentTarget = NULL;

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

	if (Req->argc == 0) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG,
					  Client_ID(Client), Req->command);
	}
	if (Req->argc == 1) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG,
					  Client_ID(Client));
	}
	if (Req->argc > 2) {
		if (!SendErrors)
			return CONNECTED;
		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
					  Client_ID(Client), Req->command);
	}

	if (Client_Type(Client) == CLIENT_SERVER)
		from = Client_Search(Req->prefix);
	else
		from = Client;
	if (!from)
		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
					  Client_ID(Client), Req->prefix);

	/* handle msgtarget = msgto *("," msgto) */
	currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget);
	ngt_UpperStr(Req->command);

	while (currentTarget) {
		/* Check for and handle valid <msgto> of form:
		 * RFC 2812 2.3.1:
		 *   msgto =  channel / ( user [ "%" host ] "@" servername )
		 *   msgto =/ ( user "%" host ) / targetmask
		 *   msgto =/ nickname / ( nickname "!" user "@" host )
		 */
		if (strchr(currentTarget, '!') == NULL)
			/* nickname */
			cl = Client_Search(currentTarget);
		else
			cl = NULL;

		if (cl == NULL) {
			/* If currentTarget isn't a nickname check for:
			 * user ["%" host] "@" servername
			 * user "%" host
			 * nickname "!" user "@" host
			 */
			char target[COMMAND_LEN];
			char * nick = NULL;
			char * user = NULL;
			char * host = NULL;
			char * server = NULL;

			strlcpy(target, currentTarget, COMMAND_LEN);
			server = strchr(target, '@');
			if (server) {
				*server = '\0';
				server++;
			}
			host = strchr(target, '%');
			if (host) {
				*host = '\0';
				host++;
			}
			user = strchr(target, '!');
			if (user) {
				/* msgto form: nick!user@host */
				*user = '******';
				user++;
				nick = target;
				host = server; /* not "@server" but "@host" */
			} else {
				user = target;
			}

			for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
				if (Client_Type(cl) != CLIENT_USER &&
				    Client_Type(cl) != CLIENT_SERVICE)
					continue;
				if (nick != NULL && host != NULL) {
					if (strcasecmp(nick, Client_ID(cl)) == 0 &&
					    strcasecmp(user, Client_User(cl)) == 0 &&
					    strcasecmp(host, Client_HostnameCloaked(cl)) == 0)
						break;
					else
						continue;
				}
				if (strcasecmp(user, Client_User(cl)) != 0)
					continue;
				if (host != NULL && strcasecmp(host,
						Client_HostnameCloaked(cl)) != 0)
					continue;
				if (server != NULL && strcasecmp(server,
						Client_ID(Client_Introducer(cl))) != 0)
					continue;
				break;
			}
		}

		if (cl) {
			/* Target is a user, enforce type */
#ifndef STRICT_RFC
			if (Client_Type(cl) != ForceType &&
			    !(ForceType == CLIENT_USER &&
			      (Client_Type(cl) == CLIENT_USER ||
			       Client_Type(cl) == CLIENT_SERVICE))) {
#else
			if (Client_Type(cl) != ForceType) {
#endif
				if (SendErrors && !IRC_WriteStrClient(
				    from, ERR_NOSUCHNICK_MSG,Client_ID(from),
				    currentTarget))
					return DISCONNECTED;
				goto send_next_target;
			}

#ifndef STRICT_RFC
			if (ForceType == CLIENT_SERVICE &&
			    (Conn_Options(Client_Conn(Client_NextHop(cl)))
			     & CONN_RFC1459)) {
				/* SQUERY command but RFC 1459 link: convert
				 * request to PRIVMSG command */
				Req->command = "PRIVMSG";
			}
#endif

			if (Client_HasMode(cl, 'C')) {
				cl2chan = Channel_FirstChannelOf(cl);
				while (cl2chan) {
					chan = Channel_GetChannel(cl2chan);
					if (Channel_IsMemberOf(chan, from))
						break;
					cl2chan = Channel_NextChannelOf(cl, cl2chan);
				}
				if (!cl2chan) {
					if (SendErrors && !IRC_WriteStrClient(
					    from, ERR_NOTONSAMECHANNEL_MSG,
					    Client_ID(from), Client_ID(cl)))
						return DISCONNECTED;
					goto send_next_target;
				}
			}

			if (SendErrors && (Client_Type(Client) != CLIENT_SERVER)
			    && strchr(Client_Modes(cl), 'a')) {
				/* Target is away */
				if (!IRC_WriteStrClient(from, RPL_AWAY_MSG,
							Client_ID(from),
							Client_ID(cl),
							Client_Away(cl)))
					return DISCONNECTED;
			}
			if (Client_Conn(from) > NONE) {
				Conn_UpdateIdle(Client_Conn(from));
			}
			if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						      Req->command, Client_ID(cl),
						      Req->argv[1]))
				return DISCONNECTED;
		} else if (ForceType != CLIENT_SERVICE
			   && (chan = Channel_Search(currentTarget))) {
			if (!Channel_Write(chan, from, Client, Req->command,
					   SendErrors, Req->argv[1]))
					return DISCONNECTED;
		} else if (ForceType != CLIENT_SERVICE
			/* $#: server/target mask, RFC 2812, sec. 3.3.1 */
			   && strchr("$#", currentTarget[0])
			   && strchr(currentTarget, '.')) {
			/* targetmask */
			if (!Send_Message_Mask(from, Req->command, currentTarget,
					       Req->argv[1], SendErrors))
				return DISCONNECTED;
		} else {
			if (!SendErrors)
				return CONNECTED;
			if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG,
						Client_ID(from), currentTarget))
				return DISCONNECTED;
		}

	send_next_target:
		currentTarget = strtok_r(NULL, ",", &lastCurrentTarget);
		if (currentTarget)
			Conn_SetPenalty(Client_Conn(Client), 1);
	}

	return CONNECTED;
} /* Send_Message */


static bool
Send_Message_Mask(CLIENT * from, char * command, char * targetMask,
		  char * message, bool SendErrors)
{
	CLIENT *cl;
	bool client_match;
	char *mask = targetMask + 1;
	const char *check_wildcards;

	cl = NULL;

	if (strchr(Client_Modes(from), 'o') == NULL) {
		if (!SendErrors)
			return true;
		return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG,
					  Client_ID(from));
	}

	/*
	 * RFC 2812, sec. 3.3.1 requires that targetMask have at least one
	 * dot (".") and no wildcards ("*", "?") following the last one.
	 */
	check_wildcards = strrchr(targetMask, '.');
	assert(check_wildcards != NULL);
	if (check_wildcards &&
		check_wildcards[strcspn(check_wildcards, "*?")])
	{
		if (!SendErrors)
			return true;
		return IRC_WriteStrClient(from, ERR_WILDTOPLEVEL, targetMask);
	}

	/* #: hostmask, see RFC 2812, sec. 3.3.1 */
	if (targetMask[0] == '#') {
		for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
			if (Client_Type(cl) != CLIENT_USER)
				continue;
			client_match = MatchCaseInsensitive(mask, Client_Hostname(cl));
			if (client_match)
				if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						command, Client_ID(cl), message))
					return false;
		}
	} else {
		assert(targetMask[0] == '$'); /* $: server mask, see RFC 2812, sec. 3.3.1 */
		for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) {
			if (Client_Type(cl) != CLIENT_USER)
				continue;
			client_match = MatchCaseInsensitive(mask,
					Client_ID(Client_Introducer(cl)));
			if (client_match)
				if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s",
						command, Client_ID(cl), message))
					return false;
		}
	}
	return CONNECTED;
} /* Send_Message_Mask */
예제 #3
0
파일: irc.c 프로젝트: mguindin/ngircd
GLOBAL bool
IRC_TRACE( CLIENT *Client, REQUEST *Req )
{
	CLIENT *from, *target, *c;
	CONN_ID idx, idx2;
	char user[CLIENT_USER_LEN];

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

	/* Bad number of arguments? */
	if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );

	/* Search sender */
	if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
	else from = Client;
	if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );

	/* Search target */
	if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
	else target = Client_ThisServer( );
	
	/* Forward command to other server? */
	if( target != Client_ThisServer( ))
	{
		if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );

		/* Send RPL_TRACELINK back to initiator */
		idx = Client_Conn( Client ); assert( idx > NONE );
		idx2 = Client_Conn( Client_NextHop( target )); assert( idx2 > NONE );
		if( ! IRC_WriteStrClient( from, RPL_TRACELINK_MSG, Client_ID( from ), PACKAGE_NAME, PACKAGE_VERSION, Client_ID( target ), Client_ID( Client_NextHop( target )), Option_String( idx2 ), time( NULL ) - Conn_StartTime( idx2 ), Conn_SendQ( idx ), Conn_SendQ( idx2 ))) return DISCONNECTED;

		/* Forward command */
		IRC_WriteStrClientPrefix( target, from, "TRACE %s", Req->argv[0] );
		return CONNECTED;
	}

	/* Infos about all connected servers */
	c = Client_First( );
	while( c )
	{
		if( Client_Conn( c ) > NONE )
		{
			/* Local client */
			if( Client_Type( c ) == CLIENT_SERVER )
			{
				/* Server link */
				strlcpy( user, Client_User( c ), sizeof( user ));
				if( user[0] == '~' ) strlcpy( user, "unknown", sizeof( user ));
				if( ! IRC_WriteStrClient( from, RPL_TRACESERVER_MSG, Client_ID( from ), Client_ID( c ), user, Client_Hostname( c ), Client_Mask( Client_ThisServer( )), Option_String( Client_Conn( c )))) return DISCONNECTED;
			}
			if(( Client_Type( c ) == CLIENT_USER ) && ( strchr( Client_Modes( c ), 'o' )))
			{
				/* IRC Operator */
				if( ! IRC_WriteStrClient( from, RPL_TRACEOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
			}
		}
		c = Client_Next( c );
	}

	IRC_SetPenalty( Client, 3 );
	return IRC_WriteStrClient( from, RPL_TRACEEND_MSG, Client_ID( from ), Conf_ServerName, PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel );
} /* IRC_TRACE */
예제 #4
0
파일: irc-mode.c 프로젝트: LucentW/ngircd
/**
 * Handle client mode requests
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @param Origin The originator of the MODE command (prefix).
 * @param Target The target (client) of this MODE command.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
{
	char the_modes[COMMAND_LEN], x[2], *mode_ptr;
	bool ok, set;
	bool send_RPL_HOSTHIDDEN_MSG = false;
	int mode_arg;
	size_t len;

	/* Is the client allowed to request or change the modes? */
	if (Client_Type(Client) == CLIENT_USER) {
		/* Users are only allowed to manipulate their own modes! */
		if (Target != Client)
			return IRC_WriteErrClient(Client,
						  ERR_USERSDONTMATCH_MSG,
						  Client_ID(Client));
	}

	/* Mode request: let's answer it :-) */
	if (Req->argc == 1)
		return IRC_WriteStrClient(Origin, RPL_UMODEIS_MSG,
					  Client_ID(Target),
					  Client_Modes(Target));

	mode_arg = 1;
	mode_ptr = Req->argv[mode_arg];

	/* Initial state: set or unset modes? */
	if (*mode_ptr == '+') {
		set = true;
		strcpy(the_modes, "+");
	} else if (*mode_ptr == '-') {
		set = false;
		strcpy(the_modes, "-");
	} else
		return IRC_WriteErrClient(Origin, ERR_UMODEUNKNOWNFLAG_MSG,
					  Client_ID(Origin));

	x[1] = '\0';
	ok = CONNECTED;
	while (mode_ptr) {
		mode_ptr++;
		if (!*mode_ptr) {
			/* Try next argument if there's any */
			mode_arg++;
			if (mode_arg < Req->argc)
				mode_ptr = Req->argv[mode_arg];
			else
				break;
		}

		switch(*mode_ptr) {
		  case '+':
		  case '-':
			if ((*mode_ptr == '+' && !set)
			    || (*mode_ptr == '-' && set)) {
				/* Action modifier ("+"/"-") must be changed */
				len = strlen(the_modes) - 1;
				if (the_modes[len] == '+'
				    || the_modes[len] == '-') {
					/* Last character in the "result
					 * string" was an "action", so just
					 * overwrite it with the new action */
					the_modes[len] = *mode_ptr;
				} else {
					/* Append new modifier character to
					 * the resulting mode string */
					x[0] = *mode_ptr;
					strlcat(the_modes, x,
						sizeof(the_modes));
				}
				if (*mode_ptr == '+')
					set = true;
				else
					set = false;
			}
			continue;
		}

		/* Validate modes */
		x[0] = '\0';
		switch (*mode_ptr) {
		case 'b': /* Block private msgs */
		case 'C': /* Only messages from clients sharing a channel */
		case 'i': /* Invisible */
		case 'I': /* Hide channel list from WHOIS */
		case 's': /* Server messages */
		case 'w': /* Wallops messages */
			x[0] = *mode_ptr;
			break;
		case 'a': /* Away */
			if (Client_Type(Client) == CLIENT_SERVER) {
				x[0] = 'a';
				Client_SetAway(Origin, DEFAULT_AWAY_MSG);
			} else
				ok = IRC_WriteErrClient(Origin,
							ERR_NOPRIVILEGES_MSG,
							Client_ID(Origin));
			break;
		case 'B': /* Bot */
			if (Client_HasMode(Client, 'r'))
				ok = IRC_WriteErrClient(Origin,
							ERR_RESTRICTED_MSG,
							Client_ID(Origin));
			else
				x[0] = 'B';
			break;
		case 'c': /* Receive connect notices */
		case 'q': /* KICK-protected user */
		case 'F': /* disable flood protection */
			  /* (only settable by IRC operators!) */
			if (!set || Client_Type(Client) == CLIENT_SERVER
			    || Client_HasMode(Origin, 'o'))
				x[0] = *mode_ptr;
			else
				ok = IRC_WriteErrClient(Origin,
							ERR_NOPRIVILEGES_MSG,
							Client_ID(Origin));
			break;
		case 'o': /* IRC operator (only unsettable!) */
			if (!set || Client_Type(Client) == CLIENT_SERVER) {
				x[0] = 'o';
			} else
				ok = IRC_WriteErrClient(Origin,
							ERR_NOPRIVILEGES_MSG,
							Client_ID(Origin));
			break;
		case 'r': /* Restricted (only settable) */
			if (set || Client_Type(Client) == CLIENT_SERVER)
				x[0] = 'r';
			else
				ok = IRC_WriteErrClient(Origin,
							ERR_RESTRICTED_MSG,
							Client_ID(Origin));
			break;
		case 'R': /* Registered (not [un]settable by clients) */
			if (Client_Type(Client) == CLIENT_SERVER)
				x[0] = 'R';
			else
				ok = IRC_WriteErrClient(Origin,
							ERR_NICKREGISTER_MSG,
							Client_ID(Origin));
			break;
		case 'x': /* Cloak hostname */
			if (Client_HasMode(Client, 'r'))
				ok = IRC_WriteErrClient(Origin,
							ERR_RESTRICTED_MSG,
							Client_ID(Origin));
			else if (!set || Conf_CloakHostModeX[0]
				 || Client_Type(Client) == CLIENT_SERVER
				 || Client_HasMode(Origin, 'o')) {
				x[0] = 'x';
				send_RPL_HOSTHIDDEN_MSG = true;
			} else
				ok = IRC_WriteErrClient(Origin,
							ERR_NOPRIVILEGES_MSG,
							Client_ID(Origin));
			break;
		default:
			if (Client_Type(Client) != CLIENT_SERVER) {
				Log(LOG_DEBUG,
				    "Unknown mode \"%c%c\" from \"%s\"!?",
				    set ? '+' : '-', *mode_ptr,
				    Client_ID(Origin));
				ok = IRC_WriteErrClient(Origin,
							ERR_UMODEUNKNOWNFLAG2_MSG,
							Client_ID(Origin),
							set ? '+' : '-',
							*mode_ptr);
				x[0] = '\0';
			} else {
				Log(LOG_DEBUG,
				    "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...",
				    set ? '+' : '-', *mode_ptr,
				    Client_ID(Origin), Client_ID(Target));
				x[0] = *mode_ptr;
			}
		}

		if (!ok)
			break;

		/* Is there a valid mode change? */
		if (!x[0])
			continue;

		if (set) {
			if (Client_ModeAdd(Target, x[0]))
				strlcat(the_modes, x, sizeof(the_modes));
		} else {
			if (Client_ModeDel(Target, x[0]))
				strlcat(the_modes, x, sizeof(the_modes));
		}
	}

	/* Are there changed modes? */
	if (the_modes[1]) {
		/* Remove needless action modifier characters */
		len = strlen(the_modes) - 1;
		if (the_modes[len] == '+' || the_modes[len] == '-')
			the_modes[len] = '\0';

		if (Client_Type(Client) == CLIENT_SERVER) {
			/* Forward modes to other servers */
			if (Client_Conn(Target) != NONE) {
				/* Remote server (service?) changed modes
				 * for one of our clients. Inform it! */
				IRC_WriteStrClientPrefix(Target, Origin,
							 "MODE %s :%s",
							 Client_ID(Target),
							 the_modes);
			}
			IRC_WriteStrServersPrefix(Client, Origin,
						  "MODE %s :%s",
						  Client_ID(Target),
						  the_modes);
		} else {
			/* Send reply to client and inform other servers */
			ok = IRC_WriteStrClientPrefix(Client, Origin,
						      "MODE %s :%s",
						      Client_ID(Target),
						      the_modes);
			IRC_WriteStrServersPrefix(Client, Origin,
						  "MODE %s :%s",
						  Client_ID(Target),
						  the_modes);
		}

		if (send_RPL_HOSTHIDDEN_MSG && Client_Conn(Target) > NONE) {
			/* A new (cloaked) hostname must be announced */
			IRC_WriteStrClientPrefix(Target, Origin,
						 RPL_HOSTHIDDEN_MSG,
						 Client_ID(Target),
						 Client_HostnameDisplayed(Target));

		}

		LogDebug("%s \"%s\": Mode change, now \"%s\".",
			 Client_TypeText(Target), Client_Mask(Target),
			 Client_Modes(Target));
	}

	return ok;
} /* Client_Mode */
예제 #5
0
파일: irc-op.c 프로젝트: cofyc/ngircd
/**
 * 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_ARGC_EQ_OR_RETURN_(Client, Req, 2)
	_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_WriteStrClient(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_WriteStrClient(from, ERR_NOTONCHANNEL_MSG, Client_ID(Client), Req->argv[1]);

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

		/* Is the channel "invite-only"? */
		if (strchr(Channel_Modes(chan), 'i')) {
			/* Yes. The user must be channel owner/admin/operator/halfop! */
			if (!strchr(Channel_UserModes(chan, from), 'q') &&
			    !strchr(Channel_UserModes(chan, from), 'a') &&
			    !strchr(Channel_UserModes(chan, from), 'o') &&
			    !strchr(Channel_UserModes(chan, from), 'h'))
				return IRC_WriteStrClient(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_WriteStrClient(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_Mask(target), true))
				return CONNECTED;
		}
	}

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

	/*
	 * RFC 2812 says:
	 * '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 (strchr(Client_Modes(target), 'a') &&
			!IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from),
					Client_ID(target), Client_Away(target)))
				return DISCONNECTED;
	}
	return CONNECTED;
} /* IRC_INVITE */
예제 #6
0
파일: client.c 프로젝트: kazcw/pande
/**
 * Announce an user or service to a server.
 *
 * This function differentiates between RFC1459 and RFC2813 server links and
 * generates the appropriate commands to register the user or service.
 *
 * @param Client	Server
 * @param Prefix	Prefix for the generated commands
 * @param User		User to announce
 */
GLOBAL bool
Client_Announce(CLIENT * Client, CLIENT * Prefix, CLIENT * User)
{
	CONN_ID conn;
	char *modes, *user, *host;

	modes = Client_Modes(User);
	user = Client_User(User) ? Client_User(User) : "-";
	host = Client_Hostname(User) ? Client_Hostname(User) : "-";

	conn = Client_Conn(Client);
	if (Conn_Options(conn) & CONN_RFC1459) {
		/* RFC 1459 mode: separate NICK and USER commands */
		if (! Conn_WriteStr(conn, "NICK %s :%d",
				    Client_ID(User), Client_Hops(User) + 1))
			return DISCONNECTED;
		if (! Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
				     Client_ID(User), user, host,
				     Client_ID(Client_Introducer(User)),
				     Client_Info(User)))
			return DISCONNECTED;
		if (modes[0]) {
			if (! Conn_WriteStr(conn, ":%s MODE %s +%s",
				     Client_ID(User), Client_ID(User),
				     modes))
				return DISCONNECTED;
		}
	} else {
		/* RFC 2813 mode: one combined NICK or SERVICE command */
		if (Client_Type(User) == CLIENT_SERVICE
		    && Client_HasFlag(Client, 'S')) {
			if (!IRC_WriteStrClientPrefix(Client, Prefix,
					"SERVICE %s %d * +%s %d :%s",
					Client_Mask(User),
					Client_MyToken(Client_Introducer(User)),
					modes, Client_Hops(User) + 1,
					Client_Info(User)))
				return DISCONNECTED;
		} else {
			if (!IRC_WriteStrClientPrefix(Client, Prefix,
					"NICK %s %d %s %s %d +%s :%s",
					Client_ID(User), Client_Hops(User) + 1,
					user, host,
					Client_MyToken(Client_Introducer(User)),
					modes, Client_Info(User)))
				return DISCONNECTED;
		}
	}

	if (Client_HasFlag(Client, 'M')) {
		/* Synchronize metadata */
		if (Client_HostnameCloaked(User)) {
			if (!IRC_WriteStrClientPrefix(Client, Prefix,
					"METADATA %s cloakhost :%s",
					Client_ID(User),
					Client_HostnameCloaked(User)))
				return DISCONNECTED;
		}

		if (Client_AccountName(User)) {
			if (!IRC_WriteStrClientPrefix(Client, Prefix,
					"METADATA %s accountname :%s",
					Client_ID(User),
					Client_AccountName(User)))
				return DISCONNECTED;
		}

		if (Conn_GetCertFp(Client_Conn(User))) {
			if (!IRC_WriteStrClientPrefix(Client, Prefix,
					"METADATA %s certfp :%s",
					Client_ID(User),
					Conn_GetCertFp(Client_Conn(User))))
				return DISCONNECTED;
		}
	}

	return CONNECTED;
} /* Client_Announce */