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 /* These must be the same on ALL servers ! Do not change ! */
62 #define NUMNICKMAXCHAR 'z' /* See convert2n[] */
63 #define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */
64 #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
65 #define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */
66 #define NN_MAX_CLIENT 262144 /* NUMNICKBASE ^ 3 */
69 * The internal counter for the 'XX' of local clients
71 static unsigned int lastNNServer = 0;
72 static struct Client* server_list[NN_MAX_SERVER];
77 * convert2y[] converts a numeric to the corresponding character.
78 * The following characters are currently known to be forbidden:
80 * '\0' : Because we use '\0' as end of line.
82 * ' ' : Because parse_*() uses this as parameter seperator.
83 * ':' : Because parse_server() uses this to detect if a prefix is a
85 * '+' : Because m_nick() uses this to determine if parv[6] is a
87 * '&', '#', '+', '$', '@' and '%' :
88 * Because m_message() matches these characters to detect special cases.
90 static const char convert2y[] = {
91 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
92 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
93 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
94 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
97 static const unsigned int convert2n[] = {
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
102 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
103 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
104 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
105 41,42,43,44,45,46,47,48,49,50,51, 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 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
120 unsigned int base64toint(const char* s)
122 unsigned int i = convert2n[(unsigned char) *s++];
125 i += convert2n[(unsigned char) *s++];
130 const char* inttobase64(char* buf, unsigned int v, unsigned int count)
134 buf[--count] = convert2y[(v & NUMNICKMASK)];
140 static struct Client* FindXNServer(const char* numeric)
146 Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
147 return server_list[base64toint(buf)];
150 struct Client* FindNServer(const char* numeric)
152 unsigned int len = strlen(numeric);
155 Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
156 return server_list[base64toint(numeric)];
159 Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
160 convert2n[(unsigned char) *numeric]));
161 return server_list[convert2n[(unsigned char) *numeric]];
163 return FindXNServer(numeric);
166 struct Client* findNUser(const char* yxx)
168 struct Client* server = 0;
169 if (5 == strlen(yxx)) {
170 if (0 != (server = FindXNServer(yxx))) {
171 Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx,
172 base64toint(yxx + 2) & cli_serv(server)->nn_mask));
173 return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
176 else if (0 != (server = FindNServer(yxx))) {
177 Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
178 yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
179 return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
184 void RemoveYXXClient(struct Client* server, const char* yxx)
189 Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
190 base64toint(yxx) & cli_serv(server)->nn_mask));
191 cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0;
195 void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
198 if (5 == strlen(yxx)) {
199 ircd_strncpy(cli_yxx(server), yxx, 2);
200 ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3);
203 (cli_yxx(server))[0] = yxx[0];
204 cli_serv(server)->nn_capacity[0] = yxx[1];
205 cli_serv(server)->nn_capacity[1] = yxx[2];
207 cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity);
209 index = base64toint(cli_yxx(server));
210 if (index >= lastNNServer)
211 lastNNServer = index + 1;
212 server_list[index] = server;
214 /* Note, exit_one_client uses the fact that `client_list' != NULL to
215 * determine that SetServerYXX has been called - and then calls
216 * ClearServerYXX. However, freeing the allocation happens in free_client() */
217 cli_serv(server)->client_list =
218 (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*));
221 void SetYXXCapacity(struct Client* c, unsigned int capacity)
223 unsigned int max_clients = 16;
225 * Calculate mask to be used for the maximum number of clients
227 while (max_clients < capacity)
232 if (max_clients > NN_MAX_CLIENT) {
233 fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
234 "too large ! Please decrease this value.\n",
235 max_clients - NN_MAX_CLIENT);
239 inttobase64(cli_serv(c)->nn_capacity, max_clients, 3);
240 cli_serv(c)->nn_mask = max_clients; /* Our Numeric Nick mask */
241 cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1,
242 sizeof(struct Client*));
243 server_list[base64toint(cli_yxx(c))] = c;
246 void SetYXXServerName(struct Client* c, unsigned int numeric)
249 assert(numeric < NN_MAX_SERVER);
251 inttobase64(cli_yxx(c), numeric, 2);
252 if (numeric >= lastNNServer)
253 lastNNServer = numeric + 1;
254 server_list[numeric] = c;
257 void ClearServerYXX(const struct Client *server)
259 unsigned int index = base64toint(cli_yxx(server));
260 if (server_list[index] == server) /* Sanity check */
261 server_list[index] = 0;
267 * Register numeric of new, remote, client.
268 * Add it to the appropriate client_list.
270 void SetRemoteNumNick(struct Client* acptr, const char *yxx)
272 struct Client** acptrp;
273 struct Client* server = cli_user(acptr)->server;
275 if (5 == strlen(yxx)) {
276 strcpy(cli_yxx(acptr), yxx + 2);
279 (cli_yxx(acptr))[0] = *++yxx;
280 (cli_yxx(acptr))[1] = *++yxx;
281 (cli_yxx(acptr))[2] = 0;
283 Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr),
284 base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask));
286 acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask];
289 * this exits the old client in the array, not the client
292 exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)");
301 * Register numeric of new, local, client. Add it to our client_list.
302 * Muxtex needed if threaded
304 int SetLocalNumNick(struct Client *cptr)
306 static unsigned int last_nn = 0;
307 struct Client** client_list = cli_serv(&me)->client_list;
308 unsigned int mask = cli_serv(&me)->nn_mask;
309 unsigned int count = 0;
311 assert(cli_user(cptr)->server == &me);
313 while (client_list[last_nn & mask]) {
314 if (++count == NN_MAX_CLIENT) {
315 assert(count < NN_MAX_CLIENT);
318 if (++last_nn == NN_MAX_CLIENT)
321 client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */
323 inttobase64(cli_yxx(cptr), last_nn, 3);
324 if (++last_nn == NN_MAX_CLIENT)
330 * markMatchexServer()
331 * Mark all servers whose name matches the given (compiled) mask
332 * and return their count, abusing FLAGS_MAP for this :)
334 int markMatchexServer(const char *cmask, int minlen)
338 struct Client *acptr;
340 for (i = 0; i < lastNNServer; i++) {
341 if ((acptr = server_list[i])) {
342 if (matchexec(cli_name(acptr), cmask, minlen))
343 cli_flags(acptr) &= ~FLAGS_MAP;
345 cli_flags(acptr) |= FLAGS_MAP;
353 struct Client* find_match_server(char *mask)
355 struct Client *acptr;
358 if (!(BadPtr(mask))) {
360 for (i = 0; i < lastNNServer; i++) {
361 if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr))))