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 * when n2k comes, define this for more capacity
61 #undef 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) */
72 * The internal counter for the 'XX' of local clients
74 static unsigned int lastNNServer = 0;
75 static struct Client* server_list[NN_MAX_SERVER];
80 * convert2y[] converts a numeric to the corresponding character.
81 * The following characters are currently known to be forbidden:
83 * '\0' : Because we use '\0' as end of line.
85 * ' ' : Because parse_*() uses this as parameter seperator.
86 * ':' : Because parse_server() uses this to detect if a prefix is a
88 * '+' : Because m_nick() uses this to determine if parv[6] is a
90 * '&', '#', '+', '$', '@' and '%' :
91 * Because m_message() matches these characters to detect special cases.
93 static const char convert2y[] = {
94 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
95 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
96 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
97 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
100 static const unsigned int convert2n[] = {
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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
105 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
106 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
107 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
108 41,42,43,44,45,46,47,48,49,50,51, 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,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
123 unsigned int base64toint(const char* s)
125 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)
137 buf[--count] = convert2y[(v & NUMNICKMASK)];
143 static struct Client* FindXNServer(const char* numeric)
149 Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
150 return server_list[base64toint(buf)];
153 struct Client* FindNServer(const char* numeric)
155 size_t len = strlen(numeric);
158 Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
159 return server_list[base64toint(numeric)];
162 Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
163 convert2n[(unsigned char) *numeric]));
164 return server_list[convert2n[(unsigned char) *numeric]];
166 return FindXNServer(numeric);
169 struct Client* findNUser(const char* yxx)
171 struct Client* server = 0;
172 unsigned int index = 0;
173 if (5 == strlen(yxx)) {
174 if (0 != (server = FindXNServer(yxx))) {
175 Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx,
176 base64toint(yxx + 2), server));
177 if ((index = base64toint(yxx + 2)) <= server->serv->nn_mask)
178 return server->serv->client_list[index];
181 else if (0 != (server = FindNServer(yxx))) {
182 index = base64toint(yxx + 1) & server->serv->nn_mask;
183 Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, index, server));
184 return server->serv->client_list[index];
189 void RemoveYXXClient(struct Client* server, const char* yxx)
194 unsigned int index = 0;
197 index = base64toint(yxx) & server->serv->nn_mask;
199 index = base64toint(yxx);
201 Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx, index));
203 if (index < (server->serv->nn_mask + 1))
204 server->serv->client_list[index] = NULL;
208 void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
211 if (5 == strlen(yxx)) {
212 ircd_strncpy(server->yxx, yxx, 2);
213 ircd_strncpy(server->serv->nn_capacity, yxx + 2, 3);
216 server->yxx[0] = yxx[0];
217 server->serv->nn_capacity[0] = yxx[1];
218 server->serv->nn_capacity[1] = yxx[2];
220 server->serv->nn_mask = base64toint(server->serv->nn_capacity);
222 index = base64toint(server->yxx);
223 if (index >= lastNNServer)
224 lastNNServer = index + 1;
225 server_list[index] = server;
227 /* Note, exit_one_client uses the fact that `client_list' != NULL to
228 * determine that SetServerYXX has been called - and then calls
229 * ClearServerYXX. However, freeing the allocation happens in free_client() */
230 server->serv->client_list =
231 (struct Client**) MyCalloc(server->serv->nn_mask + 1,
232 sizeof(struct Client*));
235 void SetYXXCapacity(struct Client* c, size_t capacity)
237 unsigned int max_clients;
238 #if defined(EXTENDED_NUMERICS)
239 max_clients = capacity - 1;
240 inttobase64(c->serv->nn_capacity, max_clients, 3);
244 * Calculate mask to be used for the maximum number of clients
246 while (capacity >= max_clients)
247 max_clients = max_clients << 1;
251 if (max_clients > NN_MAX_SERVER) {
252 fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
253 "too large ! Please decrease this value.\n",
254 max_clients - NN_MAX_SERVER);
258 inttobase64(c->serv->nn_capacity, max_clients, 2);
260 c->serv->nn_mask = max_clients; /* Our Numeric Nick mask */
261 c->serv->client_list = (struct Client**) MyCalloc(max_clients + 1,
262 sizeof(struct Client*));
263 server_list[base64toint(c->yxx)] = c;
266 void SetYXXServerName(struct Client* c, unsigned int numeric)
269 assert(numeric < NN_MAX_SERVER);
271 #if defined(EXTENDED_NUMERICS)
272 inttobase64(c->yxx, numeric, 2);
274 assert(numeric < NUMNICKBASE);
275 c->yxx[0] = convert2y[numeric];
277 if (numeric >= lastNNServer)
278 lastNNServer = numeric + 1;
279 server_list[numeric] = c;
282 void ClearServerYXX(const struct Client *server)
284 unsigned int index = base64toint(server->yxx);
285 if (server_list[index] == server) /* Sanity check */
286 server_list[index] = NULL;
292 * Register numeric of new, remote, client.
293 * Add it to the appropriate client_list.
295 int SetRemoteNumNick(struct Client* acptr, const char *yxx)
297 struct Client** acptrp;
298 struct Client* server = acptr->user->server;
299 unsigned int index = 0;
301 if (5 == strlen(yxx)) {
302 strcpy(acptr->yxx, yxx + 2);
303 index = base64toint(acptr->yxx);
306 acptr->yxx[0] = *++yxx;
307 acptr->yxx[1] = *++yxx;
309 index = base64toint(acptr->yxx) & server->serv->nn_mask;
312 Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", acptr->yxx, index));
313 if (index > server->serv->nn_mask)
316 assert(index <= server->serv->nn_mask);
318 acptrp = &server->serv->client_list[index];
321 * this exits the old client in the array, not the client
324 exit_client(acptr->from, *acptrp, server, "Numeric nick collision (Ghost)");
334 * Register numeric of new, local, client. Add it to our client_list.
336 void SetLocalNumNick(struct Client *cptr)
338 static unsigned int last_nn = 0;
339 struct Client** client_list = me.serv->client_list;
340 unsigned int capacity = me.serv->nn_mask + 1;
341 unsigned int count = 0;
343 assert(cptr->user->server == &me);
345 while (client_list[last_nn]) {
346 if (++count == capacity) {
347 assert(count < capacity);
350 if (++last_nn == capacity)
353 client_list[last_nn] = cptr; /* Reserve the numeric ! */
355 #if defined(EXTENDED_NUMERICS)
356 inttobase64(cptr->yxx, last_nn, 3);
358 inttobase64(cptr->yxx, last_nn, 2);
363 * markMatchexServer()
364 * Mark all servers whose name matches the given (compiled) mask
365 * and return their count, abusing FLAGS_MAP for this :)
367 int markMatchexServer(const char *cmask, int minlen)
371 struct Client *acptr;
373 for (i = 0; i < lastNNServer; i++) {
374 if ((acptr = server_list[i])) {
375 if (matchexec(acptr->name, cmask, minlen))
376 acptr->flags &= ~FLAGS_MAP;
378 acptr->flags |= FLAGS_MAP;
386 struct Client* find_match_server(char *mask)
388 struct Client *acptr;
391 if (!(BadPtr(mask))) {
393 for (i = 0; i < lastNNServer; i++) {
394 if ((acptr = server_list[i]) && (!match(mask, acptr->name)))