X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Firc-cap.c;h=2ea4c9af135f6a9309be449924946bd6ca6ae879;hb=bcefdef1eaed14d3156b7fb5b9ad6d3b7078efcf;hp=956b359930330347df3b601b8418ca762359f63f;hpb=da4c1ebe81bbd1335356ef40c91741b953c9f8d8;p=ngircd-alex.git diff --git a/src/ngircd/irc-cap.c b/src/ngircd/irc-cap.c index 956b3599..2ea4c9af 100644 --- a/src/ngircd/irc-cap.c +++ b/src/ngircd/irc-cap.c @@ -40,6 +40,11 @@ bool Handle_CAP_ACK PARAMS((CLIENT *Client, char *Arg)); bool Handle_CAP_CLEAR PARAMS((CLIENT *Client)); 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. * @@ -96,11 +101,11 @@ Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg) { assert(Client != NULL); - if (Client_Type(Client) != CLIENT_USER) - Client_CapAdd(Client, CLIENT_CAP_PENDING); + Set_CAP_Negotiation(Client); - Client_CapAdd(Client, CLIENT_CAP_SUPPORTED); - return IRC_WriteStrClient(Client, "CAP %s LS :", Client_ID(Client)); + return IRC_WriteStrClient(Client, + "CAP %s LS :multi-prefix", + Client_ID(Client)); } /** @@ -115,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))); } /** @@ -128,10 +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); - return IRC_WriteStrClient(Client, "CAP %s NAK :%s", + Set_CAP_Negotiation(Client); + + 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); } @@ -143,7 +160,7 @@ Handle_CAP_REQ(CLIENT *Client, char *Arg) * @returns CONNECTED or DISCONNECTED. */ bool -Handle_CAP_ACK(CLIENT *Client, char *Arg) +Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg) { assert(Client != NULL); assert(Arg != NULL); @@ -160,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)); } /** @@ -189,4 +213,79 @@ Handle_CAP_END(CLIENT *Client) return CONNECTED; } +/** + * Set CAP negotiation status and mark client as "supports capabilities". + * + * @param Client The client to handle. + */ +void +Set_CAP_Negotiation(CLIENT *Client) +{ + assert(Client != NULL); + + if (Client_Type(Client) != CLIENT_USER) + Client_CapAdd(Client, CLIENT_CAP_PENDING); + 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- */