commit - edfcc2f9d5b796fd30f60138591e4f96d54cfcf6
commit + bd3a7ccb158c9f2eac1af77804529b76d99c3e79
blob - d3098f4d62a5cbfe33ef6c3e7e3281abadbaf12f
blob + d89d3792aa9778dcc7bd9575cb5ebb495c568157
--- contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
+++ contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj
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 */
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>"; };
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 */,
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 */,
children = (
FA322D9B0CEF752C001761B3 /* Makefile.am */,
FAE22BD215270EA300F1A5AB /* Bopm.txt */,
+ FAD5852F15271A7800328741 /* Capabilities.txt */,
FAE22BD415270EA300F1A5AB /* Contributing.txt */,
FA322D9A0CEF752C001761B3 /* FAQ.txt */,
FA407F380DB15AC700271AF1 /* GIT.txt */,
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
+
+ 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
static_docs = \
Bopm.txt \
+ Capabilities.txt \
FAQ.txt \
GIT.txt \
HowToRelease.txt \
blob - e96d14bee835d7a73246bc1a709b13eb5f4792e8
blob + 3a411a964b266a2ab9874342ee618018c953ba86
--- src/ngircd/Makefile.am
+++ src/ngircd/Makefile.am
channel.c \
class.c \
client.c \
+ client-cap.c \
conf.c \
conn.c \
conn-func.c \
hash.c \
io.c \
irc.c \
+ irc-cap.c \
irc-channel.c \
irc-info.c \
irc-login.c \
channel.h \
class.h \
client.h \
+ client-cap.h \
conf.h \
conf-ssl.h \
conn.h \
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
+/*
+ * 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
#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
{
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
+/*
+ * 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
+/*
+ * 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
+/*
+ * 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
#include "conn.h"
#include "class.h"
#include "client.h"
+#include "client-cap.h"
#include "channel.h"
#include "conf.h"
#include "io.h"
}
#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
#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
#include "imp.h"
#include "irc.h"
+#include "irc-cap.h"
#include "irc-channel.h"
#include "irc-info.h"
#include "irc-login.h"
{ "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