X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/9b24cbdecc72337e825764f39cdf59ca23f41788..83f7888d72cf1faba78a4c9ed9df4780b11534b3:/modules/m_cap.c diff --git a/modules/m_cap.c b/modules/m_cap.c index a1dd5b29..3d6355bf 100644 --- a/modules/m_cap.c +++ b/modules/m_cap.c @@ -2,7 +2,7 @@ * * Copyright (C) 2005 Lee Hardy * Copyright (C) 2005 ircd-ratbox development team - * Copyright (C) 2016 William Pitcock + * Copyright (C) 2016 Ariadne Conill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -152,66 +152,83 @@ clicap_find(const char *data, int *negate, int *finished) static void clicap_generate(struct Client *source_p, const char *subcmd, int flags) { - char buf[BUFSIZE] = { 0 }; - char capbuf[BUFSIZE] = { 0 }; - int buflen = 0; - int mlen; + const char *str_cont = "* :"; + const char *str_final = ":"; struct CapabilityEntry *entry; rb_dictionary_iter iter; + bool multiline_ret; + enum multiline_item_result multiline_item_ret; - mlen = snprintf(buf, sizeof buf, ":%s CAP %s %s", + multiline_ret = send_multiline_init(source_p, " ", ":%s CAP %s %s %s", me.name, EmptyString(source_p->name) ? "*" : source_p->name, - subcmd); + subcmd, + (source_p->flags & FLAGS_CLICAP_DATA) ? str_cont : str_final); /* shortcut, nothing to do */ - if(flags == -1) - { - sendto_one(source_p, "%s :", buf); + if (flags == -1 || !multiline_ret) { + sendto_one(source_p, ":%s CAP %s %s %s", + me.name, + EmptyString(source_p->name) ? "*" : source_p->name, + subcmd, + str_final); return; } - RB_DICTIONARY_FOREACH(entry, &iter, cli_capindex->cap_dict) - { - size_t caplen = 0; + for (int pass = 0; pass < 2; pass++) + RB_DICTIONARY_FOREACH(entry, &iter, cli_capindex->cap_dict) { struct ClientCapability *clicap = entry->ownerdata; const char *data = NULL; - if(flags && !IsCapableEntry(source_p, entry)) + if (pass == 0 && !HasCapabilityFlag(entry, CLICAP_FLAGS_PRIORITY)) + continue; + else if (pass == 1 && HasCapabilityFlag(entry, CLICAP_FLAGS_PRIORITY)) continue; - if (!clicap_visible(source_p, entry)) + if (!IsCapableEntry(source_p, entry) && ConfigFileEntry.hidden_caps != NULL) + { + size_t i; + for (i = 0; ConfigFileEntry.hidden_caps[i] != NULL; i++) + { + if (!rb_strcasecmp(entry->cap, ConfigFileEntry.hidden_caps[i])) + break; + } + if (ConfigFileEntry.hidden_caps[i] != NULL) + continue; + } + + if (flags && !IsCapableEntry(source_p, entry)) continue; - caplen = strlen(entry->cap); - if (!flags && (source_p->flags & FLAGS_CLICAP_DATA) && clicap != NULL && clicap->data != NULL) - data = clicap->data(source_p); + if (!clicap_visible(source_p, entry)) + continue; - if (data != NULL) - caplen += strlen(data) + 1; + if (source_p->flags & FLAGS_CLICAP_DATA) { + if (!flags && clicap != NULL && clicap->data != NULL) + data = clicap->data(source_p); - /* \r\n\0, possible "-~=", space, " *" */ - if(buflen + mlen >= BUFSIZE - 10) - { - /* remove our trailing space -- if buflen == mlen - * here, we didnt even succeed in adding one. - */ - capbuf[buflen] = '\0'; + multiline_item_ret = send_multiline_item(source_p, "%s%s%s", + entry->cap, + data != NULL ? "=" : "", + data != NULL ? data : ""); - sendto_one(source_p, "%s * :%s", buf, capbuf); + if (multiline_item_ret == MULTILINE_FAILURE) + return; + } else { + multiline_item_ret = send_multiline_item(source_p, "%s", entry->cap); - buflen = mlen; - memset(capbuf, 0, sizeof capbuf); + if (multiline_item_ret != MULTILINE_SUCCESS) { + send_multiline_reset(); + return; + } } - - buflen = rb_snprintf_append(capbuf, sizeof capbuf, "%s%s%s ", - entry->cap, data != NULL ? "=" : "", data != NULL ? data : ""); } - /* remove trailing space */ - capbuf[buflen] = '\0'; - - sendto_one(source_p, "%s :%s", buf, capbuf); + send_multiline_fini(source_p, ":%s CAP %s %s %s", + me.name, + EmptyString(source_p->name) ? "*" : source_p->name, + subcmd, + str_final); } static void @@ -272,11 +289,16 @@ cap_list(struct Client *source_p, const char *arg) static void cap_ls(struct Client *source_p, const char *arg) { + int caps_version = 301; + if(!IsRegistered(source_p)) source_p->flags |= FLAGS_CLICAP; - if (arg != NULL && !strcmp(arg, "302")) - { + if (!EmptyString(arg)) { + caps_version = atoi(arg); + } + + if (caps_version >= 302) { source_p->flags |= FLAGS_CLICAP_DATA; source_p->localClient->caps |= CLICAP_CAP_NOTIFY; } @@ -288,13 +310,12 @@ cap_ls(struct Client *source_p, const char *arg) static void cap_req(struct Client *source_p, const char *arg) { - char buf[BUFSIZE]; - char pbuf[2][BUFSIZE]; + char ack_buf[DATALEN+1]; struct CapabilityEntry *cap; - int buflen, plen; - int i = 0; int capadd = 0, capdel = 0; int finished = 0, negate; + int ret; + hook_data_cap_change hdata; if(!IsRegistered(source_p)) source_p->flags |= FLAGS_CLICAP; @@ -302,28 +323,19 @@ cap_req(struct Client *source_p, const char *arg) if(EmptyString(arg)) return; - buflen = snprintf(buf, sizeof(buf), ":%s CAP %s ACK", - me.name, EmptyString(source_p->name) ? "*" : source_p->name); + ret = snprintf(ack_buf, sizeof ack_buf, ":%s CAP %s ACK :%s", + me.name, EmptyString(source_p->name)? "*" : source_p->name, arg); - pbuf[0][0] = '\0'; - plen = 0; + if (ret < 0 || ret > DATALEN) + { + sendto_one(source_p, ":%s CAP %s NAK :%s", + me.name, EmptyString(source_p->name) ? "*" : source_p->name, arg); + return; + } for(cap = clicap_find(arg, &negate, &finished); cap; cap = clicap_find(NULL, &negate, &finished)) { - size_t namelen = strlen(cap->cap); - - /* filled the first array, but cant send it in case the - * request fails. one REQ should never fill more than two - * buffers --fl - */ - if(buflen + plen + namelen + 6 >= BUFSIZE) - { - pbuf[1][0] = '\0'; - plen = 0; - i = 1; - } - if(negate) { if(HasCapabilityFlag(cap, CLICAP_FLAGS_STICKY)) @@ -332,9 +344,6 @@ cap_req(struct Client *source_p, const char *arg) break; } - strcat(pbuf[i], "-"); - plen++; - capdel |= (1 << cap->value); } else @@ -348,18 +357,6 @@ cap_req(struct Client *source_p, const char *arg) capadd |= (1 << cap->value); } - /* XXX this probably should exclude REQACK'd caps from capadd/capdel, but keep old behaviour for now */ - if(HasCapabilityFlag(cap, CLICAP_FLAGS_REQACK)) - { - strcat(pbuf[i], "~"); - plen++; - } - - strcat(pbuf[i], cap->cap); - if (!finished) { - strcat(pbuf[i], " "); - plen += (namelen + 1); - } } if(!finished) @@ -369,16 +366,17 @@ cap_req(struct Client *source_p, const char *arg) return; } - if(i) - { - sendto_one(source_p, "%s * :%s", buf, pbuf[0]); - sendto_one(source_p, "%s :%s", buf, pbuf[1]); - } - else - sendto_one(source_p, "%s :%s", buf, pbuf[0]); + sendto_one(source_p, "%s", ack_buf); + + hdata.client = source_p; + hdata.oldcaps = source_p->localClient->caps; + hdata.add = capadd; + hdata.del = capdel; source_p->localClient->caps |= capadd; source_p->localClient->caps &= ~capdel; + + call_hook(h_cap_change, &hdata); } static struct clicap_cmd