commit - f0a9dbe3ad59d3518f406f0b32a90246977ac58e
commit + 1d7e99531a6f713a04bbc91a6f7f2963c9ece75c
blob - e477dc004ea13a1965c8f39608149b79345bb582
blob + 5532d3310aa0df658f7f58580bb1ccf8aed742b1
--- src/ngircd/client-cap.h
+++ src/ngircd/client-cap.h
#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
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.
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));
}
/**
{
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)));
}
/**
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);
}
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));
}
/**
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- */