2 * IRC - Internet Relay Chat, ircd/channel.c
3 * Copyright (C) 1996 Carlo Wood (I wish this was C++ - this sucks :/)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 * Numeric nicks are new as of version ircu2.10.00beta1.
40 * The idea is as follows:
41 * In most messages (for protocol 10+) the original nick will be
42 * replaced by a 3 character string: YXX
43 * Where 'Y' represents the server, and 'XX' the nick on that server.
45 * 'YXX' should not interfer with the input parser, and therefore is
46 * not allowed to contain spaces or a ':'.
47 * Also, 'Y' can't start with a '+' because of m_server().
49 * We keep the characters printable for debugging reasons too.
51 * The 'XX' value can be larger then the maximum number of clients
52 * per server, we use a mask (struct Server::nn_mask) to get the real
53 * client numeric. The overhead is used to have some redundancy so
54 * just-disconnected-client aren't confused with just-connected ones.
58 * when n2k comes, define this for more capacity
60 #undef EXTENDED_NUMERICS
62 /* These must be the same on ALL servers ! Do not change ! */
65 #define NUMNICKMAXCHAR 'z' /* See convert2n[] */
66 #define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */
67 #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
68 #define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */
71 * The internal counter for the 'XX' of local clients
73 static unsigned int lastNNServer = 0;
74 static struct Client *server_list[NN_MAX_SERVER];
79 * convert2y[] converts a numeric to the corresponding character.
80 * The following characters are currently known to be forbidden:
82 * '\0' : Because we use '\0' as end of line.
84 * ' ' : Because parse_*() uses this as parameter seperator.
85 * ':' : Because parse_server() uses this to detect if a prefix is a
87 * '+' : Because m_nick() uses this to determine if parv[6] is a
89 * '&', '#', '+', '$', '@' and '%' :
90 * Because m_message() matches these characters to detect special cases.
92 static const char convert2y[] = {
93 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
94 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
95 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
96 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
99 static const unsigned int convert2n[] = {
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
104 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
105 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
106 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
107 41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0,
109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
122 unsigned int base64toint(const char *s)
124 unsigned int i = convert2n[(unsigned char)*s++];
128 i += convert2n[(unsigned char)*s++];
133 const char *inttobase64(char *buf, unsigned int v, size_t count)
138 buf[--count] = convert2y[(v & NUMNICKMASK)];
144 static struct Client *FindXNServer(const char *numeric)
150 Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
151 return server_list[base64toint(buf)];
154 struct Client *FindNServer(const char *numeric)
156 size_t len = strlen(numeric);
159 Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
160 return server_list[base64toint(numeric)];
164 Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
165 convert2n[(unsigned char)*numeric]));
166 return server_list[convert2n[(unsigned char)*numeric]];
168 return FindXNServer(numeric);
171 void RemoveYXXClient(struct Client *server, const char *yxx)
177 unsigned int index = 0;
180 index = base64toint(yxx) & server->serv->nn_mask;
182 index = base64toint(yxx);
184 Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx, index));
186 if (index < (server->serv->nn_mask + 1))
187 server->serv->client_list[index] = NULL;
191 void SetServerYXX(struct Client *cptr, struct Client *server, const char *yxx)
195 /* Use cptr, because we do protocol 9 -> 10 translation for numeric nicks ! */
196 if (Protocol(cptr) > 9)
199 if (5 == strlen(yxx))
201 strncpy(server->yxx, yxx, 2);
202 strncpy(server->serv->nn_capacity, yxx + 2, 3);
206 server->yxx[0] = yxx[0];
207 server->serv->nn_capacity[0] = yxx[1];
208 server->serv->nn_capacity[1] = yxx[2];
210 server->serv->nn_mask = base64toint(server->serv->nn_capacity);
216 static const struct ServerNameNumeric {
218 unsigned int numeric;
220 { "Uworld.undernet.org", 22},
221 { "Uworld2.undernet.org", 23},
222 { "channels.undernet.org", 30},
223 { "channels2.undernet.org", 31},
228 for (i = 0; i < 4; ++i)
230 if (!strCasediff(server_table[i].name, server->name))
233 * XXX - just use the old format for services for now
235 *server->yxx = convert2y[server_table[i].numeric];
236 inttobase64(server->serv->nn_capacity, 63, 2);
237 server->serv->nn_mask = 63;
243 index = base64toint(server->yxx);
244 if (index >= lastNNServer)
245 lastNNServer = index + 1;
246 server_list[index] = server;
248 /* Note, exit_one_client uses the fact that `client_list' != NULL to
249 * determine that SetServerYXX has been called - and then calls
250 * ClearServerYXX. However, freeing the allocation happens in free_client() */
251 server->serv->client_list =
252 (struct Client **)RunCalloc(server->serv->nn_mask + 1,
253 sizeof(struct Client *));
256 void SetYXXCapacity(struct Client *c, size_t capacity)
258 unsigned int max_clients;
259 #if defined(EXTENDED_NUMERICS)
260 max_clients = capacity - 1;
261 inttobase64(c->serv->nn_capacity, max_clients, 3);
265 * Calculate mask to be used for the maximum number of clients
267 while (capacity >= max_clients)
268 max_clients = max_clients << 1;
272 if (max_clients > NN_MAX_SERVER)
274 fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
275 "too large ! Please decrease this value.\n",
276 max_clients - NN_MAX_SERVER);
280 inttobase64(c->serv->nn_capacity, max_clients, 2);
282 c->serv->nn_mask = max_clients; /* Our Numeric Nick mask */
283 c->serv->client_list = (struct Client **)RunCalloc(max_clients + 1,
284 sizeof(struct Client *));
285 server_list[base64toint(c->yxx)] = c;
288 void SetYXXServerName(struct Client *c, unsigned int numeric)
291 assert(numeric < NN_MAX_SERVER);
293 #if defined(EXTENDED_NUMERICS)
294 inttobase64(c->yxx, numeric, 2);
296 assert(numeric < NUMNICKBASE);
297 c->yxx[0] = convert2y[numeric];
299 if (numeric >= lastNNServer)
300 lastNNServer = numeric + 1;
301 server_list[numeric] = c;
304 void ClearServerYXX(const struct Client *server)
306 unsigned int index = base64toint(server->yxx);
307 if (server_list[index] == server) /* Sanity check */
308 server_list[index] = NULL;
314 * Register numeric of new, remote, client.
315 * Add it to the appropriate client_list.
317 int SetRemoteNumNick(struct Client *acptr, const char *yxx)
319 struct Client **acptrp;
320 struct Client *server = acptr->user->server;
321 unsigned int index = 0;
323 if (5 == strlen(yxx))
325 strcpy(acptr->yxx, yxx + 2);
326 index = base64toint(acptr->yxx);
330 acptr->yxx[0] = *++yxx;
331 acptr->yxx[1] = *++yxx;
333 index = base64toint(acptr->yxx) & server->serv->nn_mask;
336 Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", acptr->yxx, index));
337 if (index > server->serv->nn_mask)
340 assert(index <= server->serv->nn_mask);
342 acptrp = &server->serv->client_list[index];
346 * this exits the old client in the array, not the client
349 exit_client(acptr->from, *acptrp, server, "Numeric nick collision (Ghost)");
359 * Register numeric of new, local, client. Add it to our client_list.
361 void SetLocalNumNick(struct Client *cptr)
363 static unsigned int last_nn = 0;
364 struct Client **client_list = me.serv->client_list;
365 unsigned int capacity = me.serv->nn_mask + 1;
366 unsigned int count = 0;
368 assert(cptr->user->server == &me);
370 while (client_list[last_nn])
372 if (++count == capacity)
374 assert(count < capacity);
377 if (++last_nn == capacity)
380 client_list[last_nn] = cptr; /* Reserve the numeric ! */
382 #if defined(EXTENDED_NUMERICS)
383 inttobase64(cptr->yxx, last_nn, 3);
385 inttobase64(cptr->yxx, last_nn, 2);
389 struct Client *findNUser(const char *yxx)
391 struct Client *server = 0;
392 unsigned int index = 0;
393 if (5 == strlen(yxx))
395 if (0 != (server = FindXNServer(yxx)))
397 Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx,
398 base64toint(yxx + 2), server));
399 if ((index = base64toint(yxx + 2)) <= server->serv->nn_mask)
400 return server->serv->client_list[index];
403 else if (0 != (server = FindNServer(yxx)))
405 index = base64toint(yxx + 1) & server->serv->nn_mask;
406 Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, index, server));
407 return server->serv->client_list[index];
413 * markMatchexServer()
414 * Mark all servers whose name matches the given (compiled) mask
415 * and return their count, abusing FLAGS_MAP for this :)
417 int markMatchexServer(const char *cmask, int minlen)
421 struct Client *acptr;
423 for (i = 0; i < lastNNServer; i++)
425 if ((acptr = server_list[i]))
427 if (matchexec(acptr->name, cmask, minlen))
428 acptr->flags &= ~FLAGS_MAP;
431 acptr->flags |= FLAGS_MAP;
439 struct Client *find_match_server(char *mask)
441 struct Client *acptr;
447 for (i = 0; i < lastNNServer; i++)
449 if ((acptr = server_list[i]) && (!match(mask, acptr->name)))
459 /******************************************************************************
461 * The following functions can be removed as soon as all servers have upgraded
466 * CreateNNforProtocol9server
468 * We do not receive numeric nicks from servers behind a protocol 9 link
469 * so we generate it ourselfs.
471 const char *CreateNNforProtocol9server(const struct Client *server)
474 struct Server *serv = server->serv;
475 unsigned int count = 0;
477 assert(IsServer(server));
478 assert(9 == Protocol(server));
480 YXX[0] = *server->yxx;
483 while (serv->client_list[serv->nn_last])
485 if (++count == NUMNICKBASE)
487 assert(count < NUMNICKBASE);
490 if (++serv->nn_last == NUMNICKBASE)
493 inttobase64(YXX + 1, serv->nn_last, 2);
497 #endif /* !NO_PROTOCOL9 */