From 7dfa4d790fbafdcebaff6201995b393c1733e85a Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Sat, 18 Dec 2004 16:26:27 +0000 Subject: [PATCH] Author: Kev Log message: * Simplify logic for determining when to run register_user(); before, we explicitly checked to see if the username, hostname, and cookie were all set, and now we can just test to see if a bit flag is 0. * Fix a minor bug in ircd_strn?cmp() that we've never noticed before, because we've never needed lexicographic ordering for strings differing in case. * Implement capabilities system. There are 604 capabilities implemented for testing purposes, but they don't do anything. (This is just the negotiation mechanism. The 604 were needed to test LS & LSL semantics.) git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1284 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 43 +++ include/capab.h | 657 +++++++++++++++++++++++++++++++++++++++++++++ include/client.h | 23 ++ include/handlers.h | 1 + include/msg.h | 4 + include/numeric.h | 2 +- ircd/Makefile.in | 1 + ircd/ircd_string.c | 4 +- ircd/list.c | 1 + ircd/m_cap.c | 370 +++++++++++++++++++++++++ ircd/m_pong.c | 3 +- ircd/m_user.c | 4 +- ircd/parse.c | 7 + ircd/s_err.c | 2 +- ircd/s_user.c | 5 +- 15 files changed, 1120 insertions(+), 7 deletions(-) create mode 100644 include/capab.h create mode 100644 ircd/m_cap.c diff --git a/ChangeLog b/ChangeLog index 2ad336b..038041e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,49 @@ socket's FD is the same after processing as it was before; local clients apparently have s_fd() == -1 after close. +2004-12-18 Kevin L Mitchell + + * ircd/s_user.c: make absolutely certain register_user() is never + called with cli_unreg non-zero; transition set_nick_name() over to + the new way of determining whether client is ready for + register_user() + + * ircd/s_err.c: add ERR_UNKNOWNCAPCMD for reporting failure to + understand a given CAP subcommand + + * ircd/parse.c: add "CAP" command + + * ircd/m_user.c (m_user): transition over to new way of + determining whether client is ready for register_user() + + * ircd/m_pong.c (mr_pong): transition over to new way of + determining whether client is ready for register_user() + + * ircd/m_cap.c: implementation of the IRC capabilities draft + + * ircd/list.c (make_client): initialize cli_unreg element of + client structure + + * ircd/ircd_string.c: correct old bugs in ircd_strn?cmp() + functions that were never found because cross-case ordering has + not been needed until now + + * ircd/Makefile.in: add m_cap.c to list of .c files + + * include/numeric.h (ERR_UNKNOWNCAPCMD): define new error reply to + indicate an unknown CAP subcommand + + * include/msg.h: add "CAP" command + + * include/handlers.h: add m_cap() to list of handlers + + * include/client.h: add support for client capabilities; rototill + the registration mechanism to dovetail well with the capability + system--i.e., allow the capability system to suspend registration + if the user issues one of the CAP commands + + * include/capab.h: header file to define client capabilities + 2004-12-17 Michael Poole * ircd/channel.h (apply_ban): Add new flag to indicate whether diff --git a/include/capab.h b/include/capab.h new file mode 100644 index 0000000..5ec44d2 --- /dev/null +++ b/include/capab.h @@ -0,0 +1,657 @@ +#ifndef INCLUDED_capab_h +#define INCLUDED_capab_h +/* + * IRC - Internet Relay Chat, include/capab.h + * Copyright (C) 2004 Kevin L. Mitchell + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief Interface and public definitions for capabilities extension + * @version $Id$ + */ + +#ifndef INCLUDED_client_h +#include "client.h" +#endif + +#define CAPFL_HIDDEN 0x0001 /**< Do not advertize this capability */ +#define CAPFL_PROHIBIT 0x0002 /**< Client may not set this capability */ +#define CAPFL_PROTO 0x0004 /**< Cap must be acknowledged by client */ + +/* XXX You can safely ignore all of these; they're only for testing purposes, + * XXX and don't result in any behavioral change. + */ +#define CAPLIST \ + _CAP(USERPFX, 0, "undernet.org/userpfx"), \ + _CAP(FOO, CAPFL_HIDDEN, "x-foo"), \ + _CAP(BAR, CAPFL_PROHIBIT, "x-bar"), \ + _CAP(BINK, CAPFL_PROTO, "x-bink"), \ + _CAP(CAP000, 0, "x-cap000"), \ + _CAP(CAP001, 0, "x-cap001"), \ + _CAP(CAP002, 0, "x-cap002"), \ + _CAP(CAP003, 0, "x-cap003"), \ + _CAP(CAP004, 0, "x-cap004"), \ + _CAP(CAP005, 0, "x-cap005"), \ + _CAP(CAP006, 0, "x-cap006"), \ + _CAP(CAP007, 0, "x-cap007"), \ + _CAP(CAP008, 0, "x-cap008"), \ + _CAP(CAP009, 0, "x-cap009"), \ + _CAP(CAP010, 0, "x-cap010"), \ + _CAP(CAP011, 0, "x-cap011"), \ + _CAP(CAP012, 0, "x-cap012"), \ + _CAP(CAP013, 0, "x-cap013"), \ + _CAP(CAP014, 0, "x-cap014"), \ + _CAP(CAP015, 0, "x-cap015"), \ + _CAP(CAP016, 0, "x-cap016"), \ + _CAP(CAP017, 0, "x-cap017"), \ + _CAP(CAP018, 0, "x-cap018"), \ + _CAP(CAP019, 0, "x-cap019"), \ + _CAP(CAP020, 0, "x-cap020"), \ + _CAP(CAP021, 0, "x-cap021"), \ + _CAP(CAP022, 0, "x-cap022"), \ + _CAP(CAP023, 0, "x-cap023"), \ + _CAP(CAP024, 0, "x-cap024"), \ + _CAP(CAP025, 0, "x-cap025"), \ + _CAP(CAP026, 0, "x-cap026"), \ + _CAP(CAP027, 0, "x-cap027"), \ + _CAP(CAP028, 0, "x-cap028"), \ + _CAP(CAP029, 0, "x-cap029"), \ + _CAP(CAP030, 0, "x-cap030"), \ + _CAP(CAP031, 0, "x-cap031"), \ + _CAP(CAP032, 0, "x-cap032"), \ + _CAP(CAP033, 0, "x-cap033"), \ + _CAP(CAP034, 0, "x-cap034"), \ + _CAP(CAP035, 0, "x-cap035"), \ + _CAP(CAP036, 0, "x-cap036"), \ + _CAP(CAP037, 0, "x-cap037"), \ + _CAP(CAP038, 0, "x-cap038"), \ + _CAP(CAP039, 0, "x-cap039"), \ + _CAP(CAP040, 0, "x-cap040"), \ + _CAP(CAP041, 0, "x-cap041"), \ + _CAP(CAP042, 0, "x-cap042"), \ + _CAP(CAP043, 0, "x-cap043"), \ + _CAP(CAP044, 0, "x-cap044"), \ + _CAP(CAP045, 0, "x-cap045"), \ + _CAP(CAP046, 0, "x-cap046"), \ + _CAP(CAP047, 0, "x-cap047"), \ + _CAP(CAP048, 0, "x-cap048"), \ + _CAP(CAP049, 0, "x-cap049"), \ + _CAP(CAP050, 0, "x-cap050"), \ + _CAP(CAP051, 0, "x-cap051"), \ + _CAP(CAP052, 0, "x-cap052"), \ + _CAP(CAP053, 0, "x-cap053"), \ + _CAP(CAP054, 0, "x-cap054"), \ + _CAP(CAP055, 0, "x-cap055"), \ + _CAP(CAP056, 0, "x-cap056"), \ + _CAP(CAP057, 0, "x-cap057"), \ + _CAP(CAP058, 0, "x-cap058"), \ + _CAP(CAP059, 0, "x-cap059"), \ + _CAP(CAP060, 0, "x-cap060"), \ + _CAP(CAP061, 0, "x-cap061"), \ + _CAP(CAP062, 0, "x-cap062"), \ + _CAP(CAP063, 0, "x-cap063"), \ + _CAP(CAP064, 0, "x-cap064"), \ + _CAP(CAP065, 0, "x-cap065"), \ + _CAP(CAP066, 0, "x-cap066"), \ + _CAP(CAP067, 0, "x-cap067"), \ + _CAP(CAP068, 0, "x-cap068"), \ + _CAP(CAP069, 0, "x-cap069"), \ + _CAP(CAP070, 0, "x-cap070"), \ + _CAP(CAP071, 0, "x-cap071"), \ + _CAP(CAP072, 0, "x-cap072"), \ + _CAP(CAP073, 0, "x-cap073"), \ + _CAP(CAP074, 0, "x-cap074"), \ + _CAP(CAP075, 0, "x-cap075"), \ + _CAP(CAP076, 0, "x-cap076"), \ + _CAP(CAP077, 0, "x-cap077"), \ + _CAP(CAP078, 0, "x-cap078"), \ + _CAP(CAP079, 0, "x-cap079"), \ + _CAP(CAP080, 0, "x-cap080"), \ + _CAP(CAP081, 0, "x-cap081"), \ + _CAP(CAP082, 0, "x-cap082"), \ + _CAP(CAP083, 0, "x-cap083"), \ + _CAP(CAP084, 0, "x-cap084"), \ + _CAP(CAP085, 0, "x-cap085"), \ + _CAP(CAP086, 0, "x-cap086"), \ + _CAP(CAP087, 0, "x-cap087"), \ + _CAP(CAP088, 0, "x-cap088"), \ + _CAP(CAP089, 0, "x-cap089"), \ + _CAP(CAP090, 0, "x-cap090"), \ + _CAP(CAP091, 0, "x-cap091"), \ + _CAP(CAP092, 0, "x-cap092"), \ + _CAP(CAP093, 0, "x-cap093"), \ + _CAP(CAP094, 0, "x-cap094"), \ + _CAP(CAP095, 0, "x-cap095"), \ + _CAP(CAP096, 0, "x-cap096"), \ + _CAP(CAP097, 0, "x-cap097"), \ + _CAP(CAP098, 0, "x-cap098"), \ + _CAP(CAP099, 0, "x-cap099"), \ + _CAP(CAP100, 0, "x-cap100"), \ + _CAP(CAP101, 0, "x-cap101"), \ + _CAP(CAP102, 0, "x-cap102"), \ + _CAP(CAP103, 0, "x-cap103"), \ + _CAP(CAP104, 0, "x-cap104"), \ + _CAP(CAP105, 0, "x-cap105"), \ + _CAP(CAP106, 0, "x-cap106"), \ + _CAP(CAP107, 0, "x-cap107"), \ + _CAP(CAP108, 0, "x-cap108"), \ + _CAP(CAP109, 0, "x-cap109"), \ + _CAP(CAP110, 0, "x-cap110"), \ + _CAP(CAP111, 0, "x-cap111"), \ + _CAP(CAP112, 0, "x-cap112"), \ + _CAP(CAP113, 0, "x-cap113"), \ + _CAP(CAP114, 0, "x-cap114"), \ + _CAP(CAP115, 0, "x-cap115"), \ + _CAP(CAP116, 0, "x-cap116"), \ + _CAP(CAP117, 0, "x-cap117"), \ + _CAP(CAP118, 0, "x-cap118"), \ + _CAP(CAP119, 0, "x-cap119"), \ + _CAP(CAP120, 0, "x-cap120"), \ + _CAP(CAP121, 0, "x-cap121"), \ + _CAP(CAP122, 0, "x-cap122"), \ + _CAP(CAP123, 0, "x-cap123"), \ + _CAP(CAP124, 0, "x-cap124"), \ + _CAP(CAP125, 0, "x-cap125"), \ + _CAP(CAP126, 0, "x-cap126"), \ + _CAP(CAP127, 0, "x-cap127"), \ + _CAP(CAP128, 0, "x-cap128"), \ + _CAP(CAP129, 0, "x-cap129"), \ + _CAP(CAP130, 0, "x-cap130"), \ + _CAP(CAP131, 0, "x-cap131"), \ + _CAP(CAP132, 0, "x-cap132"), \ + _CAP(CAP133, 0, "x-cap133"), \ + _CAP(CAP134, 0, "x-cap134"), \ + _CAP(CAP135, 0, "x-cap135"), \ + _CAP(CAP136, 0, "x-cap136"), \ + _CAP(CAP137, 0, "x-cap137"), \ + _CAP(CAP138, 0, "x-cap138"), \ + _CAP(CAP139, 0, "x-cap139"), \ + _CAP(CAP140, 0, "x-cap140"), \ + _CAP(CAP141, 0, "x-cap141"), \ + _CAP(CAP142, 0, "x-cap142"), \ + _CAP(CAP143, 0, "x-cap143"), \ + _CAP(CAP144, 0, "x-cap144"), \ + _CAP(CAP145, 0, "x-cap145"), \ + _CAP(CAP146, 0, "x-cap146"), \ + _CAP(CAP147, 0, "x-cap147"), \ + _CAP(CAP148, 0, "x-cap148"), \ + _CAP(CAP149, 0, "x-cap149"), \ + _CAP(CAP150, 0, "x-cap150"), \ + _CAP(CAP151, 0, "x-cap151"), \ + _CAP(CAP152, 0, "x-cap152"), \ + _CAP(CAP153, 0, "x-cap153"), \ + _CAP(CAP154, 0, "x-cap154"), \ + _CAP(CAP155, 0, "x-cap155"), \ + _CAP(CAP156, 0, "x-cap156"), \ + _CAP(CAP157, 0, "x-cap157"), \ + _CAP(CAP158, 0, "x-cap158"), \ + _CAP(CAP159, 0, "x-cap159"), \ + _CAP(CAP160, 0, "x-cap160"), \ + _CAP(CAP161, 0, "x-cap161"), \ + _CAP(CAP162, 0, "x-cap162"), \ + _CAP(CAP163, 0, "x-cap163"), \ + _CAP(CAP164, 0, "x-cap164"), \ + _CAP(CAP165, 0, "x-cap165"), \ + _CAP(CAP166, 0, "x-cap166"), \ + _CAP(CAP167, 0, "x-cap167"), \ + _CAP(CAP168, 0, "x-cap168"), \ + _CAP(CAP169, 0, "x-cap169"), \ + _CAP(CAP170, 0, "x-cap170"), \ + _CAP(CAP171, 0, "x-cap171"), \ + _CAP(CAP172, 0, "x-cap172"), \ + _CAP(CAP173, 0, "x-cap173"), \ + _CAP(CAP174, 0, "x-cap174"), \ + _CAP(CAP175, 0, "x-cap175"), \ + _CAP(CAP176, 0, "x-cap176"), \ + _CAP(CAP177, 0, "x-cap177"), \ + _CAP(CAP178, 0, "x-cap178"), \ + _CAP(CAP179, 0, "x-cap179"), \ + _CAP(CAP180, 0, "x-cap180"), \ + _CAP(CAP181, 0, "x-cap181"), \ + _CAP(CAP182, 0, "x-cap182"), \ + _CAP(CAP183, 0, "x-cap183"), \ + _CAP(CAP184, 0, "x-cap184"), \ + _CAP(CAP185, 0, "x-cap185"), \ + _CAP(CAP186, 0, "x-cap186"), \ + _CAP(CAP187, 0, "x-cap187"), \ + _CAP(CAP188, 0, "x-cap188"), \ + _CAP(CAP189, 0, "x-cap189"), \ + _CAP(CAP190, 0, "x-cap190"), \ + _CAP(CAP191, 0, "x-cap191"), \ + _CAP(CAP192, 0, "x-cap192"), \ + _CAP(CAP193, 0, "x-cap193"), \ + _CAP(CAP194, 0, "x-cap194"), \ + _CAP(CAP195, 0, "x-cap195"), \ + _CAP(CAP196, 0, "x-cap196"), \ + _CAP(CAP197, 0, "x-cap197"), \ + _CAP(CAP198, 0, "x-cap198"), \ + _CAP(CAP199, 0, "x-cap199"), \ + _CAP(CAP200, 0, "x-cap200"), \ + _CAP(CAP201, 0, "x-cap201"), \ + _CAP(CAP202, 0, "x-cap202"), \ + _CAP(CAP203, 0, "x-cap203"), \ + _CAP(CAP204, 0, "x-cap204"), \ + _CAP(CAP205, 0, "x-cap205"), \ + _CAP(CAP206, 0, "x-cap206"), \ + _CAP(CAP207, 0, "x-cap207"), \ + _CAP(CAP208, 0, "x-cap208"), \ + _CAP(CAP209, 0, "x-cap209"), \ + _CAP(CAP210, 0, "x-cap210"), \ + _CAP(CAP211, 0, "x-cap211"), \ + _CAP(CAP212, 0, "x-cap212"), \ + _CAP(CAP213, 0, "x-cap213"), \ + _CAP(CAP214, 0, "x-cap214"), \ + _CAP(CAP215, 0, "x-cap215"), \ + _CAP(CAP216, 0, "x-cap216"), \ + _CAP(CAP217, 0, "x-cap217"), \ + _CAP(CAP218, 0, "x-cap218"), \ + _CAP(CAP219, 0, "x-cap219"), \ + _CAP(CAP220, 0, "x-cap220"), \ + _CAP(CAP221, 0, "x-cap221"), \ + _CAP(CAP222, 0, "x-cap222"), \ + _CAP(CAP223, 0, "x-cap223"), \ + _CAP(CAP224, 0, "x-cap224"), \ + _CAP(CAP225, 0, "x-cap225"), \ + _CAP(CAP226, 0, "x-cap226"), \ + _CAP(CAP227, 0, "x-cap227"), \ + _CAP(CAP228, 0, "x-cap228"), \ + _CAP(CAP229, 0, "x-cap229"), \ + _CAP(CAP230, 0, "x-cap230"), \ + _CAP(CAP231, 0, "x-cap231"), \ + _CAP(CAP232, 0, "x-cap232"), \ + _CAP(CAP233, 0, "x-cap233"), \ + _CAP(CAP234, 0, "x-cap234"), \ + _CAP(CAP235, 0, "x-cap235"), \ + _CAP(CAP236, 0, "x-cap236"), \ + _CAP(CAP237, 0, "x-cap237"), \ + _CAP(CAP238, 0, "x-cap238"), \ + _CAP(CAP239, 0, "x-cap239"), \ + _CAP(CAP240, 0, "x-cap240"), \ + _CAP(CAP241, 0, "x-cap241"), \ + _CAP(CAP242, 0, "x-cap242"), \ + _CAP(CAP243, 0, "x-cap243"), \ + _CAP(CAP244, 0, "x-cap244"), \ + _CAP(CAP245, 0, "x-cap245"), \ + _CAP(CAP246, 0, "x-cap246"), \ + _CAP(CAP247, 0, "x-cap247"), \ + _CAP(CAP248, 0, "x-cap248"), \ + _CAP(CAP249, 0, "x-cap249"), \ + _CAP(CAP250, 0, "x-cap250"), \ + _CAP(CAP251, 0, "x-cap251"), \ + _CAP(CAP252, 0, "x-cap252"), \ + _CAP(CAP253, 0, "x-cap253"), \ + _CAP(CAP254, 0, "x-cap254"), \ + _CAP(CAP255, 0, "x-cap255"), \ + _CAP(CAP256, 0, "x-cap256"), \ + _CAP(CAP257, 0, "x-cap257"), \ + _CAP(CAP258, 0, "x-cap258"), \ + _CAP(CAP259, 0, "x-cap259"), \ + _CAP(CAP260, 0, "x-cap260"), \ + _CAP(CAP261, 0, "x-cap261"), \ + _CAP(CAP262, 0, "x-cap262"), \ + _CAP(CAP263, 0, "x-cap263"), \ + _CAP(CAP264, 0, "x-cap264"), \ + _CAP(CAP265, 0, "x-cap265"), \ + _CAP(CAP266, 0, "x-cap266"), \ + _CAP(CAP267, 0, "x-cap267"), \ + _CAP(CAP268, 0, "x-cap268"), \ + _CAP(CAP269, 0, "x-cap269"), \ + _CAP(CAP270, 0, "x-cap270"), \ + _CAP(CAP271, 0, "x-cap271"), \ + _CAP(CAP272, 0, "x-cap272"), \ + _CAP(CAP273, 0, "x-cap273"), \ + _CAP(CAP274, 0, "x-cap274"), \ + _CAP(CAP275, 0, "x-cap275"), \ + _CAP(CAP276, 0, "x-cap276"), \ + _CAP(CAP277, 0, "x-cap277"), \ + _CAP(CAP278, 0, "x-cap278"), \ + _CAP(CAP279, 0, "x-cap279"), \ + _CAP(CAP280, 0, "x-cap280"), \ + _CAP(CAP281, 0, "x-cap281"), \ + _CAP(CAP282, 0, "x-cap282"), \ + _CAP(CAP283, 0, "x-cap283"), \ + _CAP(CAP284, 0, "x-cap284"), \ + _CAP(CAP285, 0, "x-cap285"), \ + _CAP(CAP286, 0, "x-cap286"), \ + _CAP(CAP287, 0, "x-cap287"), \ + _CAP(CAP288, 0, "x-cap288"), \ + _CAP(CAP289, 0, "x-cap289"), \ + _CAP(CAP290, 0, "x-cap290"), \ + _CAP(CAP291, 0, "x-cap291"), \ + _CAP(CAP292, 0, "x-cap292"), \ + _CAP(CAP293, 0, "x-cap293"), \ + _CAP(CAP294, 0, "x-cap294"), \ + _CAP(CAP295, 0, "x-cap295"), \ + _CAP(CAP296, 0, "x-cap296"), \ + _CAP(CAP297, 0, "x-cap297"), \ + _CAP(CAP298, 0, "x-cap298"), \ + _CAP(CAP299, 0, "x-cap299"), \ + _CAP(CAP300, 0, "x-cap300"), \ + _CAP(CAP301, 0, "x-cap301"), \ + _CAP(CAP302, 0, "x-cap302"), \ + _CAP(CAP303, 0, "x-cap303"), \ + _CAP(CAP304, 0, "x-cap304"), \ + _CAP(CAP305, 0, "x-cap305"), \ + _CAP(CAP306, 0, "x-cap306"), \ + _CAP(CAP307, 0, "x-cap307"), \ + _CAP(CAP308, 0, "x-cap308"), \ + _CAP(CAP309, 0, "x-cap309"), \ + _CAP(CAP310, 0, "x-cap310"), \ + _CAP(CAP311, 0, "x-cap311"), \ + _CAP(CAP312, 0, "x-cap312"), \ + _CAP(CAP313, 0, "x-cap313"), \ + _CAP(CAP314, 0, "x-cap314"), \ + _CAP(CAP315, 0, "x-cap315"), \ + _CAP(CAP316, 0, "x-cap316"), \ + _CAP(CAP317, 0, "x-cap317"), \ + _CAP(CAP318, 0, "x-cap318"), \ + _CAP(CAP319, 0, "x-cap319"), \ + _CAP(CAP320, 0, "x-cap320"), \ + _CAP(CAP321, 0, "x-cap321"), \ + _CAP(CAP322, 0, "x-cap322"), \ + _CAP(CAP323, 0, "x-cap323"), \ + _CAP(CAP324, 0, "x-cap324"), \ + _CAP(CAP325, 0, "x-cap325"), \ + _CAP(CAP326, 0, "x-cap326"), \ + _CAP(CAP327, 0, "x-cap327"), \ + _CAP(CAP328, 0, "x-cap328"), \ + _CAP(CAP329, 0, "x-cap329"), \ + _CAP(CAP330, 0, "x-cap330"), \ + _CAP(CAP331, 0, "x-cap331"), \ + _CAP(CAP332, 0, "x-cap332"), \ + _CAP(CAP333, 0, "x-cap333"), \ + _CAP(CAP334, 0, "x-cap334"), \ + _CAP(CAP335, 0, "x-cap335"), \ + _CAP(CAP336, 0, "x-cap336"), \ + _CAP(CAP337, 0, "x-cap337"), \ + _CAP(CAP338, 0, "x-cap338"), \ + _CAP(CAP339, 0, "x-cap339"), \ + _CAP(CAP340, 0, "x-cap340"), \ + _CAP(CAP341, 0, "x-cap341"), \ + _CAP(CAP342, 0, "x-cap342"), \ + _CAP(CAP343, 0, "x-cap343"), \ + _CAP(CAP344, 0, "x-cap344"), \ + _CAP(CAP345, 0, "x-cap345"), \ + _CAP(CAP346, 0, "x-cap346"), \ + _CAP(CAP347, 0, "x-cap347"), \ + _CAP(CAP348, 0, "x-cap348"), \ + _CAP(CAP349, 0, "x-cap349"), \ + _CAP(CAP350, 0, "x-cap350"), \ + _CAP(CAP351, 0, "x-cap351"), \ + _CAP(CAP352, 0, "x-cap352"), \ + _CAP(CAP353, 0, "x-cap353"), \ + _CAP(CAP354, 0, "x-cap354"), \ + _CAP(CAP355, 0, "x-cap355"), \ + _CAP(CAP356, 0, "x-cap356"), \ + _CAP(CAP357, 0, "x-cap357"), \ + _CAP(CAP358, 0, "x-cap358"), \ + _CAP(CAP359, 0, "x-cap359"), \ + _CAP(CAP360, 0, "x-cap360"), \ + _CAP(CAP361, 0, "x-cap361"), \ + _CAP(CAP362, 0, "x-cap362"), \ + _CAP(CAP363, 0, "x-cap363"), \ + _CAP(CAP364, 0, "x-cap364"), \ + _CAP(CAP365, 0, "x-cap365"), \ + _CAP(CAP366, 0, "x-cap366"), \ + _CAP(CAP367, 0, "x-cap367"), \ + _CAP(CAP368, 0, "x-cap368"), \ + _CAP(CAP369, 0, "x-cap369"), \ + _CAP(CAP370, 0, "x-cap370"), \ + _CAP(CAP371, 0, "x-cap371"), \ + _CAP(CAP372, 0, "x-cap372"), \ + _CAP(CAP373, 0, "x-cap373"), \ + _CAP(CAP374, 0, "x-cap374"), \ + _CAP(CAP375, 0, "x-cap375"), \ + _CAP(CAP376, 0, "x-cap376"), \ + _CAP(CAP377, 0, "x-cap377"), \ + _CAP(CAP378, 0, "x-cap378"), \ + _CAP(CAP379, 0, "x-cap379"), \ + _CAP(CAP380, 0, "x-cap380"), \ + _CAP(CAP381, 0, "x-cap381"), \ + _CAP(CAP382, 0, "x-cap382"), \ + _CAP(CAP383, 0, "x-cap383"), \ + _CAP(CAP384, 0, "x-cap384"), \ + _CAP(CAP385, 0, "x-cap385"), \ + _CAP(CAP386, 0, "x-cap386"), \ + _CAP(CAP387, 0, "x-cap387"), \ + _CAP(CAP388, 0, "x-cap388"), \ + _CAP(CAP389, 0, "x-cap389"), \ + _CAP(CAP390, 0, "x-cap390"), \ + _CAP(CAP391, 0, "x-cap391"), \ + _CAP(CAP392, 0, "x-cap392"), \ + _CAP(CAP393, 0, "x-cap393"), \ + _CAP(CAP394, 0, "x-cap394"), \ + _CAP(CAP395, 0, "x-cap395"), \ + _CAP(CAP396, 0, "x-cap396"), \ + _CAP(CAP397, 0, "x-cap397"), \ + _CAP(CAP398, 0, "x-cap398"), \ + _CAP(CAP399, 0, "x-cap399"), \ + _CAP(CAP400, 0, "x-cap400"), \ + _CAP(CAP401, 0, "x-cap401"), \ + _CAP(CAP402, 0, "x-cap402"), \ + _CAP(CAP403, 0, "x-cap403"), \ + _CAP(CAP404, 0, "x-cap404"), \ + _CAP(CAP405, 0, "x-cap405"), \ + _CAP(CAP406, 0, "x-cap406"), \ + _CAP(CAP407, 0, "x-cap407"), \ + _CAP(CAP408, 0, "x-cap408"), \ + _CAP(CAP409, 0, "x-cap409"), \ + _CAP(CAP410, 0, "x-cap410"), \ + _CAP(CAP411, 0, "x-cap411"), \ + _CAP(CAP412, 0, "x-cap412"), \ + _CAP(CAP413, 0, "x-cap413"), \ + _CAP(CAP414, 0, "x-cap414"), \ + _CAP(CAP415, 0, "x-cap415"), \ + _CAP(CAP416, 0, "x-cap416"), \ + _CAP(CAP417, 0, "x-cap417"), \ + _CAP(CAP418, 0, "x-cap418"), \ + _CAP(CAP419, 0, "x-cap419"), \ + _CAP(CAP420, 0, "x-cap420"), \ + _CAP(CAP421, 0, "x-cap421"), \ + _CAP(CAP422, 0, "x-cap422"), \ + _CAP(CAP423, 0, "x-cap423"), \ + _CAP(CAP424, 0, "x-cap424"), \ + _CAP(CAP425, 0, "x-cap425"), \ + _CAP(CAP426, 0, "x-cap426"), \ + _CAP(CAP427, 0, "x-cap427"), \ + _CAP(CAP428, 0, "x-cap428"), \ + _CAP(CAP429, 0, "x-cap429"), \ + _CAP(CAP430, 0, "x-cap430"), \ + _CAP(CAP431, 0, "x-cap431"), \ + _CAP(CAP432, 0, "x-cap432"), \ + _CAP(CAP433, 0, "x-cap433"), \ + _CAP(CAP434, 0, "x-cap434"), \ + _CAP(CAP435, 0, "x-cap435"), \ + _CAP(CAP436, 0, "x-cap436"), \ + _CAP(CAP437, 0, "x-cap437"), \ + _CAP(CAP438, 0, "x-cap438"), \ + _CAP(CAP439, 0, "x-cap439"), \ + _CAP(CAP440, 0, "x-cap440"), \ + _CAP(CAP441, 0, "x-cap441"), \ + _CAP(CAP442, 0, "x-cap442"), \ + _CAP(CAP443, 0, "x-cap443"), \ + _CAP(CAP444, 0, "x-cap444"), \ + _CAP(CAP445, 0, "x-cap445"), \ + _CAP(CAP446, 0, "x-cap446"), \ + _CAP(CAP447, 0, "x-cap447"), \ + _CAP(CAP448, 0, "x-cap448"), \ + _CAP(CAP449, 0, "x-cap449"), \ + _CAP(CAP450, 0, "x-cap450"), \ + _CAP(CAP451, 0, "x-cap451"), \ + _CAP(CAP452, 0, "x-cap452"), \ + _CAP(CAP453, 0, "x-cap453"), \ + _CAP(CAP454, 0, "x-cap454"), \ + _CAP(CAP455, 0, "x-cap455"), \ + _CAP(CAP456, 0, "x-cap456"), \ + _CAP(CAP457, 0, "x-cap457"), \ + _CAP(CAP458, 0, "x-cap458"), \ + _CAP(CAP459, 0, "x-cap459"), \ + _CAP(CAP460, 0, "x-cap460"), \ + _CAP(CAP461, 0, "x-cap461"), \ + _CAP(CAP462, 0, "x-cap462"), \ + _CAP(CAP463, 0, "x-cap463"), \ + _CAP(CAP464, 0, "x-cap464"), \ + _CAP(CAP465, 0, "x-cap465"), \ + _CAP(CAP466, 0, "x-cap466"), \ + _CAP(CAP467, 0, "x-cap467"), \ + _CAP(CAP468, 0, "x-cap468"), \ + _CAP(CAP469, 0, "x-cap469"), \ + _CAP(CAP470, 0, "x-cap470"), \ + _CAP(CAP471, 0, "x-cap471"), \ + _CAP(CAP472, 0, "x-cap472"), \ + _CAP(CAP473, 0, "x-cap473"), \ + _CAP(CAP474, 0, "x-cap474"), \ + _CAP(CAP475, 0, "x-cap475"), \ + _CAP(CAP476, 0, "x-cap476"), \ + _CAP(CAP477, 0, "x-cap477"), \ + _CAP(CAP478, 0, "x-cap478"), \ + _CAP(CAP479, 0, "x-cap479"), \ + _CAP(CAP480, 0, "x-cap480"), \ + _CAP(CAP481, 0, "x-cap481"), \ + _CAP(CAP482, 0, "x-cap482"), \ + _CAP(CAP483, 0, "x-cap483"), \ + _CAP(CAP484, 0, "x-cap484"), \ + _CAP(CAP485, 0, "x-cap485"), \ + _CAP(CAP486, 0, "x-cap486"), \ + _CAP(CAP487, 0, "x-cap487"), \ + _CAP(CAP488, 0, "x-cap488"), \ + _CAP(CAP489, 0, "x-cap489"), \ + _CAP(CAP490, 0, "x-cap490"), \ + _CAP(CAP491, 0, "x-cap491"), \ + _CAP(CAP492, 0, "x-cap492"), \ + _CAP(CAP493, 0, "x-cap493"), \ + _CAP(CAP494, 0, "x-cap494"), \ + _CAP(CAP495, 0, "x-cap495"), \ + _CAP(CAP496, 0, "x-cap496"), \ + _CAP(CAP497, 0, "x-cap497"), \ + _CAP(CAP498, 0, "x-cap498"), \ + _CAP(CAP499, 0, "x-cap499"), \ + _CAP(CAP500, 0, "x-cap500"), \ + _CAP(CAP501, 0, "x-cap501"), \ + _CAP(CAP502, 0, "x-cap502"), \ + _CAP(CAP503, 0, "x-cap503"), \ + _CAP(CAP504, 0, "x-cap504"), \ + _CAP(CAP505, 0, "x-cap505"), \ + _CAP(CAP506, 0, "x-cap506"), \ + _CAP(CAP507, 0, "x-cap507"), \ + _CAP(CAP508, 0, "x-cap508"), \ + _CAP(CAP509, 0, "x-cap509"), \ + _CAP(CAP510, 0, "x-cap510"), \ + _CAP(CAP511, 0, "x-cap511"), \ + _CAP(CAP512, 0, "x-cap512"), \ + _CAP(CAP513, 0, "x-cap513"), \ + _CAP(CAP514, 0, "x-cap514"), \ + _CAP(CAP515, 0, "x-cap515"), \ + _CAP(CAP516, 0, "x-cap516"), \ + _CAP(CAP517, 0, "x-cap517"), \ + _CAP(CAP518, 0, "x-cap518"), \ + _CAP(CAP519, 0, "x-cap519"), \ + _CAP(CAP520, 0, "x-cap520"), \ + _CAP(CAP521, 0, "x-cap521"), \ + _CAP(CAP522, 0, "x-cap522"), \ + _CAP(CAP523, 0, "x-cap523"), \ + _CAP(CAP524, 0, "x-cap524"), \ + _CAP(CAP525, 0, "x-cap525"), \ + _CAP(CAP526, 0, "x-cap526"), \ + _CAP(CAP527, 0, "x-cap527"), \ + _CAP(CAP528, 0, "x-cap528"), \ + _CAP(CAP529, 0, "x-cap529"), \ + _CAP(CAP530, 0, "x-cap530"), \ + _CAP(CAP531, 0, "x-cap531"), \ + _CAP(CAP532, 0, "x-cap532"), \ + _CAP(CAP533, 0, "x-cap533"), \ + _CAP(CAP534, 0, "x-cap534"), \ + _CAP(CAP535, 0, "x-cap535"), \ + _CAP(CAP536, 0, "x-cap536"), \ + _CAP(CAP537, 0, "x-cap537"), \ + _CAP(CAP538, 0, "x-cap538"), \ + _CAP(CAP539, 0, "x-cap539"), \ + _CAP(CAP540, 0, "x-cap540"), \ + _CAP(CAP541, 0, "x-cap541"), \ + _CAP(CAP542, 0, "x-cap542"), \ + _CAP(CAP543, 0, "x-cap543"), \ + _CAP(CAP544, 0, "x-cap544"), \ + _CAP(CAP545, 0, "x-cap545"), \ + _CAP(CAP546, 0, "x-cap546"), \ + _CAP(CAP547, 0, "x-cap547"), \ + _CAP(CAP548, 0, "x-cap548"), \ + _CAP(CAP549, 0, "x-cap549"), \ + _CAP(CAP550, 0, "x-cap550"), \ + _CAP(CAP551, 0, "x-cap551"), \ + _CAP(CAP552, 0, "x-cap552"), \ + _CAP(CAP553, 0, "x-cap553"), \ + _CAP(CAP554, 0, "x-cap554"), \ + _CAP(CAP555, 0, "x-cap555"), \ + _CAP(CAP556, 0, "x-cap556"), \ + _CAP(CAP557, 0, "x-cap557"), \ + _CAP(CAP558, 0, "x-cap558"), \ + _CAP(CAP559, 0, "x-cap559"), \ + _CAP(CAP560, 0, "x-cap560"), \ + _CAP(CAP561, 0, "x-cap561"), \ + _CAP(CAP562, 0, "x-cap562"), \ + _CAP(CAP563, 0, "x-cap563"), \ + _CAP(CAP564, 0, "x-cap564"), \ + _CAP(CAP565, 0, "x-cap565"), \ + _CAP(CAP566, 0, "x-cap566"), \ + _CAP(CAP567, 0, "x-cap567"), \ + _CAP(CAP568, 0, "x-cap568"), \ + _CAP(CAP569, 0, "x-cap569"), \ + _CAP(CAP570, 0, "x-cap570"), \ + _CAP(CAP571, 0, "x-cap571"), \ + _CAP(CAP572, 0, "x-cap572"), \ + _CAP(CAP573, 0, "x-cap573"), \ + _CAP(CAP574, 0, "x-cap574"), \ + _CAP(CAP575, 0, "x-cap575"), \ + _CAP(CAP576, 0, "x-cap576"), \ + _CAP(CAP577, 0, "x-cap577"), \ + _CAP(CAP578, 0, "x-cap578"), \ + _CAP(CAP579, 0, "x-cap579"), \ + _CAP(CAP580, 0, "x-cap580"), \ + _CAP(CAP581, 0, "x-cap581"), \ + _CAP(CAP582, 0, "x-cap582"), \ + _CAP(CAP583, 0, "x-cap583"), \ + _CAP(CAP584, 0, "x-cap584"), \ + _CAP(CAP585, 0, "x-cap585"), \ + _CAP(CAP586, 0, "x-cap586"), \ + _CAP(CAP587, 0, "x-cap587"), \ + _CAP(CAP588, 0, "x-cap588"), \ + _CAP(CAP589, 0, "x-cap589"), \ + _CAP(CAP590, 0, "x-cap590"), \ + _CAP(CAP591, 0, "x-cap591"), \ + _CAP(CAP592, 0, "x-cap592"), \ + _CAP(CAP593, 0, "x-cap593"), \ + _CAP(CAP594, 0, "x-cap594"), \ + _CAP(CAP595, 0, "x-cap595"), \ + _CAP(CAP596, 0, "x-cap596"), \ + _CAP(CAP597, 0, "x-cap597"), \ + _CAP(CAP598, 0, "x-cap598"), \ + _CAP(CAP599, 0, "x-cap599") + +/** Client capabilities */ +enum Capab { +#define _CAP(cap, flags, name) CAP_ ## cap + CAPLIST, +#undef _CAP + _CAP_LAST_CAP +}; + +DECLARE_FLAGSET(CapSet, _CAP_LAST_CAP); + +#define CapHas(cs, cap) FlagHas(cs, cap) +#define CapSet(cs, cap) FlagSet(cs, cap) +#define CapClr(cs, cap) FlagClr(cs, cap) + +#endif /* INCLUDED_capab_h */ diff --git a/include/client.h b/include/client.h index b08f7cb..7b97409 100644 --- a/include/client.h +++ b/include/client.h @@ -176,6 +176,8 @@ DECLARE_FLAGSET(Privs, PRIV_LAST_PRIV); /** Declare flagset type for user flags. */ DECLARE_FLAGSET(Flags, FLAG_LAST_FLAG); +#include "capab.h" /* client capabilities */ + /** Represents a local connection. * This contains a lot of stuff irrelevant to server connections, but * those are so rare as to not be worth special-casing. @@ -255,11 +257,21 @@ struct Client { struct irc_in_addr cli_ip; /**< Real IP of client */ short cli_status; /**< Client type */ struct Privs cli_privs; /**< Oper privileges */ + struct CapSet cli_capab; /**< Client capabilities */ + struct CapSet cli_active; /**< Active client capabilities */ + unsigned long cli_unreg; /**< Indicate what still needs to be done */ char cli_name[HOSTLEN + 1]; /**< Unique name of the client, nick or host */ char cli_username[USERLEN + 1]; /**< username here now for auth stuff */ char cli_info[REALLEN + 1]; /**< Free form additional client information */ }; +#define CLIREG_NICK 0x0001 /**< Client must set nickname */ +#define CLIREG_USER 0x0002 /**< Client must set username */ +#define CLIREG_COOKIE 0x0004 /**< Client must return cookie */ +#define CLIREG_CAP 0x0008 /**< Client in capability negotiation */ + +#define CLIREG_INIT (CLIREG_NICK | CLIREG_USER | CLIREG_COOKIE) + /** Magic constant to identify valid Client structures. */ #define CLIENT_MAGIC 0x4ca08286 @@ -307,6 +319,12 @@ struct Client { #define cli_local(cli) (cli_from(cli) == cli) /** Get oper privileges for client. */ #define cli_privs(cli) ((cli)->cli_privs) +/** Get client capabilities for client */ +#define cli_capab(cli) (&((cli)->cli_capab)) +/** Get active client capabilities for client */ +#define cli_active(cli) (&((cli)->cli_active)) +/** Get flags for remaining registration tasks */ +#define cli_unreg(cli) ((cli)->cli_unreg) /** Get client name. */ #define cli_name(cli) ((cli)->cli_name) /** Get client username (ident). */ @@ -718,6 +736,11 @@ struct Client { /** Test whether a privilege has been granted to a client. */ #define HasPriv(cli, priv) FlagHas(&cli_privs(cli), priv) +/** Test whether a client has a capability */ +#define HasCap(cli, cap) CapHas(cli_capab(cli), (cap)) +/** Test whether a client has the capability active */ +#define CapActive(cli, cap) CapHas(cli_active(cli), (cap)) + #define HIDE_IP 0 /**< Do not show IP address in get_client_name() */ #define SHOW_IP 1 /**< Show ident and IP address in get_client_name() */ diff --git a/include/handlers.h b/include/handlers.h index 2fad18c..c9a40f2 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -88,6 +88,7 @@ struct Client; extern int m_admin(struct Client*, struct Client*, int, char*[]); extern int m_away(struct Client*, struct Client*, int, char*[]); +extern int m_cap(struct Client*, struct Client*, int, char*[]); extern int m_cnotice(struct Client*, struct Client*, int, char*[]); extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]); extern int m_gline(struct Client*, struct Client*, int, char*[]); diff --git a/include/msg.h b/include/msg.h index 92d9f17..cbcda92 100644 --- a/include/msg.h +++ b/include/msg.h @@ -355,6 +355,10 @@ struct Client; #define MSG_PRIVS "PRIVS" /* PRIV */ #define TOK_PRIVS "PRIVS" +#define MSG_CAP "CAP" +#define TOK_CAP "CAP" +#define CMD_CAP MSG_CAP, TOK_CAP + /* * Constants */ diff --git a/include/numeric.h b/include/numeric.h index 9778ad5..828156d 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -325,7 +325,7 @@ extern const struct Numeric* get_error_numeric(int err); /* ERR_NOSUCHSERVICE 408 IRCnet */ /* ERR_NOCOLORSONCHAN 408 Dalnet */ #define ERR_NOORIGIN 409 - +#define ERR_UNKNOWNCAPCMD 410 #define ERR_NORECIPIENT 411 #define ERR_NOTEXTTOSEND 412 #define ERR_NOTOPLEVEL 413 diff --git a/ircd/Makefile.in b/ircd/Makefile.in index d1a7317..1860dbf 100644 --- a/ircd/Makefile.in +++ b/ircd/Makefile.in @@ -115,6 +115,7 @@ IRCD_SRC = \ m_asll.c \ m_away.c \ m_burst.c \ + m_cap.c \ m_clearmode.c \ m_close.c \ m_connect.c \ diff --git a/ircd/ircd_string.c b/ircd/ircd_string.c index 4f90c9f..6b18f7c 100644 --- a/ircd/ircd_string.c +++ b/ircd/ircd_string.c @@ -262,7 +262,7 @@ int ircd_strcmp(const char *a, const char *b) else ++rb; } - return (*ra - *rb); + return (ToLower(*ra) - ToLower(*rb)); } /** Case insensitive comparison of the starts of two strings. @@ -285,7 +285,7 @@ int ircd_strncmp(const char *a, const char *b, size_t n) else ++rb; } - return (*ra - *rb); + return (ToLower(*ra) - ToLower(*rb)); } /** Fill a vector of distinct names from a delimited input list. diff --git a/ircd/list.c b/ircd/list.c index b013058..7d4a15e 100644 --- a/ircd/list.c +++ b/ircd/list.c @@ -245,6 +245,7 @@ struct Client* make_client(struct Client *from, int status) cli_connect(cptr) = con; /* set the connection and other fields */ cli_since(cptr) = cli_lasttime(cptr) = cli_firsttime(cptr) = CurrentTime; cli_lastnick(cptr) = TStime(); + cli_unreg(cptr) = CLIREG_INIT; } else cli_connect(cptr) = cli_connect(from); /* use 'from's connection */ diff --git a/ircd/m_cap.c b/ircd/m_cap.c new file mode 100644 index 0000000..1231c7d --- /dev/null +++ b/ircd/m_cap.c @@ -0,0 +1,370 @@ +/* + * IRC - Internet Relay Chat, ircd/m_cap.c + * Copyright (C) 2004 Kevin L. Mitchell + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * 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 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +/* + * m_functions execute protocol messages on this server: + * + * cptr is always NON-NULL, pointing to a *LOCAL* client + * structure (with an open socket connected!). This + * identifies the physical socket where the message + * originated (or which caused the m_function to be + * executed--some m_functions may call others...). + * + * sptr is the source of the message, defined by the + * prefix part of the message if present. If not + * or prefix not found, then sptr==cptr. + * + * (!IsServer(cptr)) => (cptr == sptr), because + * prefixes are taken *only* from servers... + * + * (IsServer(cptr)) + * (sptr == cptr) => the message didn't + * have the prefix. + * + * (sptr != cptr && IsServer(sptr) means + * the prefix specified servername. (?) + * + * (sptr != cptr && !IsServer(sptr) means + * that message originated from a remote + * user (not local). + * + * combining + * + * (!IsServer(sptr)) means that, sptr can safely + * taken as defining the target structure of the + * message in this server. + * + * *Always* true (if 'parse' and others are working correct): + * + * 1) sptr->from == cptr (note: cptr->from == cptr) + * + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr + * *cannot* be a local connection, unless it's + * actually cptr!). [MyConnect(x) should probably + * be defined as (x == x->from) --msa ] + * + * parc number of variable parameter strings (if zero, + * parv is allowed to be NULL) + * + * parv a NULL terminated list of parameter pointers, + * + * parv[0], sender (prefix string), if not present + * this points to an empty string. + * parv[1]...parv[parc-1] + * pointers to additional parameters + * parv[parc] == NULL, *always* + * + * note: it is guaranteed that parv[0]..parv[parc-1] are all + * non-NULL pointers. + */ +#include "config.h" + +#include "client.h" +#include "ircd.h" +#include "ircd_chattr.h" +#include "ircd_log.h" +#include "ircd_reply.h" +#include "ircd_snprintf.h" +#include "ircd_string.h" +#include "msg.h" +#include "numeric.h" +#include "send.h" +#include "s_user.h" + +#include +#include + +typedef int (*bqcmp)(const void *, const void *); + +static struct capabilities { + enum Capab cap; + char *capstr; + unsigned long flags; + char *name; + int namelen; +} capab_list[] = { +#define _CAP(cap, flags, name) \ + { CAP_ ## cap, #cap, (flags), (name), sizeof(name) - 1 } + CAPLIST +#undef _CAP +}; + +#define CAPAB_LIST_LEN (sizeof(capab_list) / sizeof(struct capabilities)) + +static struct CapSet clean_set; /* guaranteed to be all zeros (right?) */ + +static int +capab_sort(const struct capabilities *cap1, const struct capabilities *cap2) +{ + return ircd_strcmp(cap1->name, cap2->name); +} + +static int +capab_search(const char *key, const struct capabilities *cap) +{ + const char *rb = cap->name; + while (ToLower(*key) == ToLower(*rb)) /* walk equivalent part of strings */ + if (!*key++) /* hit the end, all right... */ + return 0; + else /* OK, let's move on... */ + rb++; + + /* If the character they differ on happens to be a space, and it happens + * to be the same length as the capability name, then we've found a + * match; otherwise, return the difference of the two. + */ + return (IsSpace(*key) && !*rb) ? 0 : (ToLower(*key) - ToLower(*rb)); +} + +static struct capabilities * +find_cap(const char **caplist_p, int *neg_p) +{ + static int inited = 0; + const char *caplist = *caplist_p; + struct capabilities *cap = 0; + + *neg_p = 0; /* clear negative flag... */ + + if (!inited) { /* First, let's sort the array... */ + qsort(capab_list, CAPAB_LIST_LEN, sizeof(struct capabilities), + (bqcmp)capab_sort); + inited++; /* remember that we've done this step... */ + } + + /* Next, find first non-whitespace character... */ + while (*caplist && IsSpace(*caplist)) + caplist++; + + /* We are now at the beginning of an element of the list; is it negative? */ + if (*caplist == '-') { + caplist++; /* yes; step past the flag... */ + *neg_p = 1; /* remember that it is negative... */ + } + + /* OK, now see if we can look up the capability... */ + if (*caplist) { + if (!(cap = (struct capabilities *)bsearch(caplist, capab_list, + CAPAB_LIST_LEN, + sizeof(struct capabilities), + (bqcmp)capab_search))) { + /* Couldn't find the capability; advance to first whitespace character */ + while (*caplist && !IsSpace(*caplist)) + caplist++; + } else + caplist += cap->namelen; /* advance to end of capability name */ + } + + assert(caplist != *caplist_p || !*caplist); /* we *must* advance */ + + /* move ahead in capability list string--or zero pointer if we hit end */ + *caplist_p = *caplist ? caplist : 0; + + return cap; /* and return the capability (if any) */ +} + +static int +send_caplist(struct Client *sptr, const struct CapSet *cs) +{ + char capbuf[BUFSIZE] = ""; + struct MsgBuf *mb; + int i, loc, len; + + /* set up the buffer for the LSL message... */ + mb = msgq_make(sptr, "%:#C " MSG_CAP " LSL :", &me); + + for (i = 0, loc = 0; i < CAPAB_LIST_LEN; i++) { + if (cs ? !CapHas(cs, capab_list[i].cap) : + (capab_list[i].flags & CAPFL_HIDDEN)) + continue; /* not including this capability in the list */ + + len = capab_list[i].namelen + (loc != 0); /* how much we'd add... */ + + if (msgq_bufleft(mb) < loc + len) { /* would add too much; must flush */ + sendcmdto_one(&me, CMD_CAP, sptr, "LS :%s", capbuf); + capbuf[(loc = 0)] = '\0'; /* re-terminate the buffer... */ + } + + loc += ircd_snprintf(0, capbuf + loc, sizeof(capbuf) - loc, "%s%s", + loc ? " " : "", capab_list[i].name); + } + + msgq_append(0, mb, "%s", capbuf); /* append capabilities to the LSL cmd */ + send_buffer(sptr, mb, 0); /* send them out... */ + msgq_clean(mb); /* and release the buffer */ + + return 0; /* convenience return */ +} + +static int +cap_empty(struct Client *sptr, const char *caplist) +{ + if (IsUnknown(sptr)) /* registration hasn't completed; suspend it... */ + cli_unreg(sptr) |= CLIREG_CAP; + + return send_caplist(sptr, 0); /* send list of capabilities */ +} + +static int +cap_req(struct Client *sptr, const char *caplist) +{ + const char *cl = caplist; + struct capabilities *cap; + struct CapSet cs = *cli_capab(sptr); /* capability set */ + struct CapSet as = *cli_active(sptr); /* active set */ + int neg; + + if (IsUnknown(sptr)) /* registration hasn't completed; suspend it... */ + cli_unreg(sptr) |= CLIREG_CAP; + + while (cl) { /* walk through the capabilities list... */ + if (!(cap = find_cap(&cl, &neg)) || /* look up capability... */ + (!neg && (cap->flags & CAPFL_PROHIBIT))) { /* is it prohibited? */ + sendcmdto_one(&me, CMD_CAP, sptr, "NAK :%s", caplist); + return 0; /* can't complete requested op... */ + } + + if (neg) { /* set or clear the capability... */ + CapClr(&cs, cap->cap); + if (!(cap->flags & CAPFL_PROTO)) + CapClr(&as, cap->cap); + } else { + CapSet(&cs, cap->cap); + if (!(cap->flags & CAPFL_PROTO)) + CapSet(&as, cap->cap); + } + } + + sendcmdto_one(&me, CMD_CAP, sptr, "ACK :%s", caplist); + + *cli_capab(sptr) = cs; /* copy the completed results */ + *cli_active(sptr) = as; + + return 0; +} + +static int +cap_ack(struct Client *sptr, const char *caplist) +{ + const char *cl = caplist; + struct capabilities *cap; + int neg; + + while (cl) { /* walk through the capabilities list... */ + if (!(cap = find_cap(&cl, &neg)) || /* look up capability... */ + (neg ? HasCap(sptr, cap->cap) : !HasCap(sptr, cap->cap))) /* uh... */ + continue; + + if (neg) /* set or clear the active capability... */ + CapClr(cli_active(sptr), cap->cap); + else + CapSet(cli_active(sptr), cap->cap); + } + + return 0; +} + +static int +cap_clear(struct Client *sptr, const char *caplist) +{ + sendcmdto_one(&me, CMD_CAP, sptr, "CLEAR"); /* Reply... */ + + *cli_capab(sptr) = clean_set; /* then clear! */ + + return 0; +} + +static int +cap_end(struct Client *sptr, const char *caplist) +{ + if (!IsUnknown(sptr)) /* registration has completed... */ + return 0; /* so just ignore the message... */ + + cli_unreg(sptr) &= ~CLIREG_CAP; /* capability negotiation is now done... */ + + if (!cli_unreg(sptr)) /* if client is now done... */ + return register_user(sptr, sptr, cli_name(sptr), cli_user(sptr)->username); + + return 0; /* Can't do registration yet... */ +} + +static int +cap_list(struct Client *sptr, const char *caplist) +{ + /* Send the list of the client's capabilities */ + return send_caplist(sptr, cli_capab(sptr)); +} + +static struct subcmd { + char *cmd; + int (*proc)(struct Client *sptr, const char *caplist); +} cmdlist[] = { + { "", cap_empty }, + { "ACK", cap_ack }, + { "CLEAR", cap_clear }, + { "END", cap_end }, + { "LIST", cap_list }, + { "LS", 0 }, + { "LSL", 0 }, + { "NAK", 0 }, + { "REQ", cap_req } +}; + +static int +subcmd_search(const char *cmd, const struct subcmd *elem) +{ + return ircd_strcmp(cmd, elem->cmd); +} + +/* + * m_cap - user message handler + * + * parv[0] = Send prefix + * + * From user: + * + * parv[1] = [] + * parv[2] = [] + * + */ +int +m_cap(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + char *subcmd = "", *caplist = 0; + struct subcmd *cmd; + + if (parc > 1 && parv[1]) /* a subcommand was provided */ + subcmd = parv[1]; + if (parc > 2) /* a capability list was provided */ + caplist = parv[2]; + + /* find the subcommand handler */ + if (!(cmd = (struct subcmd *)bsearch(subcmd, cmdlist, + sizeof(cmdlist) / sizeof(struct subcmd), + sizeof(struct subcmd), + (bqcmp)subcmd_search))) + return send_reply(sptr, ERR_UNKNOWNCAPCMD, subcmd); + + /* then execute it... */ + return cmd->proc ? (cmd->proc)(sptr, caplist) : 0; +} diff --git a/ircd/m_pong.c b/ircd/m_pong.c index e149c23..f66668d 100644 --- a/ircd/m_pong.c +++ b/ircd/m_pong.c @@ -170,7 +170,8 @@ int mr_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (0 != cli_cookie(sptr) && COOKIE_VERIFIED != cli_cookie(sptr)) { if (parc > 1 && cli_cookie(sptr) == atol(parv[parc - 1])) { cli_cookie(sptr) = COOKIE_VERIFIED; - if (cli_user(sptr) && *(cli_user(sptr))->host && (cli_name(sptr))[0]) + cli_unreg(sptr) &= ~CLIREG_COOKIE; /* cookie has been returned... */ + if (!cli_unreg(sptr)) /* no more registration tasks... */ /* * NICK and USER OK */ diff --git a/ircd/m_user.c b/ircd/m_user.c index 33dd470..efbe6eb 100644 --- a/ircd/m_user.c +++ b/ircd/m_user.c @@ -144,7 +144,9 @@ int m_user(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) user->server = &me; ircd_strncpy(cli_info(cptr), info, REALLEN); - if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED) { + cli_unreg(sptr) &= ~CLIREG_USER; /* username now set */ + + if (!cli_unreg(sptr)) { /* * NICK and PONG already received, now we have USER... */ diff --git a/ircd/parse.c b/ircd/parse.c index ac69fe6..c8ed85d 100644 --- a/ircd/parse.c +++ b/ircd/parse.c @@ -616,6 +616,13 @@ struct Message msgtab[] = { /* UNREG, CLIENT, SERVER, OPER, SERVICE */ { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore } }, + { + MSG_CAP, + TOK_CAP, + 0, MAXPARA, 0, 0, NULL, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_cap, m_cap, m_ignore, m_cap, m_ignore } + }, /* This command is an alias for QUIT during the unregistered part of * of the server. This is because someone jumping via a broken web * proxy will send a 'POST' as their first command - which we will diff --git a/ircd/s_err.c b/ircd/s_err.c index 041520e..c8d015a 100644 --- a/ircd/s_err.c +++ b/ircd/s_err.c @@ -852,7 +852,7 @@ static Numeric replyTable[] = { /* 409 */ { ERR_NOORIGIN, ":No origin specified", "409" }, /* 410 */ - { 0 }, + { ERR_UNKNOWNCAPCMD, "%s :Unknown CAP subcommand", "410" }, /* 411 */ { ERR_NORECIPIENT, ":No recipient given (%s)", "411" }, /* 412 */ diff --git a/ircd/s_user.c b/ircd/s_user.c index 00e4c08..1f26e6f 100644 --- a/ircd/s_user.c +++ b/ircd/s_user.c @@ -408,6 +408,7 @@ int register_user(struct Client *cptr, struct Client *sptr, static time_t last_too_many2; assert(cptr == sptr); + assert(cli_unreg(sptr) == 0); if (!IsIAuthed(sptr)) { if (iauth_active) return iauth_start_client(iauth_active, sptr); @@ -867,6 +868,8 @@ int set_nick_name(struct Client* cptr, struct Client* sptr, } hAddClient(sptr); + cli_unreg(sptr) &= ~CLIREG_NICK; /* nickname now set */ + /* * If the client hasn't gotten a cookie-ping yet, * choose a cookie and send it. -record!jegelhof@cloud9.net @@ -877,7 +880,7 @@ int set_nick_name(struct Client* cptr, struct Client* sptr, } while (!cli_cookie(sptr)); sendrawto_one(cptr, MSG_PING " :%u", cli_cookie(sptr)); } - else if (*(cli_user(sptr))->host && cli_cookie(sptr) == COOKIE_VERIFIED) { + else if (!cli_unreg(sptr)) { /* * USER and PONG already received, now we have NICK. * register_user may reject the client and call exit_client -- 2.20.1