Make CAP handling comply with draft-mitchell-irc-capabilities-02.xml.
authorMichael Poole <mdpoole@troilus.org>
Tue, 5 Apr 2005 01:46:05 +0000 (01:46 +0000)
committerMichael Poole <mdpoole@troilus.org>
Tue, 5 Apr 2005 01:46:05 +0000 (01:46 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1349 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
include/capab.h
include/client.h
ircd/m_cap.c

index b847ef0c2fbcba76017dc313337ee93e3813d63a..4ffac104c1887f8289569f134124e4d1477275d4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2005-04-04  Michael Poole <mdpoole@troilus.org>
+
+       * include/capab.h (CAPFL_STICKY): Define.
+       (CAPLIST): Remove the entries used for testing.
+
+       * include/client.h (Connection): Clarify comment about the
+       distinction between con_capab and con_active.
+
+       * ircd/m_cap.c: Add doxygen comments and replace the long
+       discussion of m_handler functions with an xref to it.
+       (send_caplist): Add new parameters and change the terminal vs
+       non-terminal line distinction to make compliant with current draft
+       specification.
+       (cap_empty): Rename to cap_ls().
+       (cap_req): Track modified capabilities bitwise, so that the
+       responding ACK contains all the appropriate flags.
+       (cap_ack): Add comment explaining why there is no response.
+       (cap_clear): Build and send a list of cleared capabilities, as
+       required by the current draft.
+       (cap_list): Send capability list using LIST subcommand.
+       (cmdlist): Add handler for LS subcommand.  Remove entries for the
+       empty and LSL subcommands, which are no longer allowed.
+       (m_cap): Require at least one argument from user.
+
 2005-04-01  Michael Poole <mdpoole@troilus.org>
 
        * include/s_conf.h (SMAP_FAST): Define.
index 5ec44d27e13f336f59e4a0ecfa3d7cab5a8286f5..d2c07debdd8760903c049605700b75ae7440df07 100644 (file)
 #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 */
+#define CAPFL_STICKY    0x0008  /**< Cap may not be cleared once set */
 
-/* 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")
+#define CAPLIST        \
+       _CAP(USERPFX, 0, "undernet.org/userpfx")
 
 /** Client capabilities */
 enum Capab {
index f6c2244d4fe93a22f9ac90cfac6f3db29b9adbcd..06cdcfbab3e8ee1e28d09218677fc14f54cf97c3 100644 (file)
@@ -233,8 +233,8 @@ struct Connection
   struct Timer        con_proc;      /**< process latent messages from
                                       client */
   struct Privs        con_privs;     /**< Oper privileges */
-  struct CapSet       con_capab;     /**< Client capabilities */
-  struct CapSet       con_active;    /**< Active client capabilities */
+  struct CapSet       con_capab;     /**< Client capabilities (from us) */
+  struct CapSet       con_active;    /**< Active capabilities (to us) */
   struct AuthRequest* con_auth;      /**< auth request for client */
   struct IAuthRequest* con_iauth;    /**< iauth request for client */
 };
index 1231c7d04b25728d211a5977aa3e952b04bb4e54..a41593306cd0e7d66b760592955cedf4f5b56faa 100644 (file)
  * 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.
+/** @file
+ * @brief Capability negotiation commands
+ * @version $Id$
  */
+
 #include "config.h"
 
 #include "client.h"
@@ -112,8 +58,6 @@ static struct capabilities {
 
 #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)
 {
@@ -183,33 +127,62 @@ find_cap(const char **caplist_p, int *neg_p)
   return cap; /* and return the capability (if any) */
 }
 
+/** Send a CAP \a subcmd list of capability changes to \a sptr.
+ * If more than one line is necessary, each line before the last has
+ * an added "*" parameter before that line's capability list.
+ * @param[in] sptr Client receiving capability list.
+ * @param[in] set Capabilities to show as set (with ack and sticky modifiers).
+ * @param[in] rem Capabalities to show as removed (with no other modifier).
+ * @param[in] subcmd Name of capability subcommand.
+ */
 static int
-send_caplist(struct Client *sptr, const struct CapSet *cs)
+send_caplist(struct Client *sptr, const struct CapSet *set,
+             const struct CapSet *rem, const char *subcmd)
 {
-  char capbuf[BUFSIZE] = "";
+  char capbuf[BUFSIZE] = "", pfx[16];
   struct MsgBuf *mb;
-  int i, loc, len;
+  int i, loc, len, flags, pfx_len;
 
-  /* set up the buffer for the LSL message... */
-  mb = msgq_make(sptr, "%:#C " MSG_CAP " LSL :", &me);
+  /* set up the buffer for the final LS message... */
+  mb = msgq_make(sptr, "%:#C " MSG_CAP " %s :", &me, subcmd);
 
   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);
+    flags = capab_list[i].flags;
+    /* This is a little bit subtle, but just involves applying de
+     * Morgan's laws to the obvious check: We must display the
+     * capability if (and only if) it is set in \a rem or \a set, or
+     * if both are null and the capability is hidden.
+     */
+    if (!(rem && CapHas(rem, capab_list[i].cap))
+        && !(set && CapHas(set, capab_list[i].cap))
+        && (rem || set || (flags & CAPFL_HIDDEN)))
+      continue;
+
+    /* Build the prefix (space separator and any modifiers needed). */
+    pfx_len = 0;
+    if (loc)
+      pfx[pfx_len++] = ' ';
+    if (rem && CapHas(rem, capab_list[i].cap))
+        pfx[pfx_len++] = '-';
+    else {
+      if (flags & CAPFL_PROTO)
+        pfx[pfx_len++] = '~';
+      if (flags & CAPFL_STICKY)
+        pfx[pfx_len++] = '=';
+    }
+    pfx[pfx_len] = '\0';
+
+    len = capab_list[i].namelen + pfx_len; /* how much we'd add... */
+    if (msgq_bufleft(mb) < loc + len + 2) { /* would add too much; must flush */
+      sendcmdto_one(&me, CMD_CAP, sptr, "%s * :%s", subcmd, 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);
+                        pfx, capab_list[i].name);
   }
 
-  msgq_append(0, mb, "%s", capbuf); /* append capabilities to the LSL cmd */
+  msgq_append(0, mb, "%s", capbuf); /* append capabilities to the final cmd */
   send_buffer(sptr, mb, 0); /* send them out... */
   msgq_clean(mb); /* and release the buffer */
 
@@ -217,12 +190,12 @@ send_caplist(struct Client *sptr, const struct CapSet *cs)
 }
 
 static int
-cap_empty(struct Client *sptr, const char *caplist)
+cap_ls(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 */
+  return send_caplist(sptr, 0, 0, "LS"); /* send list of capabilities */
 }
 
 static int
@@ -230,6 +203,7 @@ cap_req(struct Client *sptr, const char *caplist)
 {
   const char *cl = caplist;
   struct capabilities *cap;
+  struct CapSet set, rem;
   struct CapSet cs = *cli_capab(sptr); /* capability set */
   struct CapSet as = *cli_active(sptr); /* active set */
   int neg;
@@ -237,27 +211,34 @@ cap_req(struct Client *sptr, const char *caplist)
   if (IsUnknown(sptr)) /* registration hasn't completed; suspend it... */
     cli_unreg(sptr) |= CLIREG_CAP;
 
+  memset(&set, 0, sizeof(set));
+  memset(&rem, 0, sizeof(rem));
   while (cl) { /* walk through the capabilities list... */
-    if (!(cap = find_cap(&cl, &neg)) || /* look up capability... */
-       (!neg && (cap->flags & CAPFL_PROHIBIT))) { /* is it prohibited? */
+    if (!(cap = find_cap(&cl, &neg)) /* look up capability... */
+       || (!neg && (cap->flags & CAPFL_PROHIBIT)) /* is it prohibited? */
+        || (neg && (cap->flags & CAPFL_STICKY))) { /* is it sticky? */
       sendcmdto_one(&me, CMD_CAP, sptr, "NAK :%s", caplist);
       return 0; /* can't complete requested op... */
     }
 
     if (neg) { /* set or clear the capability... */
+      CapSet(&rem, cap->cap);
+      CapClr(&set, cap->cap);
       CapClr(&cs, cap->cap);
       if (!(cap->flags & CAPFL_PROTO))
        CapClr(&as, cap->cap);
     } else {
+      CapClr(&rem, cap->cap);
+      CapSet(&set, cap->cap);
       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 */
+  /* Notify client of accepted changes and copy over results. */
+  send_caplist(sptr, &set, &rem, "ACK");
+  *cli_capab(sptr) = cs;
   *cli_active(sptr) = as;
 
   return 0;
@@ -270,6 +251,10 @@ cap_ack(struct Client *sptr, const char *caplist)
   struct capabilities *cap;
   int neg;
 
+  /* Coming from the client, this generally indicates that the client
+   * is using a new backwards-incompatible protocol feature.  As such,
+   * it does not require further response from the server.
+   */
   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... */
@@ -287,9 +272,24 @@ cap_ack(struct Client *sptr, const char *caplist)
 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! */
+  struct CapSet cleared;
+  struct capabilities *cap;
+  unsigned int ii;
+
+  /* XXX: If we ever add a capab list sorted by capab value, it would
+   * be good cache-wise to use it here. */
+  memset(&cleared, 0, sizeof(cleared));
+  for (ii = 0; ii < CAPAB_LIST_LEN; ++ii) {
+    cap = &capab_list[ii];
+    /* Only clear active non-sticky capabilities. */
+    if (!HasCap(sptr, cap->cap) || (cap->flags & CAPFL_STICKY))
+      continue;
+    CapSet(&cleared, cap->cap);
+    CapClr(cli_capab(sptr), cap->cap);
+    if (!(cap->flags & CAPFL_PROTO))
+      CapClr(cli_active(sptr), cap->cap);
+  }
+  send_caplist(sptr, 0, &cleared, "ACK");
 
   return 0;
 }
@@ -312,20 +312,18 @@ 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));
+  return send_caplist(sptr, cli_capab(sptr), 0, "LIST");
 }
 
 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         },
+  { "LS",    cap_ls    },
   { "NAK",   0         },
   { "REQ",   cap_req   }
 };
@@ -336,25 +334,22 @@ 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] = [<subcommand>]
- * parv[2] = [<capab list>]
- *
+/** Handle a capability request or response from a client.
+ * @param[in] cptr Client that sent us the message.
+ * @param[in] sptr Original source of message.
+ * @param[in] parc Number of arguments.
+ * @param[in] parv Argument vector.
+ * @see \ref m_functions
  */
 int
 m_cap(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-  char *subcmd = "", *caplist = 0;
+  char *subcmd, *caplist = 0;
   struct subcmd *cmd;
 
-  if (parc > 1 && parv[1]) /* a subcommand was provided */
-    subcmd = parv[1];
+  if (parc < 2) /* a subcommand is required */
+    return 0;
+  subcmd = parv[1];
   if (parc > 2) /* a capability list was provided */
     caplist = parv[2];