]>
jfr.im git - irc/evilnet/x3.git/blob - src/tools.c
1 /* tools.c - miscellaneous utility functions
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
32 #ifdef HAVE_ARPA_INET_H
33 #include <arpa/inet.h>
37 #define NUMNICKBASE (1 << NUMNICKLOG)
38 #define NUMNICKMASK (NUMNICKBASE - 1)
40 /* Yes, P10's encoding here is almost-but-not-quite MIME Base64. Yay
41 * for gratuitous incompatibilities. */
42 static const char convert2y
[256] = {
43 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
44 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
45 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
46 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
49 static const unsigned char convert2n
[256] = {
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
54 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
55 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
56 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
57 41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0
60 static const unsigned char ctype
[256] = {
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
65 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 base64toint(const char* s
, int count
)
75 i
= (i
<< NUMNICKLOG
) + convert2n
[(unsigned char)*s
++];
81 const char* inttobase64(char* buf
, unsigned int v
, unsigned int count
)
85 buf
[--count
] = convert2y
[(unsigned char)(v
& NUMNICKMASK
)];
92 irc_ntop(char *output
, unsigned int out_size
, const irc_in_addr_t
*addr
)
94 static const char hexdigits
[] = "0123456789abcdef";
100 if (irc_in_addr_is_ipv4(*addr
)) {
103 ip4
= (ntohs(addr
->in6
[6]) << 16) | ntohs(addr
->in6
[7]);
104 pos
= snprintf(output
, out_size
, "%u.%u.%u.%u", (ip4
>> 24), (ip4
>> 16) & 255, (ip4
>> 8) & 255, ip4
& 255);
106 unsigned int part
, max_start
, max_zeros
, curr_zeros
, ii
;
108 /* Find longest run of zeros. */
109 for (max_start
= max_zeros
= curr_zeros
= ii
= 0; ii
< 8; ++ii
) {
112 else if (curr_zeros
> max_zeros
) {
113 max_start
= ii
- curr_zeros
;
114 max_zeros
= curr_zeros
;
118 if (curr_zeros
> max_zeros
) {
119 max_start
= ii
- curr_zeros
;
120 max_zeros
= curr_zeros
;
123 /* Print out address. */
124 #define APPEND(CH) do { if (pos < out_size) output[pos] = (CH); pos++; } while (0)
125 for (pos
= 0, ii
= 0; ii
< 8; ++ii
) {
126 if ((max_zeros
> 0) && (ii
== max_start
)) {
133 part
= ntohs(addr
->in6
[ii
]);
135 APPEND(hexdigits
[part
>> 12]);
137 APPEND(hexdigits
[(part
>> 8) & 15]);
139 APPEND(hexdigits
[(part
>> 4) & 15]);
140 APPEND(hexdigits
[part
& 15]);
145 output
[pos
< out_size
? pos
: out_size
- 1] = '\0';
152 irc_ntop_mask(char *output
, unsigned int out_size
, const irc_in_addr_t
*addr
, unsigned char bits
)
154 char base_addr
[IRC_NTOP_MAX_SIZE
];
158 return irc_ntop(output
, out_size
, addr
);
159 if (!irc_ntop(base_addr
, sizeof(base_addr
), addr
))
161 len
= snprintf(output
, out_size
, "%s/%d", base_addr
, bits
);
162 if ((unsigned int)len
>= out_size
)
168 irc_pton_ip4(const char *input
, unsigned char *pbits
, uint32_t *output
)
170 unsigned int dots
= 0, pos
= 0, part
= 0, ip
= 0, bits
= 32;
172 /* Intentionally no support for bizarre IPv4 formats (plain
173 * integers, octal or hex components) -- only vanilla dotted
174 * decimal quads, optionally with trailing /nn.
178 while (1) switch (input
[pos
]) {
183 ip
|= part
<< (24 - 8 * dots
++);
189 if (input
[++pos
] == '.')
191 ip
|= part
<< (24 - 8 * dots
++);
193 if (input
[pos
] == '*') {
194 while (input
[++pos
] == '*') ;
195 if (input
[pos
] != '\0')
204 if (!pbits
|| !isdigit(input
[pos
+ 1]))
206 for (bits
= 0; isdigit(input
[++pos
]); )
207 bits
= bits
* 10 + input
[pos
] - '0';
211 case '0': case '1': case '2': case '3': case '4':
212 case '5': case '6': case '7': case '8': case '9':
213 part
= part
* 10 + input
[pos
++] - '0';
221 irc_pton(irc_in_addr_t
*addr
, unsigned char *bits
, const char *input
)
223 const char *part_start
= NULL
;
226 unsigned int part
= 0, pos
= 0, ii
= 0, cpos
= 8;
229 memset(addr
, 0, sizeof(*addr
));
230 colon
= strchr(input
, ':');
231 dot
= strchr(input
, '.');
233 if (colon
&& (!dot
|| (dot
> colon
))) {
234 /* Parse IPv6, possibly like ::127.0.0.1.
235 * This is pretty straightforward; the only trick is borrowed
236 * from Paul Vixie (BIND): when it sees a "::" continue as if
237 * it were a single ":", but note where it happened, and fill
238 * with zeros afterwards.
240 if (input
[pos
] == ':') {
241 if ((input
[pos
+1] != ':') || (input
[pos
+2] == ':'))
245 part_start
= input
+ pos
;
247 while (ii
< 8) switch (input
[pos
]) {
248 case '0': case '1': case '2': case '3': case '4':
249 case '5': case '6': case '7': case '8': case '9':
250 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
251 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
252 part
= (part
<< 4) | (ctype
[(unsigned char)input
[pos
++]] & 15);
257 part_start
= input
+ ++pos
;
258 if (input
[pos
] == '.')
260 addr
->in6
[ii
++] = htons(part
);
262 if (input
[pos
] == ':') {
271 len
= irc_pton_ip4(part_start
, bits
, &ip4
);
272 if (!len
|| (ii
> 6))
274 memcpy(addr
->in6
+ ii
, &ip4
, sizeof(ip4
));
278 pos
= part_start
+ len
- input
;
282 if (!bits
|| !isdigit(input
[pos
+ 1]))
284 addr
->in6
[ii
++] = htons(part
);
285 for (part
= 0; isdigit(input
[++pos
]); )
286 part
= part
* 10 + input
[pos
] - '0';
292 while (input
[++pos
] == '*') ;
293 if (input
[pos
] != '\0' || cpos
< 8)
299 addr
->in6
[ii
++] = htons(part
);
300 if (cpos
== 8 && ii
< 8)
307 /* Shift stuff after "::" up and fill middle with zeros. */
310 for (jj
= 0; jj
< ii
- cpos
; jj
++)
311 addr
->in6
[7 - jj
] = addr
->in6
[ii
- jj
- 1];
312 for (jj
= 0; jj
< 8 - ii
; jj
++)
313 addr
->in6
[cpos
+ jj
] = 0;
317 pos
= irc_pton_ip4(input
, bits
, &ip4
);
319 addr
->in6
[5] = htons(65535);
320 addr
->in6
[6] = htons(ntohl(ip4
) >> 16);
321 addr
->in6
[7] = htons(ntohl(ip4
) & 65535);
325 } else if (input
[0] == '*') {
326 while (input
[++pos
] == '*') ;
327 if (input
[pos
] != '\0')
335 const char *irc_ntoa(const irc_in_addr_t
*addr
)
337 static char ntoa
[IRC_NTOP_MAX_SIZE
];
338 irc_ntop(ntoa
, sizeof(ntoa
), addr
);
343 irc_check_mask(const irc_in_addr_t
*check
, const irc_in_addr_t
*mask
, unsigned char bits
)
347 for (ii
= 0; (ii
< 8) && (bits
> 16); bits
-= 16, ++ii
)
348 if (check
->in6
[ii
] != mask
->in6
[ii
])
350 if (ii
< 8 && bits
> 0
351 && (ntohs(check
->in6
[ii
] ^ mask
->in6
[ii
]) >> (16 - bits
)))
356 static char irc_tolower
[256];
358 #define tolower(X) irc_tolower[(unsigned char)(X)]
361 irc_strtolower(char *str
) {
363 for(p
= str
;*p
;p
++) {
369 irccasecmp(const char *stra
, const char *strb
) {
374 while (*stra
&& (tolower(*stra
) == tolower(*strb
)))
376 return tolower(*stra
) - tolower(*strb
);
380 ircncasecmp(const char *stra
, const char *strb
, unsigned int len
) {
382 while (*stra
&& (tolower(*stra
) == tolower(*strb
)) && len
)
383 stra
++, strb
++, len
--;
384 return tolower(*stra
) - tolower(*strb
);
388 irccasestr(const char *haystack
, const char *needle
) {
389 unsigned int hay_len
= strlen(haystack
), needle_len
= strlen(needle
), pos
;
390 if (hay_len
< needle_len
)
392 for (pos
=0; pos
<hay_len
+1-needle_len
; ++pos
) {
393 if ((tolower(haystack
[pos
]) == tolower(*needle
))
394 && !ircncasecmp(haystack
+pos
, needle
, needle_len
))
401 ircstrlower(char *str
) {
403 for (ii
= 0; str
[ii
] != '\0'; ++ii
)
404 str
[ii
] = tolower(str
[ii
]);
409 split_line(char *line
, int irc_colon
, int argv_size
, char *argv
[])
413 while (*line
&& (argc
< argv_size
)) {
416 if (*line
== ':' && irc_colon
&& argc
> 0) {
417 /* the rest is a single parameter */
418 argv
[argc
++] = line
+ 1;
424 if (argc
>= argv_size
)
426 while (*line
!= ' ' && *line
)
432 for (n
=argc
; n
<argv_size
; n
++)
433 argv
[n
] = (char*)0xFEEDBEEF;
438 /* This is ircu's mmatch() function, from match.c. */
439 int mmatch(const char *old_mask
, const char *new_mask
)
441 register const char *m
= old_mask
;
442 register const char *n
= new_mask
;
463 for (m
--; (m
> old_mask
) && (*m
== '?'); m
--)
465 if ((*m
== '*') && (m
> old_mask
) && (m
[-1] != '\\'))
471 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
472 if ((*na
== '\\') && ((na
[1] == '*') || (na
[1] == '?')))
483 if ((*m
== '\\') && ((m
[1] == '*') || (m
[1] == '?')))
491 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
492 if ((*n
== '\\') && ((n
[1] == '*') || (n
[1] == '?')))
501 * This `if' has been changed compared to match() to do the following:
503 * old (m) new (n) boolean expression
504 * * any (*m == '*' && !mq) ||
505 * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
506 * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
507 * toLower(*m) == toLower(*n) &&
508 * !((mq && !nq) || (!mq && nq)))
510 * Here `any' also includes \* and \? !
512 * After reworking the boolean expressions, we get:
513 * (Optimized to use boolean shortcircuits, with most frequently occuring
514 * cases upfront (which took 2 hours!)).
516 if ((*m
== '*' && !mq
) ||
517 ((!mq
|| nq
) && tolower(*m
) == tolower(*n
)) ||
518 (*m
== '?' && !mq
&& (*n
!= '*' || nq
)))
531 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
532 if ((*na
== '\\') && ((na
[1] == '*') || (na
[1] == '?')))
541 match_ircglob(const char *text
, const char *glob
)
543 const char *m
= glob
, *n
= text
;
544 const char *m_tmp
= glob
, *n_tmp
= text
;
547 for (;;) switch (*m
) {
561 /* allow escaping to force capitalization */
566 for (star_p
= 0; ; m
++) {
569 else if (*m
== '?') {
577 else if (*m
== '\\') {
581 for (n_tmp
= n
; *n
&& *n
!= *m
; n
++) ;
584 for (n_tmp
= n
; *n
&& tolower(*n
) != tolower(*m
); n
++) ;
587 /* and fall through */
591 if (tolower(*m
) != tolower(*n
))
599 extern const char *hidden_host_suffix
;
601 /* Prevent *@* *@** *@*a* type masks, while allowing anything else. This is the best way iv found to detect
602 * a global matching mask; if it matches this string, it'll match almost anything :) */
603 int is_overmask(char *mask
)
605 return(match_ircglob("abcdefghijklmnopqrstuv!frcmbghilnrtoasde@apdic.yfa.dsfsdaffsdasfdasfd.abcdefghijklmnopqrstuvwxyz.asdfasfdfsdsfdasfda.ydfbe", mask
));
609 user_matches_glob(struct userNode
*user
, const char *orig_glob
, int flags
, int shared
)
611 char *tmpglob
, *glob
, *marker
;
613 int extreverse
= 0, is_extended
= 0, match
= 0, banned
= 0;
614 unsigned int count
, n
;
616 struct chanNode
*channel
;
619 /* Make a writable copy of the glob */
620 glob
= alloca(strlen(orig_glob
)+1);
621 strcpy(glob
, orig_glob
);
624 tmpglob
= alloca(strlen(orig_glob
)+1);
625 tmpglob
= strdup(orig_glob
);
627 if (*tmpglob
== '~') {
628 tmpglob
++; /* get rid of the ~ */
630 if (*tmpglob
== '!') {
632 tmpglob
++; /* get rid of the ! */
636 tmpglob
++; /* get rid of the type */
638 if (*tmpglob
== ':') {
640 tmpglob
++; /* get rid of the : */
641 glob
= strdup(tmpglob
);
646 log_module(MAIN_LOG
, LOG_DEBUG
, "Extended ban. T (%c) R (%d) M (%s)", exttype
, extreverse
, glob
);
649 if (user
->handle_info
) {
651 if (0 != strcasecmp(glob
, user
->handle_info
->handle
))
654 if (0 == strcasecmp(glob
, user
->handle_info
->handle
))
661 return match_ircglob(user
->hostname
, glob
);
662 case 'c': // another channel
663 if (!strstr(glob
, "#"))
667 for (n
=count
=0; n
<user
->channels
.used
; n
++) {
668 mn
= user
->channels
.list
[n
];
672 if (0 == strcasecmp(glob
, mn
->channel
->name
))
675 if (0 == strcasecmp(glob
+1, mn
->channel
->name
)) {
676 if ((*glob
== '@') && (mn
->modes
& MODE_CHANOP
))
678 else if ((*glob
== '%') && (mn
->modes
& MODE_HALFOP
))
680 else if ((*glob
== '+') && (mn
->modes
& MODE_VOICE
))
693 for (n
=count
=0; n
<user
->channels
.used
; n
++) {
694 mn
= user
->channels
.list
[n
];
698 if (0 == strcasecmp(glob
, mn
->channel
->name
))
701 if (0 == strcasecmp(glob
+1, mn
->channel
->name
)) {
702 if ((*glob
== '@') && (mn
->modes
& MODE_CHANOP
))
704 else if ((*glob
== '%') && (mn
->modes
& MODE_HALFOP
))
706 else if ((*glob
== '+') && (mn
->modes
& MODE_VOICE
))
719 return match_ircglob(user
->hostname
, glob
);
724 if ((channel
= GetChannel(glob
))) {
725 for (n
= 0; n
< channel
->banlist
.used
; n
++) {
726 ban
= channel
->banlist
.list
[n
];
727 if (user_matches_glob(user
, ban
->ban
, flags
, 1))
732 return match_ircglob(user
->hostname
, glob
);
733 case 'n': /* this is handled ircd side */
734 return match_ircglob(user
->hostname
, glob
);
735 case 'q': /* this is handled ircd side */
736 return match_ircglob(user
->hostname
, glob
);
737 case 't': /* this is handled ircd side */
738 return match_ircglob(user
->hostname
, glob
);
739 case 'R': /* this is handled ircd side */
740 return match_ircglob(user
->hostname
, glob
);
741 case 'm': // mute by mark
742 if(user
->mark
&& !strcmp(glob
, user
->mark
))
747 case 'M': // mute by mark unless authed
748 return false; // can never match a logged in user
755 /* Check the nick, if it's present */
756 if (flags
& MATCH_USENICK
) {
757 if (!(marker
= strchr(glob
, '!'))) {
758 log_module(MAIN_LOG
, LOG_ERROR
, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user
->nick
, orig_glob
, flags
);
762 if (!match_ircglob(user
->nick
, glob
)) return 0;
765 /* Check the ident */
766 if (!(marker
= strchr(glob
, '@'))) {
767 log_module(MAIN_LOG
, LOG_ERROR
, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user
->nick
, orig_glob
, flags
);
771 if (!match_ircglob(user
->ident
, glob
))
774 /* Check for a fakehost match. */
775 if (IsFakeHost(user
) && match_ircglob(user
->fakehost
, glob
))
778 /* Check for a sethost (S:lines) */
779 if (IsSetHost(user
) && match_ircglob(user
->sethost
, glob
))
782 /* Check for an account match. */
783 if (hidden_host_suffix
&& user
->handle_info
) {
784 char hidden_host
[HOSTLEN
+1];
785 snprintf(hidden_host
, sizeof(hidden_host
), "%s.%s", user
->handle_info
->handle
, hidden_host_suffix
);
786 if (match_ircglob(hidden_host
, glob
))
790 /* Match crypt hostname */
791 if (match_ircglob(user
->crypthost
, glob
))
795 if (match_ircglob(user
->cryptip
, glob
))
798 /* If only matching the visible hostnames, bail early. */
799 if ((flags
& MATCH_VISIBLE
) && IsHiddenHost(user
)
800 && (IsFakeHost(user
) || (hidden_host_suffix
&& user
->handle_info
) ||
801 user
->crypthost
|| user
->cryptip
))
803 /* If it might be an IP glob, test that. */
804 if (!glob
[strspn(glob
, "0123456789./*?")]
805 && match_ircglob(irc_ntoa(&user
->ip
), glob
))
807 /* None of the above; could only be a hostname match. */
808 return match_ircglob(user
->hostname
, glob
);
812 is_ircmask(const char *text
)
817 tmptext
= alloca(strlen(text
)+1);
818 tmptext
= strdup(text
);
820 tmptext
++; /* get rid of the ~ */
823 tmptext
++; /* get rid of the ! if it exists */
825 tmptext
++; /* get rid of the ext ban type */
827 if (*tmptext
== ':') {
828 tmptext
++; /* get rid of the : */
829 while (*tmptext
&& !isspace((char)*tmptext
))
830 tmptext
++; /* get rid of the rest */
835 while (*text
&& (isalnum((char)*text
) || strchr("-_[]|\\`^{}?*", *text
)))
839 while (*text
&& *text
!= '@' && !isspace((char)*text
))
843 while (*text
&& !isspace((char)*text
))
849 is_gline(const char *text
)
853 text
+= strcspn(text
, "@!% \t\r\n");
858 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
864 is_shun(const char *text
)
868 text
+= strcspn(text
, "@!% \t\r\n");
873 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
879 split_ircmask(char *text
, char **nick
, char **ident
, char **host
)
884 while (isalnum((char)*text
) || strchr("=[]\\`^{}?*", *text
))
886 if (*text
!= '!' || ((text
- start
) > NICKLEN
))
893 while (*text
&& *text
!= '@' && !isspace((char)*text
))
895 if (*text
!= '@' || ((text
- start
) > USERLEN
))
902 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
906 return !*text
&& ((text
- start
) <= HOSTLEN
) && nick
&& ident
&& host
;
910 sanitize_ircmask(char *input
)
912 unsigned int length
, flag
;
913 char *mask
, *start
, *output
;
915 /* Sanitize everything in place; input *must* be a valid
920 /* The nick is truncated at the end. */
923 while(*input
++ != '!')
932 /* This flag is used to indicate following parts should
941 /* The ident and host must be truncated at the beginning and
942 replaced with a '*' to be compatible with ircu. */
945 while(*input
++ != '@')
949 if(length
> USERLEN
|| flag
)
953 start
= input
- USERLEN
;
975 if(length
> HOSTLEN
|| flag
)
979 start
= input
- HOSTLEN
;
993 TypeLength(char type
)
996 case 'y': return 365*24*60*60;
997 case 'M': return 30*24*60*60;
998 case 'w': return 7*24*60*60;
999 case 'd': return 24*60*60;
1000 case 'h': return 60*60;
1001 case 'm': return 60;
1007 /* This function is not entirely accurate as it does not take into account leap units
1008 * or varying months. TODO: use proper dateadd functions to calculate real seconds
1009 * from now for the units (eg 1M should be give us seconds till todays date next month)
1012 ParseInterval(const char *interval
)
1014 unsigned long seconds
= 0;
1018 /* process the string, resetting the count if we find a unit character */
1019 while ((c
= *interval
++)) {
1020 if (isdigit((int)c
)) {
1021 partial
= partial
*10 + c
- '0';
1022 } else if (strchr("yMwdhms", c
)) {
1023 seconds
+= TypeLength(c
) * partial
;
1029 /* assume the last chunk is seconds (the normal case) */
1030 return seconds
+ partial
;
1034 GetSizeMultiplier(char type
)
1037 case 'G': case 'g': return 1024*1024*1024;
1038 case 'M': case 'm': return 1024*1024;
1039 case 'K': case 'k': return 1024;
1040 case 'B': case 'b': return 1;
1046 ParseVolume(const char *volume
)
1048 unsigned long accum
= 0, partial
= 0;
1050 while ((c
= *volume
++)) {
1051 if (isdigit((int)c
)) {
1052 partial
= partial
*10 + c
- '0';
1054 accum
+= GetSizeMultiplier(c
) * partial
;
1058 return accum
+ partial
;
1062 unsplit_string(char *set
[], unsigned int max
, char *dest
)
1064 static char unsplit_buffer
[MAXLEN
*2];
1065 unsigned int ii
, jj
, pos
;
1068 dest
= unsplit_buffer
;
1069 for (ii
=pos
=0; ii
<max
; ii
++) {
1070 for (jj
=0; set
[ii
][jj
]; jj
++)
1071 dest
[pos
++] = set
[ii
][jj
];
1079 intervalString(char *output
, time_t interval
, struct handle_info
*hi
)
1081 static const struct {
1082 const char *msg_single
;
1083 const char *msg_plural
;
1086 { "MSG_YEAR", "MSG_YEARS", 365 * 24 * 60 * 60 },
1087 { "MSG_WEEK", "MSG_WEEKS", 7 * 24 * 60 * 60 },
1088 { "MSG_DAY", "MSG_DAYS", 24 * 60 * 60 },
1089 { "MSG_HOUR", "MSG_HOURS", 60 * 60 },
1090 { "MSG_MINUTE", "MSG_MINUTES", 60 },
1091 { "MSG_SECOND", "MSG_SECONDS", 1 }
1093 struct language
*lang
;
1095 unsigned int type
, words
, pos
, count
;
1097 lang
= hi
? hi
->language
: lang_C
;
1100 msg
= language_find_message(lang
, "MSG_0_SECONDS");
1101 return strcpy(output
, msg
);
1104 for (type
= 0, words
= pos
= 0;
1105 interval
&& (words
< 2) && (type
< ArrayLength(unit
));
1107 if (interval
< unit
[type
].length
)
1109 count
= interval
/ unit
[type
].length
;
1110 interval
= interval
% unit
[type
].length
;
1113 msg
= language_find_message(lang
, "MSG_AND");
1114 pos
+= sprintf(output
+ pos
, "%s ", msg
);
1117 msg
= language_find_message(lang
, unit
[type
].msg_single
);
1119 msg
= language_find_message(lang
, unit
[type
].msg_plural
);
1120 pos
+= sprintf(output
+ pos
, "%d%s", count
, msg
);
1128 getipbyname(const char *name
, unsigned long *ip
)
1130 struct hostent
*he
= gethostbyname(name
);
1133 if (he
->h_addrtype
!= AF_INET
)
1135 memcpy(ip
, he
->h_addr_list
[0], sizeof(*ip
));
1139 DEFINE_LIST(string_buffer
, char)
1142 string_buffer_append_substring(struct string_buffer
*buf
, const char *tail
, unsigned int len
)
1144 while (buf
->used
+ len
>= buf
->size
) {
1149 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
1151 memcpy(buf
->list
+ buf
->used
, tail
, len
+1);
1156 string_buffer_append_string(struct string_buffer
*buf
, const char *tail
)
1158 string_buffer_append_substring(buf
, tail
, strlen(tail
));
1162 string_buffer_append_vprintf(struct string_buffer
*buf
, const char *fmt
, va_list args
)
1168 VA_COPY(working
, args
);
1170 if (!buf
->list
|| ((buf
->used
+ buf
->size
) < len
)) {
1171 buf
->size
= buf
->used
+ len
;
1172 buf
->list
= realloc(buf
->list
, buf
->size
);
1174 ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
);
1176 /* pre-C99 behavior; double buffer size until it is big enough */
1178 VA_COPY(working
, args
);
1179 while ((ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
)) <= 0) {
1181 buf
->list
= realloc(buf
->list
, buf
->size
);
1183 VA_COPY(working
, args
);
1186 } else if (buf
->used
+ ret
< buf
->size
) {
1187 /* no need to increase allocation size */
1190 /* now we know exactly how much space we need */
1191 if (buf
->size
<= buf
->used
+ ret
) {
1192 buf
->size
= buf
->used
+ ret
+ 1;
1193 buf
->list
= realloc(buf
->list
, buf
->size
);
1196 VA_COPY(working
, args
);
1197 buf
->used
+= vsnprintf(buf
->list
+ buf
->used
, buf
->size
, fmt
, working
);
1203 void string_buffer_append_printf(struct string_buffer
*buf
, const char *fmt
, ...)
1206 va_start(args
, fmt
);
1207 string_buffer_append_vprintf(buf
, fmt
, args
);
1211 string_buffer_replace(struct string_buffer
*buf
, unsigned int from
, unsigned int len
, const char *repl
)
1213 unsigned int repl_len
= strlen(repl
);
1214 if (from
> buf
->used
)
1216 if (len
+ from
> buf
->used
)
1217 len
= buf
->used
- from
;
1218 buf
->used
= buf
->used
+ repl_len
- len
;
1219 if (buf
->size
<= buf
->used
) {
1220 while (buf
->used
>= buf
->size
)
1222 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
1224 memmove(buf
->list
+from
+repl_len
, buf
->list
+from
+len
, strlen(buf
->list
+from
+len
));
1225 strcpy(buf
->list
+from
, repl
);
1228 struct string_list str_tab
;
1231 strtab(unsigned int ii
) {
1234 if (ii
> str_tab
.size
) {
1235 unsigned int old_size
= str_tab
.size
;
1236 while (ii
>= str_tab
.size
)
1238 str_tab
.list
= realloc(str_tab
.list
, str_tab
.size
*sizeof(str_tab
.list
[0]));
1239 memset(str_tab
.list
+old_size
, 0, (str_tab
.size
-old_size
)*sizeof(str_tab
.list
[0]));
1241 if (!str_tab
.list
[ii
]) {
1242 str_tab
.list
[ii
] = malloc(12);
1243 sprintf(str_tab
.list
[ii
], "%u", ii
);
1245 return str_tab
.list
[ii
];
1251 unsigned int upr
, lwr
;
1252 for (lwr
=0; lwr
<256; ++lwr
)
1254 for (upr
='A', lwr
='a'; lwr
<= 'z'; ++upr
, ++lwr
)
1256 #ifdef WITH_PROTOCOL_P10
1257 for (upr
='[', lwr
='{'; lwr
<= '~'; ++upr
, ++lwr
)
1259 for (upr
=0xc0, lwr
=0xe0; lwr
<= 0xf6; ++upr
, ++lwr
)
1261 for (upr
=0xd8, lwr
=0xf8; lwr
<= 0xfe; ++upr
, ++lwr
)
1264 str_tab
.size
= 1001;
1265 str_tab
.list
= calloc(str_tab
.size
, sizeof(str_tab
.list
[0]));
1272 for (ii
=0; ii
<str_tab
.size
; ++ii
)
1273 free(str_tab
.list
[ii
]);
1277 /* mysep() is my answer to the strtok/strsep
1278 * issue. strsep is nice but doesn't skip
1279 * multiple dilimiters, which can really
1280 * offset tokens and cause huge corruption
1281 * so this function will use strsep but
1282 * act like strtok in that sense.
1284 char *mysep(char **sepstr
, char *delim
)
1286 static char *retstr
;
1288 if(!*sepstr
|| !**sepstr
)
1293 retstr
= strsep(sepstr
, delim
);
1294 }while (retstr
&& !(*retstr
));
1299 /* Mallocing snprintf *
1301 * If it overruns size, it will simply be safely truncated.
1304 x3_msnprintf(const int size
, const char *format
, ...)
1307 char* buff
= calloc(sizeof(char *), size
+1);
1309 va_start(ap
, format
);
1310 vsnprintf(buff
, size
, format
, ap
);
1312 buff
= realloc(buff
, strlen(buff
) + 1);
1316 char *time2str(time_t thetime
)
1320 buf
= ctime(&thetime
);
1321 tmp
= (char *)strchr(buf
, '\n');
1326 char* x3_strtok(char **save
, char *str
, char *fs
)
1328 char *pos
= *save
; /* keep last position across calls */
1332 pos
= str
; /* new string scan */
1334 while (pos
&& *pos
&& strchr(fs
, *pos
) != NULL
)
1335 pos
++; /* skip leading separators */
1338 return (pos
= *save
= NULL
); /* string contains only sep's */
1340 tmp
= pos
; /* now, keep position of the token */
1342 while (*pos
&& strchr(fs
, *pos
) == NULL
)
1343 pos
++; /* skip content of the token */
1346 *pos
++ = '\0'; /* remove first sep after the token */
1348 pos
= NULL
; /* end of string */
1354 int valid_email(const char *email
)
1357 for (i
=0;i
<strlen(email
);i
++)
1359 if(!isalnum(email
[i
]) &&
1367 if(strchr(email
, '@') == NULL
)
1373 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
1374 * as the parameters. If NULL, they become "*".
1376 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 10)
1377 static char *make_nick_user_host(char *namebuf
, const char *nick
,
1378 const char *name
, const char *host
)
1380 snprintf(namebuf
, NUH_BUFSIZE
, "%s!%s@%s", nick
, name
, host
);
1387 * by Carlo Wood (Run), 05 Oct 1998.
1391 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1392 * When the user name or host name are too long (USERLEN and HOSTLEN
1393 * respectively) then they are cut off at the start with a '*'.
1395 * The following transformations are made:
1397 * 1) xxx -> nick!*@*
1398 * 2) xxx.xxx -> *!*@host
1399 * 3) xxx!yyy -> nick!user@*
1400 * 4) xxx@yyy -> *!user@host
1401 * 5) xxx!yyy@zzz -> nick!user@host
1403 char *pretty_mask(char *mask
)
1405 static char star
[2] = { '*', 0 };
1406 static char retmask
[NUH_BUFSIZE
] = "";
1407 char *last_dot
= NULL
;
1410 /* Case 1: default */
1415 /* Do a _single_ pass through the characters of the mask: */
1416 for (ptr
= mask
; *ptr
; ++ptr
)
1420 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1424 else if (*ptr
== '@')
1426 /* Case 4: Found last '@' (without finding a '!' yet) */
1431 else if (*ptr
== '.')
1433 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1443 /* Case 4 or 5: Found last '@' */
1449 if (user
== star
&& last_dot
)
1459 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1460 if (nick_end
- nick
> NICKLEN
)
1466 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1467 if (user_end
- user
> USERLEN
)
1469 user
= user_end
- USERLEN
;
1474 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1476 host
= ptr
- HOSTLEN
;
1479 return make_nick_user_host(retmask
, nick
, user
, host
);
1482 int str_is_number(const char *str
)
1486 for(ptr
= (char *)str
;*ptr
;ptr
++) {
1487 if((*ptr
>= '0' && *ptr
<= '9') || *ptr
== '-')