]>
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
);
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
);
746 /* Check the nick, if it's present */
747 if (flags
& MATCH_USENICK
) {
748 if (!(marker
= strchr(glob
, '!'))) {
749 log_module(MAIN_LOG
, LOG_ERROR
, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user
->nick
, orig_glob
, flags
);
753 if (!match_ircglob(user
->nick
, glob
)) return 0;
756 /* Check the ident */
757 if (!(marker
= strchr(glob
, '@'))) {
758 log_module(MAIN_LOG
, LOG_ERROR
, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user
->nick
, orig_glob
, flags
);
762 if (!match_ircglob(user
->ident
, glob
))
765 /* Check for a fakehost match. */
766 if (IsFakeHost(user
) && match_ircglob(user
->fakehost
, glob
))
769 /* Check for a sethost (S:lines) */
770 if (IsSetHost(user
) && match_ircglob(user
->sethost
, glob
))
773 /* Check for an account match. */
774 if (hidden_host_suffix
&& user
->handle_info
) {
775 char hidden_host
[HOSTLEN
+1];
776 snprintf(hidden_host
, sizeof(hidden_host
), "%s.%s", user
->handle_info
->handle
, hidden_host_suffix
);
777 if (match_ircglob(hidden_host
, glob
))
781 /* Match crypt hostname */
782 if (match_ircglob(user
->crypthost
, glob
))
786 if (match_ircglob(user
->cryptip
, glob
))
789 /* If only matching the visible hostnames, bail early. */
790 if ((flags
& MATCH_VISIBLE
) && IsHiddenHost(user
)
791 && (IsFakeHost(user
) || (hidden_host_suffix
&& user
->handle_info
)))
793 /* If it might be an IP glob, test that. */
794 if (!glob
[strspn(glob
, "0123456789./*?")]
795 && match_ircglob(irc_ntoa(&user
->ip
), glob
))
797 /* None of the above; could only be a hostname match. */
798 return match_ircglob(user
->hostname
, glob
);
802 is_ircmask(const char *text
)
807 tmptext
= alloca(strlen(text
)+1);
808 tmptext
= strdup(text
);
810 tmptext
++; /* get rid of the ~ */
813 tmptext
++; /* get rid of the ! if it exists */
815 tmptext
++; /* get rid of the ext ban type */
817 if (*tmptext
== ':') {
818 tmptext
++; /* get rid of the : */
819 while (*tmptext
&& !isspace((char)*tmptext
))
820 tmptext
++; /* get rid of the rest */
825 while (*text
&& (isalnum((char)*text
) || strchr("-_[]|\\`^{}?*", *text
)))
829 while (*text
&& *text
!= '@' && !isspace((char)*text
))
833 while (*text
&& !isspace((char)*text
))
839 is_gline(const char *text
)
843 text
+= strcspn(text
, "@!% \t\r\n");
848 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
854 is_shun(const char *text
)
858 text
+= strcspn(text
, "@!% \t\r\n");
863 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
869 split_ircmask(char *text
, char **nick
, char **ident
, char **host
)
874 while (isalnum((char)*text
) || strchr("=[]\\`^{}?*", *text
))
876 if (*text
!= '!' || ((text
- start
) > NICKLEN
))
883 while (*text
&& *text
!= '@' && !isspace((char)*text
))
885 if (*text
!= '@' || ((text
- start
) > USERLEN
))
892 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
896 return !*text
&& ((text
- start
) <= HOSTLEN
) && nick
&& ident
&& host
;
900 sanitize_ircmask(char *input
)
902 unsigned int length
, flag
;
903 char *mask
, *start
, *output
;
905 /* Sanitize everything in place; input *must* be a valid
910 /* The nick is truncated at the end. */
913 while(*input
++ != '!')
922 /* This flag is used to indicate following parts should
931 /* The ident and host must be truncated at the beginning and
932 replaced with a '*' to be compatible with ircu. */
935 while(*input
++ != '@')
939 if(length
> USERLEN
|| flag
)
943 start
= input
- USERLEN
;
965 if(length
> HOSTLEN
|| flag
)
969 start
= input
- HOSTLEN
;
983 TypeLength(char type
)
986 case 'y': return 365*24*60*60;
987 case 'M': return 30*24*60*60;
988 case 'w': return 7*24*60*60;
989 case 'd': return 24*60*60;
990 case 'h': return 60*60;
997 /* This function is not entirely accurate as it does not take into account leap units
998 * or varying months. TODO: use proper dateadd functions to calculate real seconds
999 * from now for the units (eg 1M should be give us seconds till todays date next month)
1002 ParseInterval(const char *interval
)
1004 unsigned long seconds
= 0;
1008 /* process the string, resetting the count if we find a unit character */
1009 while ((c
= *interval
++)) {
1010 if (isdigit((int)c
)) {
1011 partial
= partial
*10 + c
- '0';
1012 } else if (strchr("yMwdhms", c
)) {
1013 seconds
+= TypeLength(c
) * partial
;
1019 /* assume the last chunk is seconds (the normal case) */
1020 return seconds
+ partial
;
1024 GetSizeMultiplier(char type
)
1027 case 'G': case 'g': return 1024*1024*1024;
1028 case 'M': case 'm': return 1024*1024;
1029 case 'K': case 'k': return 1024;
1030 case 'B': case 'b': return 1;
1036 ParseVolume(const char *volume
)
1038 unsigned long accum
= 0, partial
= 0;
1040 while ((c
= *volume
++)) {
1041 if (isdigit((int)c
)) {
1042 partial
= partial
*10 + c
- '0';
1044 accum
+= GetSizeMultiplier(c
) * partial
;
1048 return accum
+ partial
;
1052 unsplit_string(char *set
[], unsigned int max
, char *dest
)
1054 static char unsplit_buffer
[MAXLEN
*2];
1055 unsigned int ii
, jj
, pos
;
1058 dest
= unsplit_buffer
;
1059 for (ii
=pos
=0; ii
<max
; ii
++) {
1060 for (jj
=0; set
[ii
][jj
]; jj
++)
1061 dest
[pos
++] = set
[ii
][jj
];
1069 intervalString(char *output
, time_t interval
, struct handle_info
*hi
)
1071 static const struct {
1072 const char *msg_single
;
1073 const char *msg_plural
;
1076 { "MSG_YEAR", "MSG_YEARS", 365 * 24 * 60 * 60 },
1077 { "MSG_WEEK", "MSG_WEEKS", 7 * 24 * 60 * 60 },
1078 { "MSG_DAY", "MSG_DAYS", 24 * 60 * 60 },
1079 { "MSG_HOUR", "MSG_HOURS", 60 * 60 },
1080 { "MSG_MINUTE", "MSG_MINUTES", 60 },
1081 { "MSG_SECOND", "MSG_SECONDS", 1 }
1083 struct language
*lang
;
1085 unsigned int type
, words
, pos
, count
;
1087 lang
= hi
? hi
->language
: lang_C
;
1090 msg
= language_find_message(lang
, "MSG_0_SECONDS");
1091 return strcpy(output
, msg
);
1094 for (type
= 0, words
= pos
= 0;
1095 interval
&& (words
< 2) && (type
< ArrayLength(unit
));
1097 if (interval
< unit
[type
].length
)
1099 count
= interval
/ unit
[type
].length
;
1100 interval
= interval
% unit
[type
].length
;
1103 msg
= language_find_message(lang
, "MSG_AND");
1104 pos
+= sprintf(output
+ pos
, "%s ", msg
);
1107 msg
= language_find_message(lang
, unit
[type
].msg_single
);
1109 msg
= language_find_message(lang
, unit
[type
].msg_plural
);
1110 pos
+= sprintf(output
+ pos
, "%d%s", count
, msg
);
1118 getipbyname(const char *name
, unsigned long *ip
)
1120 struct hostent
*he
= gethostbyname(name
);
1123 if (he
->h_addrtype
!= AF_INET
)
1125 memcpy(ip
, he
->h_addr_list
[0], sizeof(*ip
));
1129 DEFINE_LIST(string_buffer
, char)
1132 string_buffer_append_substring(struct string_buffer
*buf
, const char *tail
, unsigned int len
)
1134 while (buf
->used
+ len
>= buf
->size
) {
1139 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
1141 memcpy(buf
->list
+ buf
->used
, tail
, len
+1);
1146 string_buffer_append_string(struct string_buffer
*buf
, const char *tail
)
1148 string_buffer_append_substring(buf
, tail
, strlen(tail
));
1152 string_buffer_append_vprintf(struct string_buffer
*buf
, const char *fmt
, va_list args
)
1158 VA_COPY(working
, args
);
1160 if (!buf
->list
|| ((buf
->used
+ buf
->size
) < len
)) {
1161 buf
->size
= buf
->used
+ len
;
1162 buf
->list
= realloc(buf
->list
, buf
->size
);
1164 ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
);
1166 /* pre-C99 behavior; double buffer size until it is big enough */
1168 VA_COPY(working
, args
);
1169 while ((ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
)) <= 0) {
1171 buf
->list
= realloc(buf
->list
, buf
->size
);
1173 VA_COPY(working
, args
);
1176 } else if (buf
->used
+ ret
< buf
->size
) {
1177 /* no need to increase allocation size */
1180 /* now we know exactly how much space we need */
1181 if (buf
->size
<= buf
->used
+ ret
) {
1182 buf
->size
= buf
->used
+ ret
+ 1;
1183 buf
->list
= realloc(buf
->list
, buf
->size
);
1186 VA_COPY(working
, args
);
1187 buf
->used
+= vsnprintf(buf
->list
+ buf
->used
, buf
->size
, fmt
, working
);
1193 void string_buffer_append_printf(struct string_buffer
*buf
, const char *fmt
, ...)
1196 va_start(args
, fmt
);
1197 string_buffer_append_vprintf(buf
, fmt
, args
);
1201 string_buffer_replace(struct string_buffer
*buf
, unsigned int from
, unsigned int len
, const char *repl
)
1203 unsigned int repl_len
= strlen(repl
);
1204 if (from
> buf
->used
)
1206 if (len
+ from
> buf
->used
)
1207 len
= buf
->used
- from
;
1208 buf
->used
= buf
->used
+ repl_len
- len
;
1209 if (buf
->size
<= buf
->used
) {
1210 while (buf
->used
>= buf
->size
)
1212 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
1214 memmove(buf
->list
+from
+repl_len
, buf
->list
+from
+len
, strlen(buf
->list
+from
+len
));
1215 strcpy(buf
->list
+from
, repl
);
1218 struct string_list str_tab
;
1221 strtab(unsigned int ii
) {
1224 if (ii
> str_tab
.size
) {
1225 unsigned int old_size
= str_tab
.size
;
1226 while (ii
>= str_tab
.size
)
1228 str_tab
.list
= realloc(str_tab
.list
, str_tab
.size
*sizeof(str_tab
.list
[0]));
1229 memset(str_tab
.list
+old_size
, 0, (str_tab
.size
-old_size
)*sizeof(str_tab
.list
[0]));
1231 if (!str_tab
.list
[ii
]) {
1232 str_tab
.list
[ii
] = malloc(12);
1233 sprintf(str_tab
.list
[ii
], "%u", ii
);
1235 return str_tab
.list
[ii
];
1241 unsigned int upr
, lwr
;
1242 for (lwr
=0; lwr
<256; ++lwr
)
1244 for (upr
='A', lwr
='a'; lwr
<= 'z'; ++upr
, ++lwr
)
1246 #ifdef WITH_PROTOCOL_P10
1247 for (upr
='[', lwr
='{'; lwr
<= '~'; ++upr
, ++lwr
)
1249 for (upr
=0xc0, lwr
=0xe0; lwr
<= 0xf6; ++upr
, ++lwr
)
1251 for (upr
=0xd8, lwr
=0xf8; lwr
<= 0xfe; ++upr
, ++lwr
)
1254 str_tab
.size
= 1001;
1255 str_tab
.list
= calloc(str_tab
.size
, sizeof(str_tab
.list
[0]));
1262 for (ii
=0; ii
<str_tab
.size
; ++ii
)
1263 free(str_tab
.list
[ii
]);
1267 /* mysep() is my answer to the strtok/strsep
1268 * issue. strsep is nice but doesn't skip
1269 * multiple dilimiters, which can really
1270 * offset tokens and cause huge corruption
1271 * so this function will use strsep but
1272 * act like strtok in that sense.
1274 char *mysep(char **sepstr
, char *delim
)
1276 static char *retstr
;
1278 if(!*sepstr
|| !**sepstr
)
1283 retstr
= strsep(sepstr
, delim
);
1284 }while (retstr
&& !(*retstr
));
1289 /* Mallocing snprintf *
1291 * If it overruns size, it will simply be safely truncated.
1294 x3_msnprintf(const int size
, const char *format
, ...)
1297 char* buff
= calloc(sizeof(char *), size
+1);
1299 va_start(ap
, format
);
1300 vsnprintf(buff
, size
, format
, ap
);
1302 buff
= realloc(buff
, strlen(buff
) + 1);
1306 char *time2str(time_t thetime
)
1310 buf
= ctime(&thetime
);
1311 tmp
= (char *)strchr(buf
, '\n');
1316 char* x3_strtok(char **save
, char *str
, char *fs
)
1318 char *pos
= *save
; /* keep last position across calls */
1322 pos
= str
; /* new string scan */
1324 while (pos
&& *pos
&& strchr(fs
, *pos
) != NULL
)
1325 pos
++; /* skip leading separators */
1328 return (pos
= *save
= NULL
); /* string contains only sep's */
1330 tmp
= pos
; /* now, keep position of the token */
1332 while (*pos
&& strchr(fs
, *pos
) == NULL
)
1333 pos
++; /* skip content of the token */
1336 *pos
++ = '\0'; /* remove first sep after the token */
1338 pos
= NULL
; /* end of string */
1344 int valid_email(const char *email
)
1347 for (i
=0;i
<strlen(email
);i
++)
1349 if(!isalnum(email
[i
]) &&
1357 if(strchr(email
, '@') == NULL
)
1363 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
1364 * as the parameters. If NULL, they become "*".
1366 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 10)
1367 static char *make_nick_user_host(char *namebuf
, const char *nick
,
1368 const char *name
, const char *host
)
1370 snprintf(namebuf
, NUH_BUFSIZE
, "%s!%s@%s", nick
, name
, host
);
1377 * by Carlo Wood (Run), 05 Oct 1998.
1381 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1382 * When the user name or host name are too long (USERLEN and HOSTLEN
1383 * respectively) then they are cut off at the start with a '*'.
1385 * The following transformations are made:
1387 * 1) xxx -> nick!*@*
1388 * 2) xxx.xxx -> *!*@host
1389 * 3) xxx!yyy -> nick!user@*
1390 * 4) xxx@yyy -> *!user@host
1391 * 5) xxx!yyy@zzz -> nick!user@host
1393 char *pretty_mask(char *mask
)
1395 static char star
[2] = { '*', 0 };
1396 static char retmask
[NUH_BUFSIZE
] = "";
1397 char *last_dot
= NULL
;
1400 /* Case 1: default */
1405 /* Do a _single_ pass through the characters of the mask: */
1406 for (ptr
= mask
; *ptr
; ++ptr
)
1410 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1414 else if (*ptr
== '@')
1416 /* Case 4: Found last '@' (without finding a '!' yet) */
1421 else if (*ptr
== '.')
1423 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1433 /* Case 4 or 5: Found last '@' */
1439 if (user
== star
&& last_dot
)
1449 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1450 if (nick_end
- nick
> NICKLEN
)
1456 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1457 if (user_end
- user
> USERLEN
)
1459 user
= user_end
- USERLEN
;
1464 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1466 host
= ptr
- HOSTLEN
;
1469 return make_nick_user_host(retmask
, nick
, user
, host
);
1472 int str_is_number(const char *str
)
1476 for(ptr
= (char *)str
;*ptr
;ptr
++) {
1477 if((*ptr
>= '0' && *ptr
<= '9') || *ptr
== '-')