]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/channel.c | |
3 | * Copyright (C) 1996 Carlo Wood (I wish this was C++ - this sucks :/) | |
4 | * | |
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) | |
8 | * any later version. | |
9 | * | |
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. | |
14 | * | |
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. | |
18 | */ | |
19 | /** @file | |
20 | * @brief Implementation of numeric nickname operations. | |
21 | * @version $Id: numnicks.c,v 1.30 2005/05/08 00:56:05 entrope Exp $ | |
22 | */ | |
23 | #include "config.h" | |
24 | ||
25 | #include "numnicks.h" | |
26 | #include "client.h" | |
27 | #include "ircd.h" | |
28 | #include "ircd_alloc.h" | |
29 | #include "ircd_log.h" | |
30 | #include "ircd_string.h" | |
31 | #include "match.h" | |
32 | #include "s_bsd.h" | |
33 | #include "s_debug.h" | |
34 | #include "s_misc.h" | |
35 | #include "struct.h" | |
36 | ||
37 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | ||
42 | ||
43 | /** @page numnicks Numeric Nicks | |
44 | * %Numeric nicks (numnicks) are new as of version ircu2.10.00beta1. | |
45 | * | |
46 | * The idea is as follows: | |
47 | * In most messages (for protocol 10+) the original nick will be | |
48 | * replaced by a 5 character string: YYXXX | |
49 | * Where 'YY' represents the server, and 'XXX' the nick on that server. | |
50 | * | |
51 | * 'YYXXX' should not interfere with the input parser, and therefore is | |
52 | * not allowed to contain spaces or a ':'. | |
53 | * Also, 'YY' can't start with a '+' because of m_server(). | |
54 | * | |
55 | * We keep the characters printable for debugging reasons too. | |
56 | * | |
57 | * The 'XXX' value can be larger then the maximum number of clients | |
58 | * per server, we use a mask (Server::nn_mask) to get the real | |
59 | * client numeric. The overhead is used to have some redundancy so | |
60 | * just-disconnected-client aren't confused with just-connected ones. | |
61 | */ | |
62 | ||
63 | ||
64 | /* These must be the same on ALL servers ! Do not change ! */ | |
65 | ||
66 | /** Number of bits encoded in one numnick character. */ | |
67 | #define NUMNICKLOG 6 | |
68 | /** Bitmask to select value of next numnick character. */ | |
69 | #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */ | |
70 | /** Number of servers representable in a numnick. */ | |
71 | #define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */ | |
72 | /** Number of clients representable in a numnick. */ | |
73 | #define NN_MAX_CLIENT 262144 /* NUMNICKBASE ^ 3 */ | |
74 | ||
75 | /* | |
76 | * The internal counter for the 'XX' of local clients | |
77 | */ | |
78 | /** Maximum used server numnick, plus one. */ | |
79 | static unsigned int lastNNServer = 0; | |
80 | /** Array of servers indexed by numnick. */ | |
81 | static struct Client* server_list[NN_MAX_SERVER]; | |
82 | ||
83 | /* *INDENT-OFF* */ | |
84 | ||
85 | /** | |
86 | * Converts a numeric to the corresponding character. | |
87 | * The following characters are currently known to be forbidden: | |
88 | * | |
89 | * '\\0' : Because we use '\\0' as end of line. | |
90 | * | |
91 | * ' ' : Because parse_*() uses this as parameter separator. | |
92 | * | |
93 | * ':' : Because parse_server() uses this to detect if a prefix is a | |
94 | * numeric or a name. | |
95 | * | |
96 | * '+' : Because m_nick() uses this to determine if parv[6] is a | |
97 | * umode or not. | |
98 | * | |
99 | * '&', '#', '$', '@' and '%' : | |
100 | * Because m_message() matches these characters to detect special cases. | |
101 | */ | |
102 | static const char convert2y[] = { | |
103 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', | |
104 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', | |
105 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', | |
106 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']' | |
107 | }; | |
108 | ||
109 | /** Converts a character to its (base64) numnick value. */ | |
110 | static const unsigned int convert2n[] = { | |
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 | 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0, | |
115 | 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, | |
116 | 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0, | |
117 | 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, | |
118 | 41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0, | |
119 | ||
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, | |
123 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
124 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
125 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
126 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
127 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
128 | }; | |
129 | ||
130 | /* *INDENT-ON* */ | |
131 | ||
132 | /** Convert a string to its value as a numnick. | |
133 | * @param[in] s Numnick string to decode. | |
134 | * @return %Numeric nickname value. | |
135 | */ | |
136 | unsigned int base64toint(const char* s) | |
137 | { | |
138 | unsigned int i = convert2n[(unsigned char) *s++]; | |
139 | while (*s) { | |
140 | i <<= NUMNICKLOG; | |
141 | i += convert2n[(unsigned char) *s++]; | |
142 | } | |
143 | return i; | |
144 | } | |
145 | ||
146 | /** Encode a number as a numnick. | |
147 | * @param[out] buf Output buffer. | |
148 | * @param[in] v Value to encode. | |
149 | * @param[in] count Number of numnick digits to write to \a buf. | |
150 | */ | |
151 | const char* inttobase64(char* buf, unsigned int v, unsigned int count) | |
152 | { | |
153 | buf[count] = '\0'; | |
154 | while (count > 0) { | |
155 | buf[--count] = convert2y[(v & NUMNICKMASK)]; | |
156 | v >>= NUMNICKLOG; | |
157 | } | |
158 | return buf; | |
159 | } | |
160 | ||
161 | /** Look up a server by numnick string. | |
162 | * See @ref numnicks for more details. | |
163 | * @param[in] numeric %Numeric nickname of server (may contain trailing junk). | |
164 | * @return %Server with that numnick (or NULL). | |
165 | */ | |
166 | static struct Client* FindXNServer(const char* numeric) | |
167 | { | |
168 | char buf[3]; | |
169 | buf[0] = *numeric++; | |
170 | buf[1] = *numeric; | |
171 | buf[2] = '\0'; | |
172 | Debug((DEBUG_DEBUG, "FindXNServer: %s(%d)", buf, base64toint(buf))); | |
173 | return server_list[base64toint(buf)]; | |
174 | } | |
175 | ||
176 | /** Look up a server by numnick string. | |
177 | * See @ref numnicks for more details. | |
178 | * @param[in] numeric %Numeric nickname of server. | |
179 | * @return %Server with that numnick (or NULL). | |
180 | */ | |
181 | struct Client* FindNServer(const char* numeric) | |
182 | { | |
183 | unsigned int len = strlen(numeric); | |
184 | ||
185 | if (len < 3) { | |
186 | Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric))); | |
187 | return server_list[base64toint(numeric)]; | |
188 | } | |
189 | else if (len == 3) { | |
190 | Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric, | |
191 | convert2n[(unsigned char) *numeric])); | |
192 | return server_list[convert2n[(unsigned char) *numeric]]; | |
193 | } | |
194 | return FindXNServer(numeric); | |
195 | } | |
196 | ||
197 | /** Look up a user by numnick string. | |
198 | * See @ref numnicks for more details. | |
199 | * @param[in] yxx %Numeric nickname of user. | |
200 | * @return %User with that numnick (or NULL). | |
201 | */ | |
202 | struct Client* findNUser(const char* yxx) | |
203 | { | |
204 | struct Client* server = 0; | |
205 | if (5 == strlen(yxx)) { | |
206 | if (0 != (server = FindXNServer(yxx))) { | |
207 | Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx, | |
208 | base64toint(yxx + 2) & cli_serv(server)->nn_mask)); | |
209 | return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask]; | |
210 | } | |
211 | } | |
212 | else if (0 != (server = FindNServer(yxx))) { | |
213 | Debug((DEBUG_DEBUG, "findNUser: %s(%d)", | |
214 | yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask)); | |
215 | return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask]; | |
216 | } | |
217 | return 0; | |
218 | } | |
219 | ||
220 | /** Remove a client from a server's user array. | |
221 | * @param[in] server %Server that owns the user to remove. | |
222 | * @param[in] yxx Numnick of client to remove. | |
223 | */ | |
224 | void RemoveYXXClient(struct Client* server, const char* yxx) | |
225 | { | |
226 | assert(0 != server); | |
227 | assert(0 != yxx); | |
228 | if (*yxx) { | |
229 | Debug((DEBUG_DEBUG, "RemoveYXXClient: %s(%d)", yxx, | |
230 | base64toint(yxx) & cli_serv(server)->nn_mask)); | |
231 | cli_serv(server)->client_list[base64toint(yxx) & cli_serv(server)->nn_mask] = 0; | |
232 | } | |
233 | } | |
234 | ||
235 | /** Set a server's numeric nick. | |
236 | * @param[in] cptr %Client that announced the server (ignored). | |
237 | * @param[in,out] server %Server that is being assigned a numnick. | |
238 | * @param[in] yxx %Numeric nickname for server. | |
239 | */ | |
240 | void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx) | |
241 | { | |
242 | unsigned int index; | |
243 | if (5 == strlen(yxx)) { | |
244 | ircd_strncpy(cli_yxx(server), yxx, 2); | |
245 | ircd_strncpy(cli_serv(server)->nn_capacity, yxx + 2, 3); | |
246 | } | |
247 | else { | |
248 | (cli_yxx(server))[0] = yxx[0]; | |
249 | cli_serv(server)->nn_capacity[0] = yxx[1]; | |
250 | cli_serv(server)->nn_capacity[1] = yxx[2]; | |
251 | } | |
252 | cli_serv(server)->nn_mask = base64toint(cli_serv(server)->nn_capacity); | |
253 | ||
254 | index = base64toint(cli_yxx(server)); | |
255 | if (index >= lastNNServer) | |
256 | lastNNServer = index + 1; | |
257 | server_list[index] = server; | |
258 | ||
259 | /* Note, exit_one_client uses the fact that `client_list' != NULL to | |
260 | * determine that SetServerYXX has been called - and then calls | |
261 | * ClearServerYXX. However, freeing the allocation happens in free_client() */ | |
262 | cli_serv(server)->client_list = | |
263 | (struct Client**) MyCalloc(cli_serv(server)->nn_mask + 1, sizeof(struct Client*)); | |
264 | } | |
265 | ||
266 | /** Set a server's capacity. | |
267 | * @param[in] c %Server whose capacity is being set. | |
268 | * @param[in] capacity Maximum number of clients the server supports. | |
269 | */ | |
270 | void SetYXXCapacity(struct Client* c, unsigned int capacity) | |
271 | { | |
272 | unsigned int max_clients = 16; | |
273 | /* | |
274 | * Calculate mask to be used for the maximum number of clients | |
275 | */ | |
276 | while (max_clients < capacity) | |
277 | max_clients <<= 1; | |
278 | /* | |
279 | * Sanity checks | |
280 | */ | |
281 | if (max_clients > NN_MAX_CLIENT) { | |
282 | fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d " | |
283 | "too large ! Please decrease this value.\n", | |
284 | max_clients - NN_MAX_CLIENT); | |
285 | exit(-1); | |
286 | } | |
287 | --max_clients; | |
288 | inttobase64(cli_serv(c)->nn_capacity, max_clients, 3); | |
289 | cli_serv(c)->nn_mask = max_clients; /* Our Numeric Nick mask */ | |
290 | cli_serv(c)->client_list = (struct Client**) MyCalloc(max_clients + 1, | |
291 | sizeof(struct Client*)); | |
292 | server_list[base64toint(cli_yxx(c))] = c; | |
293 | } | |
294 | ||
295 | /** Set a server's numeric nick. | |
296 | * See @ref numnicks for more details. | |
297 | * @param[in] c %Server that is being assigned a numnick. | |
298 | * @param[in] numeric Numnick value for server. | |
299 | */ | |
300 | void SetYXXServerName(struct Client* c, unsigned int numeric) | |
301 | { | |
302 | assert(0 != c); | |
303 | assert(numeric < NN_MAX_SERVER); | |
304 | ||
305 | inttobase64(cli_yxx(c), numeric, 2); | |
306 | if (numeric >= lastNNServer) | |
307 | lastNNServer = numeric + 1; | |
308 | server_list[numeric] = c; | |
309 | } | |
310 | ||
311 | /** Unassign a server's numnick. | |
312 | * @param[in] server %Server that should be removed from the numnick table. | |
313 | */ | |
314 | void ClearServerYXX(const struct Client *server) | |
315 | { | |
316 | unsigned int index = base64toint(cli_yxx(server)); | |
317 | if (server_list[index] == server) /* Sanity check */ | |
318 | server_list[index] = 0; | |
319 | } | |
320 | ||
321 | /** Register numeric of new (remote) client. | |
322 | * See @ref numnicks for more details. | |
323 | * Add it to the appropriate client_list. | |
324 | * @param[in] acptr %User being registered. | |
325 | * @param[in] yxx User's numnick. | |
326 | */ | |
327 | void SetRemoteNumNick(struct Client* acptr, const char *yxx) | |
328 | { | |
329 | struct Client** acptrp; | |
330 | struct Client* server = cli_user(acptr)->server; | |
331 | ||
332 | if (5 == strlen(yxx)) { | |
333 | strcpy(cli_yxx(acptr), yxx + 2); | |
334 | } | |
335 | else { | |
336 | (cli_yxx(acptr))[0] = *++yxx; | |
337 | (cli_yxx(acptr))[1] = *++yxx; | |
338 | (cli_yxx(acptr))[2] = 0; | |
339 | } | |
340 | Debug((DEBUG_DEBUG, "SetRemoteNumNick: %s(%d)", cli_yxx(acptr), | |
341 | base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask)); | |
342 | ||
343 | acptrp = &(cli_serv(server))->client_list[base64toint(cli_yxx(acptr)) & cli_serv(server)->nn_mask]; | |
344 | if (*acptrp) { | |
345 | /* | |
346 | * this exits the old client in the array, not the client | |
347 | * that is being set | |
348 | */ | |
349 | exit_client(cli_from(acptr), *acptrp, server, "Numeric nick collision (Ghost)"); | |
350 | } | |
351 | *acptrp = acptr; | |
352 | } | |
353 | ||
354 | ||
355 | /** Register numeric of new (local) client. | |
356 | * See @ref numnicks for more details. | |
357 | * Assign a numnick and add it to our client_list. | |
358 | * @param[in] cptr %User being registered. | |
359 | */ | |
360 | int SetLocalNumNick(struct Client *cptr) | |
361 | { | |
362 | static unsigned int last_nn = 0; | |
363 | struct Client** client_list = cli_serv(&me)->client_list; | |
364 | unsigned int mask = cli_serv(&me)->nn_mask; | |
365 | unsigned int count = 0; | |
366 | ||
367 | assert(cli_user(cptr)->server == &me); | |
368 | ||
369 | while (client_list[last_nn & mask]) { | |
370 | if (++count == NN_MAX_CLIENT) { | |
371 | assert(count < NN_MAX_CLIENT); | |
372 | return 0; | |
373 | } | |
374 | if (++last_nn == NN_MAX_CLIENT) | |
375 | last_nn = 0; | |
376 | } | |
377 | client_list[last_nn & mask] = cptr; /* Reserve the numeric ! */ | |
378 | ||
379 | inttobase64(cli_yxx(cptr), last_nn, 3); | |
380 | if (++last_nn == NN_MAX_CLIENT) | |
381 | last_nn = 0; | |
382 | return 1; | |
383 | } | |
384 | ||
385 | /** Mark servers whose name matches the given (compiled) mask by | |
386 | * setting their FLAG_MAP flag. | |
387 | * @param[in] cmask Compiled mask for server names. | |
388 | * @param[in] minlen Minimum match length for \a cmask. | |
389 | * @return Number of servers marked. | |
390 | */ | |
391 | int markMatchexServer(const char *cmask, int minlen) | |
392 | { | |
393 | int cnt = 0; | |
394 | int i; | |
395 | struct Client *acptr; | |
396 | ||
397 | for (i = 0; i < lastNNServer; i++) { | |
398 | if ((acptr = server_list[i])) | |
399 | { | |
400 | if (matchexec(cli_name(acptr), cmask, minlen)) | |
401 | ClrFlag(acptr, FLAG_MAP); | |
402 | else | |
403 | { | |
404 | SetFlag(acptr, FLAG_MAP); | |
405 | cnt++; | |
406 | } | |
407 | } | |
408 | } | |
409 | return cnt; | |
410 | } | |
411 | ||
412 | /** Find first server whose name matches the given mask. | |
413 | * @param[in,out] mask %Server name mask (collapse()d in-place). | |
414 | * @return Matching server with lowest numnick value (or NULL). | |
415 | */ | |
416 | struct Client* find_match_server(char *mask) | |
417 | { | |
418 | struct Client *acptr; | |
419 | int i; | |
420 | ||
421 | if (!(BadPtr(mask))) { | |
422 | collapse(mask); | |
423 | for (i = 0; i < lastNNServer; i++) { | |
424 | if ((acptr = server_list[i]) && (!match(mask, cli_name(acptr)))) | |
425 | return acptr; | |
426 | } | |
427 | } | |
428 | return 0; | |
429 | } | |
430 | ||
431 | /** Encode an IP address in the base64 used by numnicks. | |
432 | * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6 | |
433 | * addresses), the 32-bit host address is encoded directly as six | |
434 | * characters. | |
435 | * | |
436 | * For IPv6 addresses, each 16-bit address segment is encoded as three | |
437 | * characters, but the longest run of zero segments is encoded using an | |
438 | * underscore. | |
439 | * @param[out] buf Output buffer to write to. | |
440 | * @param[in] addr IP address to encode. | |
441 | * @param[in] count Number of bytes writable to \a buf. | |
442 | * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses. | |
443 | */ | |
444 | const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok) | |
445 | { | |
446 | if (irc_in_addr_is_ipv4(addr)) { | |
447 | assert(count >= 6); | |
448 | inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6); | |
449 | } else if (!v6_ok) { | |
450 | assert(count >= 6); | |
451 | if (addr->in6_16[0] == htons(0x2002)) | |
452 | inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6); | |
453 | else | |
454 | strcpy(buf, "AAAAAA"); | |
455 | } else { | |
456 | unsigned int max_start, max_zeros, curr_zeros, zero, ii; | |
457 | char *output = buf; | |
458 | ||
459 | assert(count >= 25); | |
460 | /* Can start by printing out the leading non-zero parts. */ | |
461 | for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) { | |
462 | inttobase64(output, ntohs(addr->in6_16[ii]), 3); | |
463 | output += 3; | |
464 | } | |
465 | /* Find the longest run of zeros. */ | |
466 | for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) { | |
467 | if (!addr->in6_16[ii]) | |
468 | curr_zeros++; | |
469 | else if (curr_zeros > max_zeros) { | |
470 | max_start = ii - curr_zeros; | |
471 | max_zeros = curr_zeros; | |
472 | curr_zeros = 0; | |
473 | } | |
474 | } | |
475 | if (curr_zeros > max_zeros) { | |
476 | max_start = ii - curr_zeros; | |
477 | max_zeros = curr_zeros; | |
478 | curr_zeros = 0; | |
479 | } | |
480 | /* Print the rest of the address */ | |
481 | for (ii = zero; ii < 8; ) { | |
482 | if ((ii == max_start) && max_zeros) { | |
483 | *output++ = '_'; | |
484 | ii += max_zeros; | |
485 | } else { | |
486 | inttobase64(output, ntohs(addr->in6_16[ii]), 3); | |
487 | output += 3; | |
488 | ii++; | |
489 | } | |
490 | } | |
491 | *output = '\0'; | |
492 | } | |
493 | return buf; | |
494 | } | |
495 | ||
496 | /** Decode an IP address from base64. | |
497 | * @param[in] input Input buffer to decode. | |
498 | * @param[out] addr IP address structure to populate. | |
499 | */ | |
500 | void base64toip(const char* input, struct irc_in_addr* addr) | |
501 | { | |
502 | memset(addr, 0, sizeof(*addr)); | |
503 | if (strlen(input) == 6) { | |
504 | unsigned int in = base64toint(input); | |
505 | /* An all-zero address should stay that way. */ | |
506 | if (in) { | |
507 | addr->in6_16[5] = htons(65535); | |
508 | addr->in6_16[6] = htons(in >> 16); | |
509 | addr->in6_16[7] = htons(in & 65535); | |
510 | } | |
511 | } else { | |
512 | unsigned int pos = 0; | |
513 | do { | |
514 | if (*input == '_') { | |
515 | unsigned int left; | |
516 | for (left = (25 - strlen(input)) / 3 - pos; left; left--) | |
517 | addr->in6_16[pos++] = 0; | |
518 | input++; | |
519 | } else { | |
520 | unsigned short accum = convert2n[(unsigned char)*input++]; | |
521 | accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++]; | |
522 | accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++]; | |
523 | addr->in6_16[pos++] = ntohs(accum); | |
524 | } | |
525 | } while (pos < 8); | |
526 | } | |
527 | } |