commit 1d7e99531a6f713a04bbc91a6f7f2963c9ece75c from: Alexander Barton date: Fri Apr 27 22:36:41 2012 UTC "multi-prefix" capability 1/2: implement complete CAP infrastructure Now ngIRCd is able to handle "CAP LS", "CAP REQ", "CAP LIST", and "CAP CLEAR" commands. "multi-prefix" can be set/unset, but has no functionality - yet! commit - f0a9dbe3ad59d3518f406f0b32a90246977ac58e commit + 1d7e99531a6f713a04bbc91a6f7f2963c9ece75c blob - e477dc004ea13a1965c8f39608149b79345bb582 blob + 5532d3310aa0df658f7f58580bb1ccf8aed742b1 --- src/ngircd/client-cap.h +++ src/ngircd/client-cap.h @@ -20,6 +20,8 @@ #define CLIENT_CAP_PENDING 1 /* Capability negotiation pending */ #define CLIENT_CAP_SUPPORTED 2 /* Client supports IRC capabilities */ +#define CLIENT_CAP_MULTI_PREFIX 4 /* multi-prefix */ + GLOBAL int Client_Cap PARAMS((CLIENT *Client)); GLOBAL void Client_CapSet PARAMS((CLIENT *Client, int Cap)); blob - c92a3f392dd38fea3a3aa53ab225460dc3898ff2 blob + a6923ac62da0425548b81398d9935afab36d2512 --- src/ngircd/irc-cap.c +++ src/ngircd/irc-cap.c @@ -42,6 +42,8 @@ bool Handle_CAP_END PARAMS((CLIENT *Client)); void Set_CAP_Negotiation PARAMS((CLIENT *Client)); +int Parse_CAP PARAMS((int Capabilities, char *Args)); +char *Get_CAP_String PARAMS((int Capabilities)); /** * Handler for the IRCv3 "CAP" command. @@ -101,7 +103,9 @@ Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg) Set_CAP_Negotiation(Client); - return IRC_WriteStrClient(Client, "CAP %s LS :", Client_ID(Client)); + return IRC_WriteStrClient(Client, + "CAP %s LS :multi-prefix", + Client_ID(Client)); } /** @@ -116,7 +120,8 @@ Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg) { assert(Client != NULL); - return IRC_WriteStrClient(Client, "CAP %s LIST :", Client_ID(Client)); + return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client), + Get_CAP_String(Client_Cap(Client))); } /** @@ -129,12 +134,21 @@ Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg) bool Handle_CAP_REQ(CLIENT *Client, char *Arg) { + int new_cap; + assert(Client != NULL); assert(Arg != NULL); Set_CAP_Negotiation(Client); - return IRC_WriteStrClient(Client, "CAP %s NAK :%s", + new_cap = Parse_CAP(Client_Cap(Client), Arg); + + if (new_cap < 0) + return IRC_WriteStrClient(Client, "CAP %s NAK :%s", + Client_ID(Client), Arg); + + Client_CapSet(Client, new_cap); + return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client), Arg); } @@ -163,9 +177,16 @@ Handle_CAP_ACK(CLIENT *Client, char *Arg) bool Handle_CAP_CLEAR(CLIENT *Client) { + int cap_old; + assert(Client != NULL); - return IRC_WriteStrClient(Client, "CAP %s ACK :", Client_ID(Client)); + cap_old = Client_Cap(Client); + if (cap_old & CLIENT_CAP_MULTI_PREFIX) + Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX); + + return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client), + Get_CAP_String(cap_old)); } /** @@ -207,4 +228,64 @@ Set_CAP_Negotiation(CLIENT *Client) Client_CapAdd(Client, CLIENT_CAP_SUPPORTED); } +/** + * Parse capability string and return numeric flag value. + * + * @param Args The string containing space-separated capability names. + * @return Changed capability flags or 0 on error. + */ +int +Parse_CAP(int Capabilities, char *Args) +{ + static char tmp[COMMAND_LEN]; + char *ptr; + + assert(Args != NULL); + + strlcpy(tmp, Args, sizeof(tmp)); + + ptr = strtok(tmp, " "); + while (ptr) { + if (*ptr == '-') { + /* drop capabilities */ + ptr++; + if (strcmp(ptr, "multi-prefix") == 0) + Capabilities &= ~CLIENT_CAP_MULTI_PREFIX; + else + return -1; + } else { + /* request capabilities */ + if (strcmp(ptr, "multi-prefix") == 0) + Capabilities |= CLIENT_CAP_MULTI_PREFIX; + else + return -1; + } + ptr = strtok(NULL, " "); + } + + return Capabilities; +} + +/** + * Return textual representation of capability flags. + * + * Please note: this function returns a pointer to a global buffer and + * therefore isn't thread safe! + * + * @param Capabilities Capability flags (bitmask). + * @return Pointer to textual representation. + */ +char +*Get_CAP_String(int Capabilities) +{ + static char txt[COMMAND_LEN]; + + txt[0] = '\0'; + + if (Capabilities & CLIENT_CAP_MULTI_PREFIX) + strlcat(txt, "multi-prefix ", sizeof(txt)); + + return txt; +} + /* -eof- */