diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ngircd/Makefile.am | 4 | ||||
| -rw-r--r-- | src/ngircd/client-cap.c | 62 | ||||
| -rw-r--r-- | src/ngircd/client-cap.h | 28 | ||||
| -rw-r--r-- | src/ngircd/client.h | 3 | ||||
| -rw-r--r-- | src/ngircd/irc-cap.c | 192 | ||||
| -rw-r--r-- | src/ngircd/irc-cap.h | 24 | ||||
| -rw-r--r-- | src/ngircd/login.c | 5 | ||||
| -rw-r--r-- | src/ngircd/messages.h | 1 | ||||
| -rw-r--r-- | src/ngircd/parse.c | 2 |
9 files changed, 320 insertions, 1 deletions
diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.am index e96d14be..3a411a96 100644 --- a/src/ngircd/Makefile.am +++ b/src/ngircd/Makefile.am @@ -24,6 +24,7 @@ ngircd_SOURCES = \ channel.c \ class.c \ client.c \ + client-cap.c \ conf.c \ conn.c \ conn-func.c \ @@ -32,6 +33,7 @@ ngircd_SOURCES = \ hash.c \ io.c \ irc.c \ + irc-cap.c \ irc-channel.c \ irc-info.c \ irc-login.c \ @@ -62,6 +64,7 @@ noinst_HEADERS = \ channel.h \ class.h \ client.h \ + client-cap.h \ conf.h \ conf-ssl.h \ conn.h \ @@ -72,6 +75,7 @@ noinst_HEADERS = \ hash.h \ io.h \ irc.h \ + irc-cap.h \ irc-channel.h \ irc-info.h \ irc-login.h \ diff --git a/src/ngircd/client-cap.c b/src/ngircd/client-cap.c new file mode 100644 index 00000000..edaf2603 --- /dev/null +++ b/src/ngircd/client-cap.c @@ -0,0 +1,62 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2012 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. + */ + +#define __client_cap_c__ + +#include "portab.h" + +/** + * @file + * Functions to deal with IRC Capabilities + */ + +#include "imp.h" +#include <assert.h> + +#include "defines.h" +#include "conn.h" +#include "client.h" +#include "log.h" + +#include "exp.h" +#include "client-cap.h" + +GLOBAL int +Client_Cap(CLIENT *Client) +{ + assert (Client != NULL); + + return Client->capabilities; +} + +GLOBAL void +Client_CapAdd(CLIENT *Client, int Cap) +{ + assert(Client != NULL); + assert(Cap > 0); + + Client->capabilities |= Cap; + LogDebug("Add capability %d, new capability of \"%s\" is %d.", + Cap, Client_ID(Client), Client->capabilities); +} + +GLOBAL void +Client_CapDel(CLIENT *Client, int Cap) +{ + assert(Client != NULL); + assert(Cap > 0); + + Client->capabilities &= ~Cap; + LogDebug("Delete capability %d, new capability of \"%s\" is %d.", + Cap, Client_ID(Client), Client->capabilities); +} + +/* -eof- */ diff --git a/src/ngircd/client-cap.h b/src/ngircd/client-cap.h new file mode 100644 index 00000000..faec1c20 --- /dev/null +++ b/src/ngircd/client-cap.h @@ -0,0 +1,28 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2012 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. + */ + +#ifndef __client_cap_h__ +#define __client_cap_h__ + +/** + * @file + * Functions to deal with IRC Capabilities (header) + */ + +#define CLIENT_CAP_PENDING 1 /* Capability negotiation pending */ +#define CLIENT_CAP_SUPPORTED 2 /* Client supports IRC capabilities */ + +GLOBAL int Client_Cap PARAMS((CLIENT *Client)); + +GLOBAL void Client_CapAdd PARAMS((CLIENT *Client, int Cap)); +GLOBAL void Client_CapDel PARAMS((CLIENT *Client, int Cap)); + +#endif diff --git a/src/ngircd/client.h b/src/ngircd/client.h index def0549c..bdad9ce9 100644 --- a/src/ngircd/client.h +++ b/src/ngircd/client.h @@ -34,7 +34,7 @@ #include "defines.h" -#if defined(__client_c__) | defined(S_SPLINT_S) +#if defined(__client_c__) | defined(__client_cap_c__) | defined(S_SPLINT_S) typedef struct _CLIENT { @@ -58,6 +58,7 @@ typedef struct _CLIENT bool oper_by_me; /* client is local IRC operator on this server? */ char away[CLIENT_AWAY_LEN]; /* AWAY text (valid if mode 'a' is set) */ char flags[CLIENT_FLAGS_LEN]; /* flags of the client */ + int capabilities; /* enabled IRC capabilities */ } CLIENT; #else diff --git a/src/ngircd/irc-cap.c b/src/ngircd/irc-cap.c new file mode 100644 index 00000000..926943c8 --- /dev/null +++ b/src/ngircd/irc-cap.c @@ -0,0 +1,192 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2012 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. + */ + +#include "portab.h" + +/** + * @file + * Handler for IRC capability ("CAP") commands + */ + +#include "imp.h" +#include <assert.h> +#include <string.h> + +#include "defines.h" +#include "conn.h" +#include "channel.h" +#include "client-cap.h" +#include "irc-write.h" +#include "log.h" +#include "login.h" +#include "messages.h" +#include "parse.h" + +#include "exp.h" +#include "irc-cap.h" + +bool Handle_CAP_LS PARAMS((CLIENT *Client, char *Arg)); +bool Handle_CAP_LIST PARAMS((CLIENT *Client, char *Arg)); +bool Handle_CAP_REQ PARAMS((CLIENT *Client, char *Arg)); +bool Handle_CAP_ACK PARAMS((CLIENT *Client, char *Arg)); +bool Handle_CAP_CLEAR PARAMS((CLIENT *Client)); +bool Handle_CAP_END PARAMS((CLIENT *Client)); + +/** + * Handler for the IRCv3 "CAP" command. + * + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @returns CONNECTED or DISCONNECTED. + */ +GLOBAL bool +IRC_CAP(CLIENT *Client, REQUEST *Req) +{ + assert(Client != NULL); + assert(Req != NULL); + + /* Bad number of prameters? */ + if (Req->argc < 1 || Req->argc > 2) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); + + LogDebug("Got \"%s %s\" command from \"%s\" ...", + Req->command, Req->argv[0], Client_ID(Client)); + + if (Req->argc == 1) { + if (strcasecmp(Req->argv[0], "CLEAR") == 0) + return Handle_CAP_CLEAR(Client); + if (strcasecmp(Req->argv[0], "END") == 0) + return Handle_CAP_END(Client); + } + if (Req->argc >= 1 && Req->argc <= 2) { + if (strcasecmp(Req->argv[0], "LS") == 0) + return Handle_CAP_LS(Client, Req->argv[1]); + if (strcasecmp(Req->argv[0], "LIST") == 0) + return Handle_CAP_LIST(Client, Req->argv[1]); + } + if (Req->argc == 2) { + if (strcasecmp(Req->argv[0], "REQ") == 0) + return Handle_CAP_REQ(Client, Req->argv[1]); + if (strcasecmp(Req->argv[0], "ACK") == 0) + return Handle_CAP_ACK(Client, Req->argv[1]); + } + + return IRC_WriteStrClient(Client, ERR_INVALIDCAP_MSG, + Client_ID(Client), Req->argv[0]); +} + +/** + * Handler for the "CAP LS" command. + * + * @param Client The client from which this command has been received. + * @param Arg Command argument or NULL. + * @returns CONNECTED or DISCONNECTED. + */ +bool +Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg) +{ + assert(Client != NULL); + + if (Client_Type(Client) != CLIENT_USER) + Client_CapAdd(Client, CLIENT_CAP_PENDING); + + Client_CapAdd(Client, CLIENT_CAP_SUPPORTED); + return IRC_WriteStrClient(Client, "CAP %s LS :", Client_ID(Client)); +} + +/** + * Handler for the "CAP LIST" command. + * + * @param Client The client from which this command has been received. + * @param Arg Command argument or NULL. + * @returns CONNECTED or DISCONNECTED. + */ +bool +Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg) +{ + assert(Client != NULL); + + return IRC_WriteStrClient(Client, "CAP %s LIST :", Client_ID(Client)); +} + +/** + * Handler for the "CAP REQ" command. + * + * @param Client The client from which this command has been received. + * @param Arg Command argument. + * @returns CONNECTED or DISCONNECTED. + */ +bool +Handle_CAP_REQ(CLIENT *Client, char *Arg) +{ + assert(Client != NULL); + assert(Arg != NULL); + + return IRC_WriteStrClient(Client, "CAP %s NAK :%s", + Client_ID(Client), Arg); +} + +/** + * Handler for the "CAP ACK" command. + * + * @param Client The client from which this command has been received. + * @param Arg Command argument. + * @returns CONNECTED or DISCONNECTED. + */ +bool +Handle_CAP_ACK(CLIENT *Client, char *Arg) +{ + assert(Client != NULL); + assert(Arg != NULL); + + return CONNECTED; +} + +/** + * Handler for the "CAP CLEAR" command. + * + * @param Client The client from which this command has been received. + * @returns CONNECTED or DISCONNECTED. + */ +bool +Handle_CAP_CLEAR(CLIENT *Client) +{ + assert(Client != NULL); + + return IRC_WriteStrClient(Client, "CAP %s ACK :", Client_ID(Client)); +} + +/** + * Handler for the "CAP END" command. + * + * @param Client The client from which this command has been received. + * @returns CONNECTED or DISCONNECTED. + */ +bool +Handle_CAP_END(CLIENT *Client) +{ + assert(Client != NULL); + + if (Client_Type(Client) != CLIENT_USER) { + /* User is still logging in ... */ + Client_CapDel(Client, CLIENT_CAP_PENDING); + + if (Client_Type(Client) == CLIENT_GOTUSER) { + /* Only "CAP END" was missing: log in! */ + return Login_User(Client); + } + } + + return CONNECTED; +} + +/* -eof- */ diff --git a/src/ngircd/irc-cap.h b/src/ngircd/irc-cap.h new file mode 100644 index 00000000..7cd4c841 --- /dev/null +++ b/src/ngircd/irc-cap.h @@ -0,0 +1,24 @@ +/* + * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de). + * + * 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 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. + */ + +#ifndef __irc_cap_h__ +#define __irc_cap_h__ + +/** + * @file + * Handler for IRC capability ("CAP") commands (header) + */ + +GLOBAL bool IRC_CAP PARAMS((CLIENT *Client, REQUEST *Req)); + +#endif + +/* -eof- */ diff --git a/src/ngircd/login.c b/src/ngircd/login.c index 2c305402..ad45219e 100644 --- a/src/ngircd/login.c +++ b/src/ngircd/login.c @@ -26,6 +26,7 @@ #include "conn.h" #include "class.h" #include "client.h" +#include "client-cap.h" #include "channel.h" #include "conf.h" #include "io.h" @@ -78,6 +79,10 @@ Login_User(CLIENT * Client) } #endif + /* Still waiting for "CAP END" command? */ + if (Client_Cap(Client) & CLIENT_CAP_PENDING) + return CONNECTED; + #ifdef PAM if (!Conf_PAM) { /* Don't do any PAM authentication at all, instead emulate diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index 90e0fdc2..96ff2dea 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -103,6 +103,7 @@ #define ERR_TOOMANYCHANNELS_MSG "405 %s %s :You have joined too many channels" #define ERR_WASNOSUCHNICK_MSG "406 %s %s :There was no such nickname" #define ERR_NOORIGIN_MSG "409 %s :No origin specified" +#define ERR_INVALIDCAP_MSG "410 %s %s :Invalid CAP subcommand" #define ERR_NORECIPIENT_MSG "411 %s :No recipient given (%s)" #define ERR_NOTEXTTOSEND_MSG "412 %s :No text to send" #define ERR_WILDTOPLEVEL "414 %s :Wildcard in toplevel domain" diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index 02ab8935..41e3872f 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -36,6 +36,7 @@ #include "imp.h" #include "irc.h" +#include "irc-cap.h" #include "irc-channel.h" #include "irc-info.h" #include "irc-login.h" @@ -113,6 +114,7 @@ static COMMAND My_Commands[] = { "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 }, #endif #ifndef STRICT_RFC + { "CAP", IRC_CAP, CLIENT_UNKNOWN|CLIENT_GOTNICK|CLIENT_GOTPASS|CLIENT_GOTUSER|CLIENT_USER, 0, 0, 0 }, { "GET", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 }, { "POST", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 }, #endif |