/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
*
* 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
* IRC info commands
*/
-#include "imp.h"
#include <assert.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
+#include <time.h>
#include "ngircd.h"
#include "conn-func.h"
#include "channel.h"
#include "class.h"
#include "conf.h"
-#include "defines.h"
#include "lists.h"
-#include "log.h"
#include "messages.h"
#include "match.h"
-#include "tool.h"
#include "parse.h"
#include "irc.h"
#include "irc-macros.h"
#include "irc-write.h"
#include "client-cap.h"
+#include "op.h"
-#include "exp.h"
#include "irc-info.h"
/* Local functions */
flags, Client_Hops(c), Client_Info(c));
}
-static const char *
-who_flags_status(const char *client_modes)
-{
- if (strchr(client_modes, 'a'))
- return "G"; /* away */
- return "H";
-}
-
/**
* Return channel user mode prefix(es).
*
{
bool is_visible, is_member, is_ircop;
CL2CHAN *cl2chan;
- const char *client_modes;
char flags[10];
CLIENT *c;
int count = 0;
assert( Client != NULL );
assert( Chan != NULL );
- IRC_SetPenalty(Client, 1);
-
is_member = Channel_IsMemberOf(Chan, Client);
/* Secret channel? */
- if (!is_member && strchr(Channel_Modes(Chan), 's'))
+ if (!is_member && Channel_HasMode(Chan, 's'))
return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG,
Client_ID(Client), Channel_Name(Chan));
for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
c = Channel_GetClient(cl2chan);
- client_modes = Client_Modes(c);
- is_ircop = strchr(client_modes, 'o') != NULL;
+ is_ircop = Client_HasMode(c, 'o');
if (OnlyOps && !is_ircop)
continue;
- is_visible = strchr(client_modes, 'i') == NULL;
+ is_visible = !Client_HasMode(c, 'i');
if (is_member || is_visible) {
- strlcpy(flags, who_flags_status(client_modes),
- sizeof(flags));
+ memset(flags, 0, sizeof(flags));
+
+ if (Client_HasMode(c, 'a'))
+ flags[0] = 'G'; /* away */
+ else
+ flags[0] = 'H';
+
if (is_ircop)
- strlcat(flags, "*", sizeof(flags));
+ flags[1] = '*';
who_flags_qualifier(Client, Channel_UserModes(Chan, c),
flags, sizeof(flags));
}
}
- /* If there are a lot of clients, augment penalty a bit */
+ /* If there are a lot of clients, increase the penalty a bit */
if (count > MAX_RPL_WHO)
IRC_SetPenalty(Client, 1);
CL2CHAN *cl2chan;
CHANNEL *chan;
bool client_match, is_visible;
- char flags[4];
+ char flags[3];
int count = 0;
assert (Client != NULL);
if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO"))
break;
- strlcpy(flags, who_flags_status(Client_Modes(c)), sizeof(flags));
- if (strchr(Client_Modes(c), 'o'))
- strlcat(flags, "*", sizeof(flags));
+ memset(flags, 0, sizeof(flags));
+
+ if (Client_HasMode(c, 'a'))
+ flags[0] = 'G'; /* away */
+ else
+ flags[0] = 'H';
+
+ if (Client_HasMode(c, 'o'))
+ flags[1] = '*';
if (!write_whoreply(Client, c, "*", flags))
return DISCONNECTED;
Client_Info(Client_Introducer(c))))
return DISCONNECTED;
- /* Channels */
- snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
- Client_ID(from), Client_ID(c));
- cl2chan = Channel_FirstChannelOf(c);
- while (cl2chan) {
- chan = Channel_GetChannel(cl2chan);
- assert(chan != NULL);
-
- /* next */
- cl2chan = Channel_NextChannelOf(c, cl2chan);
-
- /* Secret channel? */
- if (strchr(Channel_Modes(chan), 's')
- && !Channel_IsMemberOf(chan, Client))
- continue;
+ /* Channels, show only if client has no +I or if from is oper */
+ if(!(Client_HasMode(c, 'I')) || Client_HasMode(from, 'o')) {
+ snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
+ Client_ID(from), Client_ID(c));
+ cl2chan = Channel_FirstChannelOf(c);
+ while (cl2chan) {
+ chan = Channel_GetChannel(cl2chan);
+ assert(chan != NULL);
+
+ /* next */
+ cl2chan = Channel_NextChannelOf(c, cl2chan);
+
+ /* Secret channel? */
+ if (Channel_HasMode(chan, 's')
+ && !Channel_IsMemberOf(chan, Client))
+ continue;
- /* Local channel and request is not from a user? */
- if (Client_Type(Client) == CLIENT_SERVER
- && Channel_IsLocal(chan))
- continue;
+ /* Local channel and request is not from a user? */
+ if (Client_Type(Client) == CLIENT_SERVER
+ && Channel_IsLocal(chan))
+ continue;
- /* Concatenate channel names */
- if (str[strlen(str) - 1] != ':')
- strlcat(str, " ", sizeof(str));
+ /* Concatenate channel names */
+ if (str[strlen(str) - 1] != ':')
+ strlcat(str, " ", sizeof(str));
- who_flags_qualifier(Client, Channel_UserModes(chan, c),
- str, sizeof(str));
- strlcat(str, Channel_Name(chan), sizeof(str));
+ who_flags_qualifier(Client, Channel_UserModes(chan, c),
+ str, sizeof(str));
+ strlcat(str, Channel_Name(chan), sizeof(str));
- if (strlen(str) > (COMMAND_LEN - CHANNEL_NAME_LEN - 4)) {
- /* Line becomes too long: send it! */
+ if (strlen(str) > (COMMAND_LEN - CHANNEL_NAME_LEN - 4)) {
+ /* Line becomes too long: send it! */
+ if (!IRC_WriteStrClient(Client, "%s", str))
+ return DISCONNECTED;
+ snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
+ Client_ID(from), Client_ID(c));
+ }
+ }
+ if(str[strlen(str) - 1] != ':') {
+ /* There is data left to send: */
if (!IRC_WriteStrClient(Client, "%s", str))
return DISCONNECTED;
- snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
- Client_ID(from), Client_ID(c));
}
}
- if(str[strlen(str) - 1] != ':') {
- /* There is data left to send: */
- if (!IRC_WriteStrClient(Client, "%s", str))
- return DISCONNECTED;
- }
/* IRC-Services? */
if (Client_Type(c) == CLIENT_SERVICE &&
return DISCONNECTED;
/* Certificate fingerprint? */
- if (Conn_GetFingerprint(Client_Conn(c)) &&
+ if (Conn_GetCertFp(Client_Conn(c)) &&
from == c &&
!IRC_WriteStrClient(from, RPL_WHOISCERTFP_MSG,
Client_ID(from), Client_ID(c),
- Conn_GetFingerprint(Client_Conn(c))))
+ Conn_GetCertFp(Client_Conn(c))))
return DISCONNECTED;
}
Client_ID(from), Client_ID(c)))
return DISCONNECTED;
+ /* Account name metadata? */
+ if (Client_AccountName(c) &&
+ !IRC_WriteStrClient(from, RPL_WHOISLOGGEDIN_MSG,
+ Client_ID(from), Client_ID(c),
+ Client_AccountName(c)))
+ return DISCONNECTED;
+
/* Local client and requester is the user itself or an IRC Op? */
if (Client_Conn(c) > NONE &&
- (from == c || (!Conf_MorePrivacy && Client_HasMode(from, 'o')))) {
+ (from == c || Client_HasMode(from, 'o'))) {
/* Client hostname */
if (!IRC_WriteStrClient(from, RPL_WHOISHOST_MSG,
- Client_ID(from), Client_ID(c), Client_Hostname(c),
- Conn_GetIPAInfo(Client_Conn(c))))
+ Client_ID(from), Client_ID(c),
+ Client_Hostname(c), Client_IPAText(c)))
return DISCONNECTED;
/* Client modes */
if (!IRC_WriteStrClient(from, RPL_WHOISMODES_MSG,
entry->id, entry->server, t_str);
}
-static bool
-Show_MOTD_Start(CLIENT *Client)
-{
- return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
- Client_ID( Client ), Client_ID( Client_ThisServer( )));
-}
-
-static bool
-Show_MOTD_Sendline(CLIENT *Client, const char *msg)
-{
- return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
-}
-
-static bool
-Show_MOTD_End(CLIENT *Client)
-{
- if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
- return DISCONNECTED;
-
- if (*Conf_CloakHost)
- return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
- Client_ID(Client),
- Client_Hostname(Client));
-
- return CONNECTED;
-}
-
#ifdef SSL_SUPPORT
-static bool Show_MOTD_SSLInfo(CLIENT *Client)
+static bool
+Show_MOTD_SSLInfo(CLIENT *Client)
{
char buf[COMMAND_LEN];
char c_str[128];
return false;
}
- if (Conn_GetFingerprint(Client_Conn(Client))) {
+ if (Conn_GetCertFp(Client_Conn(Client))) {
snprintf(buf, sizeof(buf),
"Your client certificate fingerprint is: %s",
- Conn_GetFingerprint(Client_Conn(Client)));
+ Conn_GetCertFp(Client_Conn(Client)));
if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
Client_ID(Client), buf))
return false;
return true;
}
#else
-static inline bool
+static bool
Show_MOTD_SSLInfo(UNUSED CLIENT *c)
-{ return true; }
+{
+ return true;
+}
#endif
/* Global functions */
assert( Client != NULL );
assert( Req != NULL );
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1)
_IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
assert(Client != NULL);
assert(Req != NULL);
- IRC_SetPenalty(Client, 2);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1)
_IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
assert(Client != NULL);
assert(Req != NULL);
- _IRC_ARGC_GE_OR_RETURN_(Client, Req, 1)
-
strlcpy(rpl, RPL_ISON_MSG, sizeof rpl);
for (i = 0; i < Req->argc; i++) {
/* "All" ircd even parse ":<x> <y> ..." arguments and split
assert(Client != NULL);
assert(Req != NULL);
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
/* Get pointer to server mask or "*", if none given */
assert( Client != NULL );
assert( Req != NULL );
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
{
CLIENT *c;
- IRC_SetPenalty(Client, 1);
-
assert(Client != NULL);
assert(Req != NULL);
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
-
if (Req->argc < 2 || strcmp(Req->argv[1], "0") == 0) {
for (c = Client_First(); c!= NULL; c = Client_Next(c)) {
if (Client_Type(c) != CLIENT_SERVICE)
assert( Client != NULL );
assert( Req != NULL );
- IRC_SetPenalty(Client, 3);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
assert( Client != NULL );
assert( Req != NULL );
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
while (c) {
if (Client_Type(c) == CLIENT_USER
&& Channel_FirstChannelOf(c) == NULL
- && !strchr(Client_Modes(c), 'i'))
+ && !Client_HasMode(c, 'i'))
{
/* its a user, concatenate ... */
if (rpl[strlen(rpl) - 1] != ':')
unsigned int days, hrs, mins;
struct list_head *list;
struct list_elem *list_item;
+ bool more_links = false;
assert(Client != NULL);
assert(Req != NULL);
- IRC_SetPenalty(Client, 2);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
case 'k': /* Server-local bans ("K-Lines") */
case 'K':
if (!Client_HasMode(from, 'o'))
- return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG,
+ return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG,
Client_ID(from));
if (query == 'g' || query == 'G')
list = Class_GetList(CLASS_GLINE);
list_item = Lists_GetNext(list_item);
}
break;
+ case 'L': /* Link status (servers and user links) */
+ if (!Op_Check(from, Req))
+ return Op_NoPrivileges(from, Req);
+ more_links = true;
+
case 'l': /* Link status (servers and own link) */
- case 'L':
time_now = time(NULL);
for (con = Conn_First(); con != NONE; con = Conn_Next(con)) {
cl = Conn_GetClient(con);
if (!cl)
continue;
- if ((Client_Type(cl) == CLIENT_SERVER)
- || (cl == Client)) {
- /* Server link or our own connection */
+ if (Client_Type(cl) == CLIENT_SERVER ||
+ cl == Client ||
+ (more_links && Client_Type(cl) == CLIENT_USER)) {
#ifdef ZLIB
if (Conn_Options(con) & CONN_ZIP) {
if (!IRC_WriteStrClient
{
assert(Client != NULL);
- IRC_SetPenalty(Client, 1);
-
- return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG,
+ return IRC_WriteErrClient(Client, ERR_SUMMONDISABLED_MSG,
Client_ID(Client));
} /* IRC_SUMMON */
assert(Client != NULL);
assert(Req != NULL);
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
assert(Client != NULL);
assert(Req != NULL);
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_GE_OR_RETURN_(Client, Req, 1)
-
if (Req->argc > 5)
max = 5;
else
{
assert(Client != NULL);
- IRC_SetPenalty(Client, 1);
-
- return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG,
+ return IRC_WriteErrClient(Client, ERR_USERSDISABLED_MSG,
Client_ID(Client));
} /* IRC_USERS */
assert( Client != NULL );
assert( Req != NULL );
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1)
_IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
}
/* send version information */
- return IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
- PACKAGE_NAME, PACKAGE_VERSION,
- NGIRCd_DebugLevel, Conf_ServerName,
- NGIRCd_VersionAddition);
+ if (!IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
+ PACKAGE_NAME, PACKAGE_VERSION,
+ NGIRCd_DebugLevel, Conf_ServerName,
+ NGIRCd_VersionAddition))
+ return DISCONNECTED;
+
+#ifndef STRICT_RFC
+ /* send RPL_ISUPPORT(005) numerics */
+ if (!IRC_Send_ISUPPORT(prefix))
+ return DISCONNECTED;
+#endif
+
+ return CONNECTED;
} /* IRC_VERSION */
/**
assert (Client != NULL);
assert (Req != NULL);
- IRC_SetPenalty(Client, 1);
-
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
-
only_ops = false;
if (Req->argc == 2) {
if (strcmp(Req->argv[1], "o") == 0)
only_ops = true;
#ifdef STRICT_RFC
- else
- return IRC_WriteStrClient(Client,
+ else {
+ return IRC_WriteErrClient(Client,
ERR_NEEDMOREPARAMS_MSG,
Client_ID(Client),
Req->command);
+ }
#endif
}
}
/* No channel or (valid) mask given */
- IRC_SetPenalty(Client, 2);
return IRC_WHO_Mask(Client, NULL, only_ops);
} /* IRC_WHO */
assert( Client != NULL );
assert( Req != NULL );
- IRC_SetPenalty(Client, 1);
-
- /* Bad number of parameters? */
- if (Req->argc < 1 || Req->argc > 2)
- return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
- Client_ID(Client), Req->command);
+ /* Wrong number of parameters? */
+ if (Req->argc < 1)
+ return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
+ Client_ID(Client));
+ _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
_IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
/* Get target server for this command */
if (!IRC_WHOIS_SendReply(Client, from, c))
return DISCONNECTED;
} else {
- if (!IRC_WriteStrClient(Client,
+ if (!IRC_WriteErrClient(Client,
ERR_NOSUCHNICK_MSG,
Client_ID(Client),
query))
}
if (got_wildcard) {
/* we already handled one wildcard query */
- if (!IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ if (!IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
Client_ID(Client), query))
return DISCONNECTED;
continue;
}
got_wildcard = true;
+ /* Increase penalty for wildcard queries */
IRC_SetPenalty(Client, 3);
for (c = Client_First(); c; c = Client_Next(c)) {
}
if (match_count == 0)
- IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
Client_ID(Client),
Req->argv[Req->argc - 1]);
}
assert( Client != NULL );
assert( Req != NULL );
- /* Do not reveal any info on disconnected users? */
- if (Conf_MorePrivacy)
- return CONNECTED;
-
/* Wrong number of parameters? */
if (Req->argc < 1)
- return IRC_WriteStrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
+ return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
Client_ID(Client));
_IRC_ARGC_LE_OR_RETURN_(Client, Req, 3)
_IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
_IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 2, prefix)
+ /* Do not reveal any info on disconnected users? */
+ if (Conf_MorePrivacy)
+ return CONNECTED;
+
/* Forward? */
if (target != Client_ThisServer()) {
IRC_WriteStrClientPrefix(target, prefix, "WHOWAS %s %s %s",
break;
} while (i != last);
- if (nc == 0 && !IRC_WriteStrClient(prefix, ERR_WASNOSUCHNICK_MSG,
+ if (nc == 0 && !IRC_WriteErrClient(prefix, ERR_WASNOSUCHNICK_MSG,
Client_ID(prefix), nick))
return DISCONNECTED;
}
assert(Client != NULL);
- /* Users, services and serevers in the network */
+ /* Users, services and servers in the network */
if (!IRC_WriteStrClient(Client, RPL_LUSERCLIENT_MSG, Client_ID(Client),
Client_UserCount(), Client_ServiceCount(),
Client_ServerCount()))
len_tot = array_bytes(&Conf_Motd);
if (len_tot == 0 && !Conn_UsesSSL(Client_Conn(Client)))
- return IRC_WriteStrClient(Client, ERR_NOMOTD_MSG, Client_ID(Client));
+ return IRC_WriteErrClient(Client, ERR_NOMOTD_MSG, Client_ID(Client));
- if (!Show_MOTD_Start(Client))
+ if (!IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG, Client_ID(Client),
+ Client_ID(Client_ThisServer())))
return DISCONNECTED;
line = array_start(&Conf_Motd);
assert(len_tot >= len_str);
len_tot -= len_str;
- if (!Show_MOTD_Sendline(Client, line))
+ if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID(Client), line))
return DISCONNECTED;
line += len_str;
}
if (!Show_MOTD_SSLInfo(Client))
return DISCONNECTED;
- return Show_MOTD_End(Client);
+
+ if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
+ return DISCONNECTED;
+
+ if (*Conf_CloakHost)
+ return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
+ Client_ID(Client),
+ Client_Hostname(Client));
+
+ return CONNECTED;
} /* IRC_Show_MOTD */
/**
return CONNECTED;
/* Secret channel? */
- if (!is_member && strchr(Channel_Modes(Chan), 's'))
+ if (!is_member && Channel_HasMode(Chan, 's'))
return CONNECTED;
snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
while (cl2chan) {
cl = Channel_GetClient(cl2chan);
- if (strchr(Client_Modes(cl), 'i'))
+ if (Client_HasMode(cl, 'i'))
is_visible = false;
else
is_visible = true;
GLOBAL bool
IRC_Send_ISUPPORT(CLIENT * Client)
{
+ if (Conf_Network[0] && !IRC_WriteStrClient(Client, RPL_ISUPPORTNET_MSG,
+ Client_ID(Client),
+ Conf_Network))
+ return DISCONNECTED;
if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
- Conf_MaxJoins))
+ CHANTYPES, CHANTYPES, Conf_MaxJoins))
return DISCONNECTED;
return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,