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"
41 * Numeric nicks are new as of version ircu2.10.00beta1.
43 * The idea is as follows:
44 * In most messages (for protocol 10+) the original nick will be
45 * replaced by a 3 character string: YXX
46 * Where 'Y' represents the server, and 'XX' the nick on that server.
48 * 'YXX' should not interfer with the input parser, and therefore is
49 * not allowed to contain spaces or a ':'.
50 * Also, 'Y' can't start with a '+' because of m_server().
52 * We keep the characters printable for debugging reasons too.
54 * The 'XX' value can be larger then the maximum number of clients
55 * per server, we use a mask (struct Server::nn_mask) to get the real
56 * client numeric. The overhead is used to have some redundancy so
57 * just-disconnected-client aren't confused with just-connected ones.
61 /* These must be the same on ALL servers ! Do not change ! */
64 #define NUMNICKMAXCHAR 'z' /* See convert2n[] */
65 #define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */
66 #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
67 #define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */
68 #define NN_MAX_CLIENT 262144 /* NUMNICKBASE ^ 3 */
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++];
127 i += convert2n[(unsigned char) *s++];
132 const char* inttobase64(char* buf, unsigned int v, unsigned int count)
136 buf[--count] = convert2y[(v & NUMNICKMASK)];
142 static struct Client* FindXNServer(const char* numeric)
148 Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf)));
149 return server_list[base64toint(buf)];
152 struct Client* FindNServer(const char* numeric)
154 unsigned int len = strlen(numeric);
157 Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
158 return server_list[base64toint(numeric)];
161 Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
162 convert2n[(unsigned char) *numeric]));
163 return server_list[convert2n[(unsigned char) *numeric]];
165 return FindXNServer(numeric);
168 struct Client* findNUser(const char* yxx)
170 struct Client* server = 0;
171 if (5 == strlen(yxx)) {
172 if (0 != (server = FindXNServer(yxx))) {
173 Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx,
174 base64toint(yxx + 2) & cli_serv(server)->nn_mask));
175 return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
178 else if (0 != (server = FindNServer(yxx))) {
179 Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
180 yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
181 return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
186 void RemoveYXXClient(struct Client* server, const char* yxx)
191 Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx,
192 base64toint(yxx) & cli_serv(server)->nn_mask));
193 cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0;
197 void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
200 if (5 == strlen(yxx)) {
201 ircd_strncpy(cli_yxx(server), yxx, 2);
202 ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3);
205 (cli_yxx(server))[0] = yxx[0];
206 cli_serv(server)->nn_capacity[0] = yxx[1];
207 cli_serv(server)->nn_capacity[1] = yxx[2];
209 cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity);
211 index = base64toint(cli_yxx(server));
212 if (index >= lastNNServer)
213 lastNNServer = index + 1;
214 server_list[index] = server;
216 /* Note, exit_one_client uses the fact that `client_list' != NULL to
217 * determine that SetServerYXX has been called - and then calls
218 * ClearServerYXX. However, freeing the allocation happens in free_client() */
219 cli_serv(server)->client_list =
220 (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*));
223 void SetYXXCapacity(struct Client* c, unsigned int capacity)
225 unsigned int max_clients = 16;
227 * Calculate mask to be used for the maximum number of clients
229 while (max_clients < capacity)
234 if (max_clients > NN_MAX_CLIENT) {
235 fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
236 "too large ! Please decrease this value.\n",
237 max_clients - NN_MAX_CLIENT);
241 inttobase64(cli_serv(c)->nn_capacity, max_clients, 3);
242 cli_serv(c)->nn_mask = max_clients; /* Our Numeric Nick mask */
243 cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1,
244 sizeof(struct Client*));
245 server_list[base64toint(cli_yxx(c))] = c;
248 void SetYXXServerName(struct Client* c, unsigned int numeric)
251 assert(numeric < NN_MAX_SERVER);
253 inttobase64(cli_yxx(c), numeric, 2);
254 if (numeric >= lastNNServer)
255 lastNNServer = numeric + 1;
256 server_list[numeric] = c;
259 void ClearServerYXX(const struct Client *server)
261 unsigned int index = base64toint(cli_yxx(server));
262 if (server_list[index] == server) /* Sanity check */
263 server_list[index] = 0;
269 * Register numeric of new, remote, client.
270 * Add it to the appropriate client_list.
272 void SetRemoteNumNick(struct Client* acptr, const char *yxx)
274 struct Client** acptrp;
275 struct Client* server = cli_user(acptr)->server;
277 if (5 == strlen(yxx)) {
278 strcpy(cli_yxx(acptr), yxx + 2);
281 (cli_yxx(acptr))[0] = *++yxx;
282 (cli_yxx(acptr))[1] = *++yxx;
283 (cli_yxx(acptr))[2] = 0;
285 Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr),
286 base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask));
288 acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask];
291 * this exits the old client in the array, not the client
294 exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)");
303 * Register numeric of new, local, client. Add it to our client_list.
304 * Muxtex needed if threaded
306 int SetLocalNumNick(struct Client *cptr)
308 static unsigned int last_nn = 0;
309 struct Client** client_list = cli_serv(&me)->client_list;
310 unsigned int mask = cli_serv(&me)->nn_mask;
311 unsigned int count = 0;
313 assert(cli_user(cptr)->server == &me);
315 while (client_list[last_nn & mask]) {
316 if (++count == NN_MAX_CLIENT) {
317 assert(count < NN_MAX_CLIENT);
320 if (++last_nn == NN_MAX_CLIENT)
323 client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */
325 inttobase64(cli_yxx(cptr), last_nn, 3);
326 if (++last_nn == NN_MAX_CLIENT)
332 * markMatchexServer()
333 * Mark all servers whose name matches the given (compiled) mask
334 * and return their count, abusing FLAGS_MAP for this :)
336 int markMatchexServer(const char *cmask, int minlen)
340 struct Client *acptr;
342 for (i = 0; i < lastNNServer; i++) {
343 if ((acptr = server_list[i])) {
344 if (matchexec(cli_name(acptr), cmask, minlen))
345 cli_flags(acptr) &= ~FLAGS_MAP;
347 cli_flags(acptr) |= FLAGS_MAP;
355 struct Client* find_match_server(char *mask)
357 struct Client *acptr;
360 if (!(BadPtr(mask))) {
362 for (i = 0; i < lastNNServer; i++) {
363 if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr))))