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.
26 #include "ircd_alloc.h"
27 #include "ircd_string.h"
40 * Numeric nicks are new as of version ircu2.10.00beta1.
42 * The idea is as follows:
43 * In most messages (for protocol 10+) the original nick will be
44 * replaced by a 3 character string: YXX
45 * Where 'Y' represents the server, and 'XX' the nick on that server.
47 * 'YXX' should not interfer with the input parser, and therefore is
48 * not allowed to contain spaces or a ':'.
49 * Also, 'Y' can't start with a '+' because of m_server().
51 * We keep the characters printable for debugging reasons too.
53 * The 'XX' value can be larger then the maximum number of clients
54 * per server, we use a mask (struct Server::nn_mask) to get the real
55 * client numeric. The overhead is used to have some redundancy so
56 * just-disconnected-client aren't confused with just-connected ones.
60 /* These must be the same on ALL servers ! Do not change ! */
63 #define NUMNICKMAXCHAR 'z' /* See convert2n[] */
64 #define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */
65 #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
66 #define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */
67 #define NN_MAX_CLIENT 262144 /* NUMNICKBASE ^ 3 */
70 * The internal counter for the 'XX' of local clients
72 static unsigned int lastNNServer = 0;
73 static struct Client* server_list[NN_MAX_SERVER];
78 * convert2y[] converts a numeric to the corresponding character.
79 * The following characters are currently known to be forbidden:
81 * '\0' : Because we use '\0' as end of line.
83 * ' ' : Because parse_*() uses this as parameter seperator.
84 * ':' : Because parse_server() uses this to detect if a prefix is a
86 * '+' : Because m_nick() uses this to determine if parv[6] is a
88 * '&', '#', '+', '$', '@' and '%' :
89 * Because m_message() matches these characters to detect special cases.
91 static const char convert2y[] = {
92 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
93 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
94 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
95 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
98 static const unsigned int convert2n[] = {
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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
103 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
104 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
105 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
106 41,42,43,44,45,46,47,48,49,50,51, 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,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
121 unsigned int base64toint(const char* s)
123 unsigned int i = convert2n[(unsigned char) *s++];
126 i += convert2n[(unsigned char) *s++];
131 const char* inttobase64(char* buf, unsigned int v, unsigned int count)
135 buf[--count] = convert2y[(v & NUMNICKMASK)];
141 static struct Client* FindXNServer(const char* numeric)
147 Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
148 return server_list[base64toint(buf)];
151 struct Client* FindNServer(const char* numeric)
153 unsigned int len = strlen(numeric);
156 Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
157 return server_list[base64toint(numeric)];
160 Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
161 convert2n[(unsigned char) *numeric]));
162 return server_list[convert2n[(unsigned char) *numeric]];
164 return FindXNServer(numeric);
167 struct Client* findNUser(const char* yxx)
169 struct Client* server = 0;
170 if (5 == strlen(yxx)) {
171 if (0 != (server = FindXNServer(yxx))) {
172 Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx,
173 base64toint(yxx + 2) & cli_serv(server)->nn_mask));
174 return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
177 else if (0 != (server = FindNServer(yxx))) {
178 Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
179 yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
180 return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
185 void RemoveYXXClient(struct Client* server, const char* yxx)
190 Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
191 base64toint(yxx) & cli_serv(server)->nn_mask));
192 cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0;
196 void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
199 if (5 == strlen(yxx)) {
200 ircd_strncpy(cli_yxx(server), yxx, 2);
201 ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3);
204 (cli_yxx(server))[0] = yxx[0];
205 cli_serv(server)->nn_capacity[0] = yxx[1];
206 cli_serv(server)->nn_capacity[1] = yxx[2];
208 cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity);
210 index = base64toint(cli_yxx(server));
211 if (index >= lastNNServer)
212 lastNNServer = index + 1;
213 server_list[index] = server;
215 /* Note, exit_one_client uses the fact that `client_list' != NULL to
216 * determine that SetServerYXX has been called - and then calls
217 * ClearServerYXX. However, freeing the allocation happens in free_client() */
218 cli_serv(server)->client_list =
219 (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*));
222 void SetYXXCapacity(struct Client* c, unsigned int capacity)
224 unsigned int max_clients = 16;
226 * Calculate mask to be used for the maximum number of clients
228 while (max_clients < capacity)
233 if (max_clients > NN_MAX_CLIENT) {
234 fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
235 "too large ! Please decrease this value.\n",
236 max_clients - NN_MAX_CLIENT);
240 inttobase64(cli_serv(c)->nn_capacity, max_clients, 3);
241 cli_serv(c)->nn_mask = max_clients; /* Our Numeric Nick mask */
242 cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1,
243 sizeof(struct Client*));
244 server_list[base64toint(cli_yxx(c))] = c;
247 void SetYXXServerName(struct Client* c, unsigned int numeric)
250 assert(numeric < NN_MAX_SERVER);
252 inttobase64(cli_yxx(c), numeric, 2);
253 if (numeric >= lastNNServer)
254 lastNNServer = numeric + 1;
255 server_list[numeric] = c;
258 void ClearServerYXX(const struct Client *server)
260 unsigned int index = base64toint(cli_yxx(server));
261 if (server_list[index] == server) /* Sanity check */
262 server_list[index] = 0;
268 * Register numeric of new, remote, client.
269 * Add it to the appropriate client_list.
271 void SetRemoteNumNick(struct Client* acptr, const char *yxx)
273 struct Client** acptrp;
274 struct Client* server = cli_user(acptr)->server;
276 if (5 == strlen(yxx)) {
277 strcpy(cli_yxx(acptr), yxx + 2);
280 (cli_yxx(acptr))[0] = *++yxx;
281 (cli_yxx(acptr))[1] = *++yxx;
282 (cli_yxx(acptr))[2] = 0;
284 Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr),
285 base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask));
287 acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask];
290 * this exits the old client in the array, not the client
293 exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)");
302 * Register numeric of new, local, client. Add it to our client_list.
303 * Muxtex needed if threaded
305 int SetLocalNumNick(struct Client *cptr)
307 static unsigned int last_nn = 0;
308 struct Client** client_list = cli_serv(&me)->client_list;
309 unsigned int mask = cli_serv(&me)->nn_mask;
310 unsigned int count = 0;
312 assert(cli_user(cptr)->server == &me);
314 while (client_list[last_nn & mask]) {
315 if (++count == NN_MAX_CLIENT) {
316 assert(count < NN_MAX_CLIENT);
319 if (++last_nn == NN_MAX_CLIENT)
322 client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */
324 inttobase64(cli_yxx(cptr), last_nn, 3);
325 if (++last_nn == NN_MAX_CLIENT)
331 * markMatchexServer()
332 * Mark all servers whose name matches the given (compiled) mask
333 * and return their count, abusing FLAGS_MAP for this :)
335 int markMatchexServer(const char *cmask, int minlen)
339 struct Client *acptr;
341 for (i = 0; i < lastNNServer; i++) {
342 if ((acptr = server_list[i])) {
343 if (matchexec(cli_name(acptr), cmask, minlen))
344 cli_flags(acptr) &= ~FLAGS_MAP;
346 cli_flags(acptr) |= FLAGS_MAP;
354 struct Client* find_match_server(char *mask)
356 struct Client *acptr;
359 if (!(BadPtr(mask))) {
361 for (i = 0; i < lastNNServer; i++) {
362 if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr))))