From: Michael Poole Date: Tue, 5 Apr 2005 01:46:05 +0000 (+0000) Subject: Make CAP handling comply with draft-mitchell-irc-capabilities-02.xml. X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=commitdiff_plain;h=3958ee0d914adea3583394c87f0ac1619f663d15 Make CAP handling comply with draft-mitchell-irc-capabilities-02.xml. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1349 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- diff --git a/ChangeLog b/ChangeLog index b847ef0..4ffac10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2005-04-04 Michael Poole + + * 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 * include/s_conf.h (SMAP_FAST): Define. diff --git a/include/capab.h b/include/capab.h index 5ec44d2..d2c07de 100644 --- a/include/capab.h +++ b/include/capab.h @@ -30,615 +30,10 @@ #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 { diff --git a/include/client.h b/include/client.h index f6c2244..06cdcfb 100644 --- a/include/client.h +++ b/include/client.h @@ -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 */ }; diff --git a/ircd/m_cap.c b/ircd/m_cap.c index 1231c7d..a415933 100644 --- a/ircd/m_cap.c +++ b/ircd/m_cap.c @@ -18,66 +18,12 @@ * 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] = [] - * parv[2] = [] - * +/** 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];