Commit Diff
Diff:
edfcc2f9d5b796fd30f60138591e4f96d54cfcf6
bd3a7ccb158c9f2eac1af77804529b76d99c3e79
Commit:
bd3a7ccb158c9f2eac1af77804529b76d99c3e79
Tree:
aa5e95e0854510803657f278498d9c94084c91f8
Author:
Alexander Barton <alex@barton.de>
Committer:
Alexander Barton <alex@barton.de>
Date:
Sat Mar 31 13:59:06 2012 UTC
Message:
Implement core IRC capability handling and "CAP" command This patch implements the core functions to support "IRC Capabilities" and the IRC "CAP" command as used by other servers and specified here: . It enables ngIRCd to support the defined handshake, but it doesn't implement any capabilities, so "CAP LS" and "CAP LIST" always return the empty set and "CAP REQ ..." always fails with "CAP NAK".
blob - d3098f4d62a5cbfe33ef6c3e7e3281abadbaf12f
blob + d89d3792aa9778dcc7bd9575cb5ebb495c568157
--- contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
+++ contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
@@ -41,6 +41,8 @@
FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA97C55124A271400D5BBA9 /* sighandlers.c */; };
FAACD5F514A6099C006ED74F /* class.c in Sources */ = {isa = PBXBuildFile; fileRef = FAACD5F314A6099C006ED74F /* class.c */; };
+ FAD5853215271AAB00328741 /* client-cap.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853015271AAB00328741 /* client-cap.c */; };
+ FAD5853515271AB800328741 /* irc-cap.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853315271AB800328741 /* irc-cap.c */; };
FAD5853815272C2600328741 /* login.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853615272C2500328741 /* login.c */; };
FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
/* End PBXBuildFile section */
@@ -232,6 +234,11 @@
FAA97C56124A271400D5BBA9 /* sighandlers.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = sighandlers.h; sourceTree = "<group>"; };
FAACD5F314A6099C006ED74F /* class.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = class.c; sourceTree = "<group>"; };
FAACD5F414A6099C006ED74F /* class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = class.h; sourceTree = "<group>"; };
+ FAD5852F15271A7800328741 /* Capabilities.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Capabilities.txt; sourceTree = "<group>"; };
+ FAD5853015271AAB00328741 /* client-cap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "client-cap.c"; sourceTree = "<group>"; };
+ FAD5853115271AAB00328741 /* client-cap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "client-cap.h"; sourceTree = "<group>"; };
+ FAD5853315271AB800328741 /* irc-cap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "irc-cap.c"; sourceTree = "<group>"; };
+ FAD5853415271AB800328741 /* irc-cap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "irc-cap.h"; sourceTree = "<group>"; };
FAD5853615272C2500328741 /* login.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = login.c; sourceTree = "<group>"; };
FAD5853715272C2500328741 /* login.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.h; sourceTree = "<group>"; };
FAE22BD215270EA300F1A5AB /* Bopm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bopm.txt; sourceTree = "<group>"; };
@@ -318,6 +325,8 @@
FAACD5F414A6099C006ED74F /* class.h */,
FA322CDD0CEF74B1001761B3 /* client.c */,
FA322CDE0CEF74B1001761B3 /* client.h */,
+ FAD5853015271AAB00328741 /* client-cap.c */,
+ FAD5853115271AAB00328741 /* client-cap.h */,
FA322CDF0CEF74B1001761B3 /* conf.c */,
FA322CE00CEF74B1001761B3 /* conf.h */,
FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
@@ -332,6 +341,8 @@
FA322CE90CEF74B1001761B3 /* hash.h */,
FA322CEA0CEF74B1001761B3 /* io.c */,
FA322CEB0CEF74B1001761B3 /* io.h */,
+ FAD5853315271AB800328741 /* irc-cap.c */,
+ FAD5853415271AB800328741 /* irc-cap.h */,
FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
FA322CED0CEF74B1001761B3 /* irc-channel.h */,
FA322CEE0CEF74B1001761B3 /* irc-info.c */,
@@ -576,6 +587,7 @@
children = (
FA322D9B0CEF752C001761B3 /* Makefile.am */,
FAE22BD215270EA300F1A5AB /* Bopm.txt */,
+ FAD5852F15271A7800328741 /* Capabilities.txt */,
FAE22BD415270EA300F1A5AB /* Contributing.txt */,
FA322D9A0CEF752C001761B3 /* FAQ.txt */,
FA407F380DB15AC700271AF1 /* GIT.txt */,
@@ -735,6 +747,8 @@
FA2D564A11EA158B00D37A35 /* pam.c in Sources */,
FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */,
FAACD5F514A6099C006ED74F /* class.c in Sources */,
+ FAD5853215271AAB00328741 /* client-cap.c in Sources */,
+ FAD5853515271AB800328741 /* irc-cap.c in Sources */,
FAD5853815272C2600328741 /* login.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
blob - /dev/null
blob + 9a692ea6cd273a4a6ec4c460ff6d9c0dc89e33d2 (mode 644)
--- /dev/null
+++ doc/Capabilities.txt
@@ -0,0 +1,23 @@
+
+ ngIRCd - Next Generation IRC Server
+ http://ngircd.barton.de/
+
+ (c)2001-2012 Alexander Barton and Contributors.
+ ngIRCd is free software and published under the
+ terms of the GNU General Public License.
+
+ -- Capabilities.txt --
+
+
+This document lists and describes the "IRC capabilities" that ngIRCd supports
+and can be requested by a IRC/IRCv3 client that supports the "CAP" command.
+
+ngIRCd implements the "IRC Client Capabilities Extension" as described here:
+<http://www.leeh.co.uk/draft-mitchell-irc-capabilities-02.html>
+
+
+I. Supported Capabilities
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+None. At the moment, ngIRCd supports the "CAP" command and its sub-commands
+but offers no capabilities that could be requested by a client.
blob - 1a792c5f95396e5fd1e2b894364a0e713b08f87c
blob + 92e019b832ad1bcd00b3ca0bdd4f4fe929a72472
--- doc/Makefile.am
+++ doc/Makefile.am
@@ -18,6 +18,7 @@ SUFFIXES = .tmpl
static_docs = \
Bopm.txt \
+ Capabilities.txt \
FAQ.txt \
GIT.txt \
HowToRelease.txt \
blob - e96d14bee835d7a73246bc1a709b13eb5f4792e8
blob + 3a411a964b266a2ab9874342ee618018c953ba86
--- src/ngircd/Makefile.am
+++ 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 \
blob - /dev/null
blob + edaf2603bb79005a9b517a6d809702578fa50991 (mode 644)
--- /dev/null
+++ 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- */
blob - def0549c2e8b65a0335bbe3bb72b02a99c106159
blob + bdad9ce93530ace226d5da1885cdb54cafa67ee9
--- src/ngircd/client.h
+++ 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
blob - /dev/null
blob + faec1c202948953df7b5e970082032adaf06a99a (mode 644)
--- /dev/null
+++ 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
blob - /dev/null
blob + 926943c859ab5f265ac3dda585e62ea2ff2bb4cb (mode 644)
--- /dev/null
+++ 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- */
blob - /dev/null
blob + 7cd4c84108ea1f27d9f7146573be300a174caef8 (mode 644)
--- /dev/null
+++ 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- */
blob - 2c305402d77893158ac009ad989303ed53a8ddbf
blob + ad45219eca164aeb16cd3cf6f3ad485fe880439c
--- src/ngircd/login.c
+++ 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
blob - 90e0fdc2b906fe063cfc76be2837ca380cfc120d
blob + 96ff2dea2cc8ab431eef03adb084e7f16d1e3f69
--- src/ngircd/messages.h
+++ 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"
blob - 02ab8935d6ca465d33c70ac29f8e731f1f46307b
blob + 41e3872f66be7a07bff7ab424c46f77fe848d9f6
--- src/ngircd/parse.c
+++ 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
IRCNow