X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fnumnicks.c;h=66e432135d23db284df65b3e1c1b0a03518bd2c8;hb=refs%2Fheads%2Fupstream-ssl;hp=09b904cebc287f85f2b23e83559886d9a478a4c1;hpb=b70944c4b84fc2b707d0853ddf03975569dac2bd;p=ircu2.10.12-pk.git diff --git a/ircd/numnicks.c b/ircd/numnicks.c index 09b904c..66e4321 100644 --- a/ircd/numnicks.c +++ b/ircd/numnicks.c @@ -16,78 +16,88 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/** @file + * @brief Implementation of numeric nickname operations. + * @version $Id$ + */ +#include "config.h" #include "numnicks.h" - -#include "sys.h" -#include "h.h" -#include "s_serv.h" -#include "struct.h" -#include "common.h" +#include "client.h" #include "ircd.h" -#include "s_misc.h" +#include "ircd_alloc.h" +#include "ircd_log.h" +#include "ircd_string.h" #include "match.h" #include "s_bsd.h" #include "s_debug.h" +#include "s_misc.h" +#include "struct.h" -#include +/* #include -- Now using assert in ircd_log.h */ +#include +#include +#include -RCSTAG_CC("$Id$"); -/* - * Numeric nicks are new as of version ircu2.10.00beta1. +/** @page numnicks Numeric Nicks + * %Numeric nicks (numnicks) are new as of version ircu2.10.00beta1. * * The idea is as follows: * In most messages (for protocol 10+) the original nick will be - * replaced by a 3 character string: YXX - * Where 'Y' represents the server, and 'XX' the nick on that server. + * replaced by a 5 character string: YYXXX + * Where 'YY' represents the server, and 'XXX' the nick on that server. * - * 'YXX' should not interfer with the input parser, and therefore is + * 'YYXXX' should not interfere with the input parser, and therefore is * not allowed to contain spaces or a ':'. - * Also, 'Y' can't start with a '+' because of m_server(). + * Also, 'YY' can't start with a '+' because of m_server(). * * We keep the characters printable for debugging reasons too. * - * The 'XX' value can be larger then the maximum number of clients - * per server, we use a mask (struct Server::nn_mask) to get the real + * The 'XXX' value can be larger then the maximum number of clients + * per server, we use a mask (Server::nn_mask) to get the real * client numeric. The overhead is used to have some redundancy so * just-disconnected-client aren't confused with just-connected ones. */ -/* - * when n2k comes, define this for more capacity - */ -#undef EXTENDED_NUMERICS /* These must be the same on ALL servers ! Do not change ! */ +/** Number of bits encoded in one numnick character. */ #define NUMNICKLOG 6 -#define NUMNICKMAXCHAR 'z' /* See convert2n[] */ -#define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */ -#define NUMNICKMASK 63 /* (NUMNICKBASE-1) */ -#define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */ +/** Bitmask to select value of next numnick character. */ +#define NUMNICKMASK 63 /* (NUMNICKBASE-1) */ +/** Number of servers representable in a numnick. */ +#define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */ +/** Number of clients representable in a numnick. */ +#define NN_MAX_CLIENT 262144 /* NUMNICKBASE ^ 3 */ /* * The internal counter for the 'XX' of local clients */ +/** Maximum used server numnick, plus one. */ static unsigned int lastNNServer = 0; -static struct Client *server_list[NN_MAX_SERVER]; +/** Array of servers indexed by numnick. */ +static struct Client* server_list[NN_MAX_SERVER]; /* *INDENT-OFF* */ -/* - * convert2y[] converts a numeric to the corresponding character. +/** + * Converts a numeric to the corresponding character. * The following characters are currently known to be forbidden: * - * '\0' : Because we use '\0' as end of line. + * '\\0' : Because we use '\\0' as end of line. + * + * ' ' : Because parse_*() uses this as parameter separator. + * + * ':' : Because parse_server() uses this to detect if a prefix is a + * numeric or a name. * - * ' ' : Because parse_*() uses this as parameter seperator. - * ':' : Because parse_server() uses this to detect if a prefix is a - * numeric or a name. - * '+' : Because m_nick() uses this to determine if parv[6] is a - * umode or not. - * '&', '#', '+', '$', '@' and '%' : - * Because m_message() matches these characters to detect special cases. + * '+' : Because m_nick() uses this to determine if parv[6] is a + * umode or not. + * + * '&', '#', '$', '@' and '%' : + * Because m_message() matches these characters to detect special cases. */ static const char convert2y[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', @@ -96,11 +106,12 @@ static const char convert2y[] = { 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']' }; +/** Converts a character to its (base64) numnick value. */ static const unsigned int convert2n[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0, + 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0, 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, @@ -118,30 +129,41 @@ static const unsigned int convert2n[] = { /* *INDENT-ON* */ - -unsigned int base64toint(const char *s) +/** Convert a string to its value as a numnick. + * @param[in] s Numnick string to decode. + * @return %Numeric nickname value. + */ +unsigned int base64toint(const char* s) { - unsigned int i = convert2n[(unsigned char)*s++]; - while (*s) - { + unsigned int i = convert2n[(unsigned char) *s++]; + while (*s) { i <<= NUMNICKLOG; - i += convert2n[(unsigned char)*s++]; + i += convert2n[(unsigned char) *s++]; } return i; } -const char *inttobase64(char *buf, unsigned int v, size_t count) +/** Encode a number as a numnick. + * @param[out] buf Output buffer. + * @param[in] v Value to encode. + * @param[in] count Number of numnick digits to write to \a buf. + */ +const char* inttobase64(char* buf, unsigned int v, unsigned int count) { buf[count] = '\0'; - while (count > 0) - { + while (count > 0) { buf[--count] = convert2y[(v & NUMNICKMASK)]; v >>= NUMNICKLOG; } return buf; } -static struct Client *FindXNServer(const char *numeric) +/** Look up a server by numnick string. + * See @ref numnicks for more details. + * @param[in] numeric %Numeric nickname of server (may contain trailing junk). + * @return %Server with that numnick (or NULL). + */ +static struct Client* FindXNServer(const char* numeric) { char buf[3]; buf[0] = *numeric++; @@ -151,100 +173,85 @@ static struct Client *FindXNServer(const char *numeric) return server_list[base64toint(buf)]; } -struct Client *FindNServer(const char *numeric) +/** Look up a server by numnick string. + * See @ref numnicks for more details. + * @param[in] numeric %Numeric nickname of server. + * @return %Server with that numnick (or NULL). + */ +struct Client* FindNServer(const char* numeric) { - size_t len = strlen(numeric); - if (len < 3) - { + unsigned int len = strlen(numeric); + + if (len < 3) { Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric))); return server_list[base64toint(numeric)]; } - else if (len == 3) - { - Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric, - convert2n[(unsigned char)*numeric])); - return server_list[convert2n[(unsigned char)*numeric]]; + else if (len == 3) { + Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric, + convert2n[(unsigned char) *numeric])); + return server_list[convert2n[(unsigned char) *numeric]]; } return FindXNServer(numeric); } -void RemoveYXXClient(struct Client *server, const char *yxx) +/** Look up a user by numnick string. + * See @ref numnicks for more details. + * @param[in] yxx %Numeric nickname of user. + * @return %User with that numnick (or NULL). + */ +struct Client* findNUser(const char* yxx) +{ + struct Client* server = 0; + if (5 == strlen(yxx)) { + if (0 != (server = FindXNServer(yxx))) { + Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx, + base64toint(yxx + 2) & cli_serv(server)->nn_mask)); + return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask]; + } + } + else if (0 != (server = FindNServer(yxx))) { + Debug((DEBUG_DEBUG, "findNUser: %s(%d)", + yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask)); + return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask]; + } + return 0; +} + +/** Remove a client from a server's user array. + * @param[in] server %Server that owns the user to remove. + * @param[in] yxx Numnick of client to remove. + */ +void RemoveYXXClient(struct Client* server, const char* yxx) { assert(0 != server); assert(0 != yxx); - if (*yxx) - { - unsigned int index = 0; - - if (strlen(yxx) < 3) - index = base64toint(yxx) & server->serv->nn_mask; - else - index = base64toint(yxx); - - Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx, index)); - - if (index < (server->serv->nn_mask + 1)) - server->serv->client_list[index] = NULL; + if (*yxx) { + Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx, + base64toint(yxx) & cli_serv(server)->nn_mask)); + cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0; } } -void SetServerYXX(struct Client *cptr, struct Client *server, const char *yxx) +/** Set a server's numeric nick. + * @param[in] cptr %Client that announced the server (ignored). + * @param[in,out] server %Server that is being assigned a numnick. + * @param[in] yxx %Numeric nickname for server. + */ +void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx) { unsigned int index; -#ifndef NO_PROTOCOL9 - /* Use cptr, because we do protocol 9 -> 10 translation for numeric nicks ! */ - if (Protocol(cptr) > 9) - { -#endif - if (5 == strlen(yxx)) - { - strncpy(server->yxx, yxx, 2); - strncpy(server->serv->nn_capacity, yxx + 2, 3); - } - else - { - server->yxx[0] = yxx[0]; - server->serv->nn_capacity[0] = yxx[1]; - server->serv->nn_capacity[1] = yxx[2]; - } - server->serv->nn_mask = base64toint(server->serv->nn_capacity); - -#ifndef NO_PROTOCOL9 + if (5 == strlen(yxx)) { + ircd_strncpy(cli_yxx(server), yxx, 2); + ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3); } - else - { - static const struct ServerNameNumeric { - const char *name; - unsigned int numeric; - } server_table[] = { - { - "Uworld.undernet.org", 22}, - { - "Uworld2.undernet.org", 23}, - { - "channels.undernet.org", 30}, - { - "channels2.undernet.org", 31}, - { - 0, 0} - }; - int i; - for (i = 0; i < 4; ++i) - { - if (!strCasediff(server_table[i].name, server->name)) - { - /* - * XXX - just use the old format for services for now - */ - *server->yxx = convert2y[server_table[i].numeric]; - inttobase64(server->serv->nn_capacity, 63, 2); - server->serv->nn_mask = 63; - break; - } - } + else { + (cli_yxx(server))[0] = yxx[0]; + cli_serv(server)->nn_capacity[0] = yxx[1]; + cli_serv(server)->nn_capacity[1] = yxx[2]; } -#endif - index = base64toint(server->yxx); + cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity); + + index = base64toint(cli_yxx(server)); if (index >= lastNNServer) lastNNServer = index + 1; server_list[index] = server; @@ -252,171 +259,134 @@ void SetServerYXX(struct Client *cptr, struct Client *server, const char *yxx) /* Note, exit_one_client uses the fact that `client_list' != NULL to * determine that SetServerYXX has been called - and then calls * ClearServerYXX. However, freeing the allocation happens in free_client() */ - server->serv->client_list = - (struct Client **)RunCalloc(server->serv->nn_mask + 1, - sizeof(struct Client *)); + cli_serv(server)->client_list = + (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*)); } -void SetYXXCapacity(struct Client *c, size_t capacity) +/** Set a server's capacity. + * @param[in] c %Server whose capacity is being set. + * @param[in] capacity Maximum number of clients the server supports. + */ +void SetYXXCapacity(struct Client* c, unsigned int capacity) { - unsigned int max_clients; -#if defined(EXTENDED_NUMERICS) - max_clients = capacity - 1; - inttobase64(c->serv->nn_capacity, max_clients, 3); -#else - max_clients = 16; - /* + unsigned int max_clients = 16; + /* * Calculate mask to be used for the maximum number of clients */ - while (capacity >= max_clients) - max_clients = max_clients << 1; + while (max_clients < capacity) + max_clients <<= 1; /* * Sanity checks */ - if (max_clients > NN_MAX_SERVER) - { + if (max_clients > NN_MAX_CLIENT) { fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d " - "too large ! Please decrease this value.\n", - max_clients - NN_MAX_SERVER); + "too large ! Please decrease this value.\n", + max_clients - NN_MAX_CLIENT); exit(-1); } --max_clients; - inttobase64(c->serv->nn_capacity, max_clients, 2); -#endif - c->serv->nn_mask = max_clients; /* Our Numeric Nick mask */ - c->serv->client_list = (struct Client **)RunCalloc(max_clients + 1, - sizeof(struct Client *)); - server_list[base64toint(c->yxx)] = c; + inttobase64(cli_serv(c)->nn_capacity, max_clients, 3); + cli_serv(c)->nn_mask = max_clients; /* Our Numeric Nick mask */ + cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1, + sizeof(struct Client*)); + server_list[base64toint(cli_yxx(c))] = c; } -void SetYXXServerName(struct Client *c, unsigned int numeric) +/** Set a server's numeric nick. + * See @ref numnicks for more details. + * @param[in] c %Server that is being assigned a numnick. + * @param[in] numeric Numnick value for server. + */ +void SetYXXServerName(struct Client* c, unsigned int numeric) { assert(0 != c); assert(numeric < NN_MAX_SERVER); -#if defined(EXTENDED_NUMERICS) - inttobase64(c->yxx, numeric, 2); -#else - assert(numeric < NUMNICKBASE); - c->yxx[0] = convert2y[numeric]; -#endif + inttobase64(cli_yxx(c), numeric, 2); if (numeric >= lastNNServer) lastNNServer = numeric + 1; server_list[numeric] = c; } +/** Unassign a server's numnick. + * @param[in] server %Server that should be removed from the numnick table. + */ void ClearServerYXX(const struct Client *server) { - unsigned int index = base64toint(server->yxx); - if (server_list[index] == server) /* Sanity check */ - server_list[index] = NULL; + unsigned int index = base64toint(cli_yxx(server)); + if (server_list[index] == server) /* Sanity check */ + server_list[index] = 0; } -/* - * SetRemoteNumNick() - * - * Register numeric of new, remote, client. +/** Register numeric of new (remote) client. + * See @ref numnicks for more details. * Add it to the appropriate client_list. + * @param[in] acptr %User being registered. + * @param[in] yxx User's numnick. */ -int SetRemoteNumNick(struct Client *acptr, const char *yxx) +void SetRemoteNumNick(struct Client* acptr, const char *yxx) { - struct Client **acptrp; - struct Client *server = acptr->user->server; - unsigned int index = 0; - - if (5 == strlen(yxx)) - { - strcpy(acptr->yxx, yxx + 2); - index = base64toint(acptr->yxx); + struct Client** acptrp; + struct Client* server = cli_user(acptr)->server; + + if (5 == strlen(yxx)) { + strcpy(cli_yxx(acptr), yxx + 2); } - else - { - acptr->yxx[0] = *++yxx; - acptr->yxx[1] = *++yxx; - acptr->yxx[2] = 0; - index = base64toint(acptr->yxx) & server->serv->nn_mask; + else { + (cli_yxx(acptr))[0] = *++yxx; + (cli_yxx(acptr))[1] = *++yxx; + (cli_yxx(acptr))[2] = 0; } + Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr), + base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask)); - Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", acptr->yxx, index)); - if (index > server->serv->nn_mask) - return 0; - - assert(index <= server->serv->nn_mask); - - acptrp = &server->serv->client_list[index]; - if (*acptrp) - { + acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask]; + if (*acptrp) { /* * this exits the old client in the array, not the client * that is being set */ - exit_client(acptr->from, *acptrp, server, "Numeric nick collision (Ghost)"); + exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)"); } *acptrp = acptr; - return 1; } -/* - * SetLocalNumNick() - * - * Register numeric of new, local, client. Add it to our client_list. +/** Register numeric of new (local) client. + * See @ref numnicks for more details. + * Assign a numnick and add it to our client_list. + * @param[in] cptr %User being registered. */ -void SetLocalNumNick(struct Client *cptr) +int SetLocalNumNick(struct Client *cptr) { - static unsigned int last_nn = 0; - struct Client **client_list = me.serv->client_list; - unsigned int capacity = me.serv->nn_mask + 1; - unsigned int count = 0; + static unsigned int last_nn = 0; + struct Client** client_list = cli_serv(&me)->client_list; + unsigned int mask = cli_serv(&me)->nn_mask; + unsigned int count = 0; - assert(cptr->user->server == &me); + assert(cli_user(cptr)->server == &me); - while (client_list[last_nn]) - { - if (++count == capacity) - { - assert(count < capacity); - return; + while (client_list[last_nn & mask]) { + if (++count == NN_MAX_CLIENT) { + assert(count < NN_MAX_CLIENT); + return 0; } - if (++last_nn == capacity) + if (++last_nn == NN_MAX_CLIENT) last_nn = 0; } - client_list[last_nn] = cptr; /* Reserve the numeric ! */ - -#if defined(EXTENDED_NUMERICS) - inttobase64(cptr->yxx, last_nn, 3); -#else - inttobase64(cptr->yxx, last_nn, 2); -#endif -} + client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */ -struct Client *findNUser(const char *yxx) -{ - struct Client *server = 0; - unsigned int index = 0; - if (5 == strlen(yxx)) - { - if (0 != (server = FindXNServer(yxx))) - { - Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, - base64toint(yxx + 2), server)); - if ((index = base64toint(yxx + 2)) <= server->serv->nn_mask) - return server->serv->client_list[index]; - } - } - else if (0 != (server = FindNServer(yxx))) - { - index = base64toint(yxx + 1) & server->serv->nn_mask; - Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, index, server)); - return server->serv->client_list[index]; - } - return 0; + inttobase64(cli_yxx(cptr), last_nn, 3); + if (++last_nn == NN_MAX_CLIENT) + last_nn = 0; + return 1; } -/* - * markMatchexServer() - * Mark all servers whose name matches the given (compiled) mask - * and return their count, abusing FLAGS_MAP for this :) +/** Mark servers whose name matches the given (compiled) mask by + * setting their FLAG_MAP flag. + * @param[in] cmask Compiled mask for server names. + * @param[in] minlen Minimum match length for \a cmask. + * @return Number of servers marked. */ int markMatchexServer(const char *cmask, int minlen) { @@ -424,78 +394,134 @@ int markMatchexServer(const char *cmask, int minlen) int i; struct Client *acptr; - for (i = 0; i < lastNNServer; i++) - { + for (i = 0; i < lastNNServer; i++) { if ((acptr = server_list[i])) { - if (matchexec(acptr->name, cmask, minlen)) - acptr->flags &= ~FLAGS_MAP; + if (matchexec(cli_name(acptr), cmask, minlen)) + ClrFlag(acptr, FLAG_MAP); else { - acptr->flags |= FLAGS_MAP; - cnt++; + SetFlag(acptr, FLAG_MAP); + cnt++; } } } return cnt; } -struct Client *find_match_server(char *mask) +/** Find first server whose name matches the given mask. + * @param[in,out] mask %Server name mask (collapse()d in-place). + * @return Matching server with lowest numnick value (or NULL). + */ +struct Client* find_match_server(char *mask) { struct Client *acptr; int i; - if (!(BadPtr(mask))) - { + if (!(BadPtr(mask))) { collapse(mask); - for (i = 0; i < lastNNServer; i++) - { - if ((acptr = server_list[i]) && (!match(mask, acptr->name))) - return acptr; + for (i = 0; i < lastNNServer; i++) { + if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr)))) + return acptr; } } - return NULL; + return 0; } - -#ifndef NO_PROTOCOL9 - -/****************************************************************************** +/** Encode an IP address in the base64 used by numnicks. + * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6 + * addresses), the 32-bit host address is encoded directly as six + * characters. * - * The following functions can be removed as soon as all servers have upgraded - * to ircu2.10. + * For IPv6 addresses, each 16-bit address segment is encoded as three + * characters, but the longest run of zero segments is encoded using an + * underscore. + * @param[out] buf Output buffer to write to. + * @param[in] addr IP address to encode. + * @param[in] count Number of bytes writable to \a buf. + * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses. */ +const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok) +{ + if (irc_in_addr_is_ipv4(addr)) { + assert(count >= 6); + inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6); + } else if (!v6_ok) { + assert(count >= 6); + if (addr->in6_16[0] == htons(0x2002)) + inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6); + else + strcpy(buf, "AAAAAA"); + } else { + unsigned int max_start, max_zeros, curr_zeros, zero, ii; + char *output = buf; + + assert(count >= 25); + /* Can start by printing out the leading non-zero parts. */ + for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) { + inttobase64(output, ntohs(addr->in6_16[ii]), 3); + output += 3; + } + /* Find the longest run of zeros. */ + for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) { + if (!addr->in6_16[ii]) + curr_zeros++; + else if (curr_zeros > max_zeros) { + max_start = ii - curr_zeros; + max_zeros = curr_zeros; + curr_zeros = 0; + } + } + if (curr_zeros > max_zeros) { + max_start = ii - curr_zeros; + max_zeros = curr_zeros; + curr_zeros = 0; + } + /* Print the rest of the address */ + for (ii = zero; ii < 8; ) { + if ((ii == max_start) && max_zeros) { + *output++ = '_'; + ii += max_zeros; + } else { + inttobase64(output, ntohs(addr->in6_16[ii]), 3); + output += 3; + ii++; + } + } + *output = '\0'; + } + return buf; +} -/* - * CreateNNforProtocol9server - * - * We do not receive numeric nicks from servers behind a protocol 9 link - * so we generate it ourselfs. +/** Decode an IP address from base64. + * @param[in] input Input buffer to decode. + * @param[out] addr IP address structure to populate. */ -const char *CreateNNforProtocol9server(const struct Client *server) +void base64toip(const char* input, struct irc_in_addr* addr) { - static char YXX[4]; - struct Server *serv = server->serv; - unsigned int count = 0; - - assert(IsServer(server)); - assert(9 == Protocol(server)); - - YXX[0] = *server->yxx; - YXX[3] = 0; - - while (serv->client_list[serv->nn_last]) - { - if (++count == NUMNICKBASE) - { - assert(count < NUMNICKBASE); - return NULL; + memset(addr, 0, sizeof(*addr)); + if (strlen(input) == 6) { + unsigned int in = base64toint(input); + /* An all-zero address should stay that way. */ + if (in) { + addr->in6_16[5] = htons(65535); + addr->in6_16[6] = htons(in >> 16); + addr->in6_16[7] = htons(in & 65535); } - if (++serv->nn_last == NUMNICKBASE) - serv->nn_last = 0; + } else { + unsigned int pos = 0; + do { + if (*input == '_') { + unsigned int left; + for (left = (25 - strlen(input)) / 3 - pos; left; left--) + addr->in6_16[pos++] = 0; + input++; + } else { + unsigned short accum = convert2n[(unsigned char)*input++]; + accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++]; + accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++]; + addr->in6_16[pos++] = ntohs(accum); + } + } while (pos < 8); } - inttobase64(YXX + 1, serv->nn_last, 2); - return YXX; } - -#endif /* !NO_PROTOCOL9 */