diff options
Diffstat (limited to '')
-rw-r--r-- | bounce.h | 55 | ||||
-rw-r--r-- | client.c | 18 |
2 files changed, 64 insertions, 9 deletions
diff --git a/bounce.h b/bounce.h index aa7fda1..5dd2536 100644 --- a/bounce.h +++ b/bounce.h @@ -35,8 +35,6 @@ typedef unsigned char byte; -bool verbose; - enum { ParamCap = 15 }; struct Message { char *origin; @@ -58,6 +56,59 @@ static inline struct Message parse(char *line) { return msg; } +#define ENUM_CAP \ + X("account-notify", CapAccountNotify) \ + X("away-notify", CapAwayNotify) \ + X("chghost", CapChghost) \ + X("extended-join", CapExtendedJoin) \ + X("invite-notify", CapInviteNotify) \ + X("server-time", CapServerTime) \ + X("", CapUnsupported) + +enum Cap { +#define X(name, id) BIT(id), + ENUM_CAP +#undef X +}; + +static const char *CapNames[] = { +#define X(name, id) [id##Bit] = name, + ENUM_CAP +#undef X +}; + +static inline enum Cap capParse(const char *list) { + enum Cap caps = 0; + while (*list) { + enum Cap cap = CapUnsupported; + size_t len = strcspn(list, " "); + for (size_t i = 0; i < ARRAY_LEN(CapNames); ++i) { + if (len != strlen(CapNames[i])) continue; + if (strncmp(list, CapNames[i], len)) continue; + cap = 1 << i; + break; + } + caps |= cap; + list += len; + if (*list) list++; + } + return caps; +} + +static inline const char *capList(enum Cap caps) { + static char buf[1024]; + buf[0] = '\0'; + for (size_t i = 0; i < ARRAY_LEN(CapNames); ++i) { + if (caps & (1 << i)) { + if (buf[0]) strlcat(buf, " ", sizeof(buf)); + strlcat(buf, CapNames[i], sizeof(buf)); + } + } + return buf; +} + +bool verbose; + void ringAlloc(size_t len); void ringProduce(const char *line); size_t ringConsumer(const char *name); diff --git a/client.c b/client.c index 6ac0869..9bbc5d9 100644 --- a/client.c +++ b/client.c @@ -41,7 +41,7 @@ struct Client { struct tls *tls; enum Need need; size_t consumer; - bool serverTime; + enum Cap caps; char buf[1024]; size_t len; bool error; @@ -158,13 +158,17 @@ static void handleCap(struct Client *client, struct Message *msg) { } else if (!strcmp(msg->params[0], "LS")) { if (client->need) client->need |= NeedCapEnd; - clientFormat(client, ":%s CAP * LS :server-time\r\n", ORIGIN); + clientFormat( + client, ":%s CAP * LS :%s\r\n", + ORIGIN, capList(CapServerTime) + ); } else if (!strcmp(msg->params[0], "REQ") && msg->params[1]) { if (client->need) client->need |= NeedCapEnd; - if (!strcmp(msg->params[1], "server-time")) { - client->serverTime = true; - clientFormat(client, ":%s CAP * ACK :server-time\r\n", ORIGIN); + enum Cap caps = capParse(msg->params[1]); + if (caps == CapServerTime) { + client->caps |= caps; + clientFormat(client, ":%s CAP * ACK :%s\r\n", ORIGIN, msg->params[1]); } else { clientFormat(client, ":%s CAP * NAK :%s\r\n", ORIGIN, msg->params[1]); } @@ -172,7 +176,7 @@ static void handleCap(struct Client *client, struct Message *msg) { } else if (!strcmp(msg->params[0], "LIST")) { clientFormat( client, ":%s CAP * LIST :%s\r\n", - ORIGIN, (client->serverTime ? "server-time" : "") + ORIGIN, capList(client->caps) ); } else { @@ -277,7 +281,7 @@ void clientConsume(struct Client *client) { time_t time; const char *line = ringPeek(&time, client->consumer); if (!line) return; - if (client->serverTime) { + if (client->caps & CapServerTime) { char ts[sizeof("YYYY-MM-DDThh:mm:ss.sssZ")]; struct tm *tm = gmtime(&time); strftime(ts, sizeof(ts), "%FT%T.000Z", tm); |