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.
25 #include "ircd_alloc.h"
26 #include "ircd_string.h"
39 * Numeric nicks are new as of version ircu2.10.00beta1.
41 * The idea is as follows:
42 * In most messages (for protocol 10+) the original nick will be
43 * replaced by a 3 character string: YXX
44 * Where 'Y' represents the server, and 'XX' the nick on that server.
46 * 'YXX' should not interfer with the input parser, and therefore is
47 * not allowed to contain spaces or a ':'.
48 * Also, 'Y' can't start with a '+' because of m_server().
50 * We keep the characters printable for debugging reasons too.
52 * The 'XX' value can be larger then the maximum number of clients
53 * per server, we use a mask (struct Server::nn_mask) to get the real
54 * client numeric. The overhead is used to have some redundancy so
55 * just-disconnected-client aren't confused with just-connected ones.
59 * Lets have *LOTS* of connections...
61 #define EXTENDED_NUMERICS
63 /* These must be the same on ALL servers ! Do not change ! */
66 #define NUMNICKMAXCHAR 'z' /* See convert2n[] */
67 #define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */
68 #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
69 #define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */
70 #if defined(EXTENDED_NUMERICS)
71 #define NN_MAX_CLIENT 262144 /* NUMNICKBASE ^ 3 */
73 #define NN_MAX_CLIENT 4096 /* (NUMNICKBASE * NUMNICKBASE) */
77 * The internal counter for the 'XX' of local clients
79 static unsigned int lastNNServer = 0;
80 static struct Client* server_list[NN_MAX_SERVER];
85 * convert2y[] converts a numeric to the corresponding character.
86 * The following characters are currently known to be forbidden:
88 * '\0' : Because we use '\0' as end of line.
90 * ' ' : Because parse_*() uses this as parameter seperator.
91 * ':' : Because parse_server() uses this to detect if a prefix is a
93 * '+' : Because m_nick() uses this to determine if parv[6] is a
95 * '&', '#', '+', '$', '@' and '%' :
96 * Because m_message() matches these characters to detect special cases.
98 static const char convert2y[] = {
99 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
100 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
101 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
102 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
105 static const unsigned int convert2n[] = {
106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
110 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
111 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
112 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
113 41,42,43,44,45,46,47,48,49,50,51, 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,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
128 unsigned int base64toint(const char* s)
130 unsigned int i = convert2n[(unsigned char) *s++];
133 i += convert2n[(unsigned char) *s++];
138 const char* inttobase64(char* buf, unsigned int v, unsigned int count)
142 buf[--count] = convert2y[(v & NUMNICKMASK)];
148 static struct Client* FindXNServer(const char* numeric)
154 Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
155 return server_list[base64toint(buf)];
158 struct Client* FindNServer(const char* numeric)
160 unsigned int len = strlen(numeric);
163 Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
164 return server_list[base64toint(numeric)];
167 Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
168 convert2n[(unsigned char) *numeric]));
169 return server_list[convert2n[(unsigned char) *numeric]];
171 return FindXNServer(numeric);
174 struct Client* findNUser(const char* yxx)
176 struct Client* server = 0;
177 if (5 == strlen(yxx)) {
178 if (0 != (server = FindXNServer(yxx))) {
179 Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx,
180 base64toint(yxx + 2) & server->serv->nn_mask));
181 return server->serv->client_list[base64toint(yxx + 2) & server->serv->nn_mask];
184 else if (0 != (server = FindNServer(yxx))) {
185 Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
186 yxx, base64toint(yxx + 1) & server->serv->nn_mask));
187 return server->serv->client_list[base64toint(yxx + 1) & server->serv->nn_mask];
192 void RemoveYXXClient(struct Client* server, const char* yxx)
197 Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
198 base64toint(yxx) & server->serv->nn_mask));
199 server->serv->client_list[base64toint(yxx) & server->serv->nn_mask] = 0;
203 void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
206 if (5 == strlen(yxx)) {
207 ircd_strncpy(server->yxx, yxx, 2);
208 ircd_strncpy(server->serv->nn_capacity, yxx + 2, 3);
211 server->yxx[0] = yxx[0];
212 server->serv->nn_capacity[0] = yxx[1];
213 server->serv->nn_capacity[1] = yxx[2];
215 server->serv->nn_mask = base64toint(server->serv->nn_capacity);
217 index = base64toint(server->yxx);
218 if (index >= lastNNServer)
219 lastNNServer = index + 1;
220 server_list[index] = server;
222 /* Note, exit_one_client uses the fact that `client_list' != NULL to
223 * determine that SetServerYXX has been called - and then calls
224 * ClearServerYXX. However, freeing the allocation happens in free_client() */
225 server->serv->client_list =
226 (struct Client**) MyCalloc(server->serv->nn_mask + 1, sizeof(struct Client*));
229 void SetYXXCapacity(struct Client* c, unsigned int capacity)
231 unsigned int max_clients = 16;
233 * Calculate mask to be used for the maximum number of clients
235 while (max_clients < capacity)
240 if (max_clients > NN_MAX_CLIENT) {
241 fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
242 "too large ! Please decrease this value.\n",
243 max_clients - NN_MAX_CLIENT);
247 #if defined(EXTENDED_NUMERICS)
248 inttobase64(c->serv->nn_capacity, max_clients, 3);
250 inttobase64(c->serv->nn_capacity, max_clients, 2);
252 c->serv->nn_mask = max_clients; /* Our Numeric Nick mask */
253 c->serv->client_list = (struct Client**) MyCalloc(max_clients + 1,
254 sizeof(struct Client*));
255 server_list[base64toint(c->yxx)] = c;
258 void SetYXXServerName(struct Client* c, unsigned int numeric)
261 assert(numeric < NN_MAX_SERVER);
263 #if defined(EXTENDED_NUMERICS)
264 inttobase64(c->yxx, numeric, 2);
266 assert(numeric < NUMNICKBASE);
267 c->yxx[0] = convert2y[numeric];
269 if (numeric >= lastNNServer)
270 lastNNServer = numeric + 1;
271 server_list[numeric] = c;
274 void ClearServerYXX(const struct Client *server)
276 unsigned int index = base64toint(server->yxx);
277 if (server_list[index] == server) /* Sanity check */
278 server_list[index] = 0;
284 * Register numeric of new, remote, client.
285 * Add it to the appropriate client_list.
287 void SetRemoteNumNick(struct Client* acptr, const char *yxx)
289 struct Client** acptrp;
290 struct Client* server = acptr->user->server;
292 if (5 == strlen(yxx)) {
293 strcpy(acptr->yxx, yxx + 2);
296 acptr->yxx[0] = *++yxx;
297 acptr->yxx[1] = *++yxx;
300 Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", acptr->yxx,
301 base64toint(acptr->yxx) & server->serv->nn_mask));
303 acptrp = &server->serv->client_list[base64toint(acptr->yxx) & server->serv->nn_mask];
306 * this exits the old client in the array, not the client
309 exit_client(acptr->from, *acptrp, server, "Numeric nick collision (Ghost)");
318 * Register numeric of new, local, client. Add it to our client_list.
319 * Muxtex needed if threaded
321 int SetLocalNumNick(struct Client *cptr)
323 static unsigned int last_nn = 0;
324 struct Client** client_list = me.serv->client_list;
325 unsigned int mask = me.serv->nn_mask;
326 unsigned int count = 0;
328 assert(cptr->user->server == &me);
330 while (client_list[last_nn & mask]) {
331 if (++count == NN_MAX_CLIENT) {
332 assert(count < NN_MAX_CLIENT);
335 if (++last_nn == NN_MAX_CLIENT)
338 client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */
340 #if defined(EXTENDED_NUMERICS)
341 inttobase64(cptr->yxx, last_nn, 3);
343 inttobase64(cptr->yxx, last_nn, 2);
345 if (++last_nn == NN_MAX_CLIENT)
351 * markMatchexServer()
352 * Mark all servers whose name matches the given (compiled) mask
353 * and return their count, abusing FLAGS_MAP for this :)
355 int markMatchexServer(const char *cmask, int minlen)
359 struct Client *acptr;
361 for (i = 0; i < lastNNServer; i++) {
362 if ((acptr = server_list[i])) {
363 if (matchexec(acptr->name, cmask, minlen))
364 acptr->flags &= ~FLAGS_MAP;
366 acptr->flags |= FLAGS_MAP;
374 struct Client* find_match_server(char *mask)
376 struct Client *acptr;
379 if (!(BadPtr(mask))) {
381 for (i = 0; i < lastNNServer; i++) {
382 if ((acptr = server_list[i]) && (!match(mask, acptr->name)))