]>
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 2 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 irccasecmp(const char *stra
, const char *strb
) {
362 while (*stra
&& (tolower(*stra
) == tolower(*strb
)))
364 return tolower(*stra
) - tolower(*strb
);
368 ircncasecmp(const char *stra
, const char *strb
, unsigned int len
) {
370 while (*stra
&& (tolower(*stra
) == tolower(*strb
)) && len
)
371 stra
++, strb
++, len
--;
372 return tolower(*stra
) - tolower(*strb
);
376 irccasestr(const char *haystack
, const char *needle
) {
377 unsigned int hay_len
= strlen(haystack
), needle_len
= strlen(needle
), pos
;
378 if (hay_len
< needle_len
)
380 for (pos
=0; pos
<hay_len
+1-needle_len
; ++pos
) {
381 if ((tolower(haystack
[pos
]) == tolower(*needle
))
382 && !ircncasecmp(haystack
+pos
, needle
, needle_len
))
389 split_line(char *line
, int irc_colon
, int argv_size
, char *argv
[])
393 while (*line
&& (argc
< argv_size
)) {
396 if (*line
== ':' && irc_colon
&& argc
> 0) {
397 /* the rest is a single parameter */
398 argv
[argc
++] = line
+ 1;
404 if (argc
>= argv_size
)
406 while (*line
!= ' ' && *line
)
412 for (n
=argc
; n
<argv_size
; n
++)
413 argv
[n
] = (char*)0xFEEDBEEF;
418 /* This is ircu's mmatch() function, from match.c. */
419 int mmatch(const char *old_mask
, const char *new_mask
)
421 register const char *m
= old_mask
;
422 register const char *n
= new_mask
;
443 for (m
--; (m
> old_mask
) && (*m
== '?'); m
--)
445 if ((*m
== '*') && (m
> old_mask
) && (m
[-1] != '\\'))
451 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
452 if ((*na
== '\\') && ((na
[1] == '*') || (na
[1] == '?')))
463 if ((*m
== '\\') && ((m
[1] == '*') || (m
[1] == '?')))
471 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
472 if ((*n
== '\\') && ((n
[1] == '*') || (n
[1] == '?')))
481 * This `if' has been changed compared to match() to do the following:
483 * old (m) new (n) boolean expression
484 * * any (*m == '*' && !mq) ||
485 * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
486 * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
487 * toLower(*m) == toLower(*n) &&
488 * !((mq && !nq) || (!mq && nq)))
490 * Here `any' also includes \* and \? !
492 * After reworking the boolean expressions, we get:
493 * (Optimized to use boolean shortcircuits, with most frequently occuring
494 * cases upfront (which took 2 hours!)).
496 if ((*m
== '*' && !mq
) ||
497 ((!mq
|| nq
) && tolower(*m
) == tolower(*n
)) ||
498 (*m
== '?' && !mq
&& (*n
!= '*' || nq
)))
511 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
512 if ((*na
== '\\') && ((na
[1] == '*') || (na
[1] == '?')))
521 match_ircglob(const char *text
, const char *glob
)
523 const char *m
= glob
, *n
= text
;
524 const char *m_tmp
= glob
, *n_tmp
= text
;
527 for (;;) switch (*m
) {
539 /* allow escaping to force capitalization */
544 for (star_p
= 0; ; m
++) {
547 else if (*m
== '?') {
555 else if (*m
== '\\') {
559 for (n_tmp
= n
; *n
&& *n
!= *m
; n
++) ;
562 for (n_tmp
= n
; *n
&& tolower(*n
) != tolower(*m
); n
++) ;
565 /* and fall through */
569 if (tolower(*m
) != tolower(*n
))
577 extern const char *hidden_host_suffix
;
579 /* Prevent *@* *@** *@*a* type masks, while allowing anything else. This is the best way iv found to detect
580 * a global matching mask; if it matches this string, it'll match almost anything :) */
581 int is_overmask(char *mask
)
583 return(match_ircglob("abcdefghijklmnopqrstuv!frcmbghilnrtoasde@apdic.yfa.dsfsdaffsdasfdasfd.abcdefghijklmnopqrstuvwxyz.asdfasfdfsdsfdasfda.ydfbe", mask
));
587 user_matches_glob(struct userNode
*user
, const char *orig_glob
, int flags
)
591 /* Make a writable copy of the glob */
592 glob
= alloca(strlen(orig_glob
)+1);
593 strcpy(glob
, orig_glob
);
594 /* Check the nick, if it's present */
595 if (flags
& MATCH_USENICK
) {
596 if (!(marker
= strchr(glob
, '!'))) {
597 log_module(MAIN_LOG
, LOG_ERROR
, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user
->nick
, orig_glob
, flags
);
601 if (!match_ircglob(user
->nick
, glob
)) return 0;
604 /* Check the ident */
605 if (!(marker
= strchr(glob
, '@'))) {
606 log_module(MAIN_LOG
, LOG_ERROR
, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user
->nick
, orig_glob
, flags
);
610 if (!match_ircglob(user
->ident
, glob
))
613 /* Check for a fakehost match. */
614 if (IsFakeHost(user
) && match_ircglob(user
->fakehost
, glob
))
617 /* Check for a sethost (S:lines) */
618 if (IsSetHost(user
) && match_ircglob(user
->sethost
, glob
))
621 /* Check for an account match. */
622 if (hidden_host_suffix
&& user
->handle_info
) {
623 char hidden_host
[HOSTLEN
+1];
624 snprintf(hidden_host
, sizeof(hidden_host
), "%s.%s", user
->handle_info
->handle
, hidden_host_suffix
);
625 if (match_ircglob(hidden_host
, glob
))
628 /* If only matching the visible hostnames, bail early. */
629 if ((flags
& MATCH_VISIBLE
) && IsHiddenHost(user
)
630 && (IsFakeHost(user
) || (hidden_host_suffix
&& user
->handle_info
)))
632 /* If it might be an IP glob, test that. */
633 if (!glob
[strspn(glob
, "0123456789./*?")]
634 && match_ircglob(irc_ntoa(&user
->ip
), glob
))
636 /* None of the above; could only be a hostname match. */
637 return match_ircglob(user
->hostname
, glob
);
641 is_ircmask(const char *text
)
643 while (*text
&& (isalnum((char)*text
) || strchr("-_[]|\\`^{}?*", *text
)))
647 while (*text
&& *text
!= '@' && !isspace((char)*text
))
651 while (*text
&& !isspace((char)*text
))
657 is_gline(const char *text
)
661 text
+= strcspn(text
, "@!% \t\r\n");
666 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
672 is_shun(const char *text
)
676 text
+= strcspn(text
, "@!% \t\r\n");
681 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
687 split_ircmask(char *text
, char **nick
, char **ident
, char **host
)
692 while (isalnum((char)*text
) || strchr("=[]\\`^{}?*", *text
))
694 if (*text
!= '!' || ((text
- start
) > NICKLEN
))
701 while (*text
&& *text
!= '@' && !isspace((char)*text
))
703 if (*text
!= '@' || ((text
- start
) > USERLEN
))
710 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
714 return !*text
&& ((text
- start
) <= HOSTLEN
) && nick
&& ident
&& host
;
718 sanitize_ircmask(char *input
)
720 unsigned int length
, flag
;
721 char *mask
, *start
, *output
;
723 /* Sanitize everything in place; input *must* be a valid
728 /* The nick is truncated at the end. */
731 while(*input
++ != '!')
740 /* This flag is used to indicate following parts should
749 /* The ident and host must be truncated at the beginning and
750 replaced with a '*' to be compatible with ircu. */
753 while(*input
++ != '@')
757 if(length
> USERLEN
|| flag
)
761 start
= input
- USERLEN
;
783 if(length
> HOSTLEN
|| flag
)
787 start
= input
- HOSTLEN
;
801 TypeLength(char type
)
804 case 'y': return 365*24*60*60;
805 case 'M': return 30*24*60*60;
806 case 'w': return 7*24*60*60;
807 case 'd': return 24*60*60;
808 case 'h': return 60*60;
815 /* This function is not entirely accurate as it does not take into account leap units
816 * or varying months. TODO: use proper dateadd functions to calculate real seconds
817 * from now for the units (eg 1M should be give us seconds till todays date next month)
820 ParseInterval(const char *interval
)
822 unsigned long seconds
= 0;
826 /* process the string, resetting the count if we find a unit character */
827 while ((c
= *interval
++)) {
828 if (isdigit((int)c
)) {
829 partial
= partial
*10 + c
- '0';
831 seconds
+= TypeLength(c
) * partial
;
835 /* assume the last chunk is seconds (the normal case) */
836 return seconds
+ partial
;
840 GetSizeMultiplier(char type
)
843 case 'G': case 'g': return 1024*1024*1024;
844 case 'M': case 'm': return 1024*1024;
845 case 'K': case 'k': return 1024;
846 case 'B': case 'b': return 1;
852 ParseVolume(const char *volume
)
854 unsigned long accum
= 0, partial
= 0;
856 while ((c
= *volume
++)) {
857 if (isdigit((int)c
)) {
858 partial
= partial
*10 + c
- '0';
860 accum
+= GetSizeMultiplier(c
) * partial
;
864 return accum
+ partial
;
868 unsplit_string(char *set
[], unsigned int max
, char *dest
)
870 static char unsplit_buffer
[MAXLEN
*2];
871 unsigned int ii
, jj
, pos
;
874 dest
= unsplit_buffer
;
875 for (ii
=pos
=0; ii
<max
; ii
++) {
876 for (jj
=0; set
[ii
][jj
]; jj
++)
877 dest
[pos
++] = set
[ii
][jj
];
885 intervalString(char *output
, time_t interval
, struct handle_info
*hi
)
887 static const struct {
888 const char *msg_single
;
889 const char *msg_plural
;
892 { "MSG_YEAR", "MSG_YEARS", 365 * 24 * 60 * 60 },
893 { "MSG_WEEK", "MSG_WEEKS", 7 * 24 * 60 * 60 },
894 { "MSG_DAY", "MSG_DAYS", 24 * 60 * 60 },
895 { "MSG_HOUR", "MSG_HOURS", 60 * 60 },
896 { "MSG_MINUTE", "MSG_MINUTES", 60 },
897 { "MSG_SECOND", "MSG_SECONDS", 1 }
899 struct language
*lang
;
901 unsigned int type
, words
, pos
, count
;
903 lang
= hi
? hi
->language
: lang_C
;
906 msg
= language_find_message(lang
, "MSG_0_SECONDS");
907 return strcpy(output
, msg
);
910 for (type
= 0, words
= pos
= 0;
911 interval
&& (words
< 2) && (type
< ArrayLength(unit
));
913 if (interval
< unit
[type
].length
)
915 count
= interval
/ unit
[type
].length
;
916 interval
= interval
% unit
[type
].length
;
919 msg
= language_find_message(lang
, "MSG_AND");
920 pos
+= sprintf(output
+ pos
, "%s ", msg
);
923 msg
= language_find_message(lang
, unit
[type
].msg_single
);
925 msg
= language_find_message(lang
, unit
[type
].msg_plural
);
926 pos
+= sprintf(output
+ pos
, "%d%s", count
, msg
);
934 getipbyname(const char *name
, unsigned long *ip
)
936 struct hostent
*he
= gethostbyname(name
);
939 if (he
->h_addrtype
!= AF_INET
)
941 memcpy(ip
, he
->h_addr_list
[0], sizeof(*ip
));
945 DEFINE_LIST(string_buffer
, char)
948 string_buffer_append_substring(struct string_buffer
*buf
, const char *tail
, unsigned int len
)
950 while (buf
->used
+ len
>= buf
->size
) {
955 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
957 memcpy(buf
->list
+ buf
->used
, tail
, len
+1);
962 string_buffer_append_string(struct string_buffer
*buf
, const char *tail
)
964 string_buffer_append_substring(buf
, tail
, strlen(tail
));
968 string_buffer_append_vprintf(struct string_buffer
*buf
, const char *fmt
, va_list args
)
974 VA_COPY(working
, args
);
976 if (!buf
->list
|| ((buf
->used
+ buf
->size
) < len
)) {
977 buf
->size
= buf
->used
+ len
;
978 buf
->list
= realloc(buf
->list
, buf
->size
);
980 ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
);
982 /* pre-C99 behavior; double buffer size until it is big enough */
984 VA_COPY(working
, args
);
985 while ((ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
)) <= 0) {
987 buf
->list
= realloc(buf
->list
, buf
->size
);
989 VA_COPY(working
, args
);
992 } else if (buf
->used
+ ret
< buf
->size
) {
993 /* no need to increase allocation size */
996 /* now we know exactly how much space we need */
997 if (buf
->size
<= buf
->used
+ ret
) {
998 buf
->size
= buf
->used
+ ret
+ 1;
999 buf
->list
= realloc(buf
->list
, buf
->size
);
1002 VA_COPY(working
, args
);
1003 buf
->used
+= vsnprintf(buf
->list
+ buf
->used
, buf
->size
, fmt
, working
);
1009 void string_buffer_append_printf(struct string_buffer
*buf
, const char *fmt
, ...)
1012 va_start(args
, fmt
);
1013 string_buffer_append_vprintf(buf
, fmt
, args
);
1017 string_buffer_replace(struct string_buffer
*buf
, unsigned int from
, unsigned int len
, const char *repl
)
1019 unsigned int repl_len
= strlen(repl
);
1020 if (from
> buf
->used
)
1022 if (len
+ from
> buf
->used
)
1023 len
= buf
->used
- from
;
1024 buf
->used
= buf
->used
+ repl_len
- len
;
1025 if (buf
->size
<= buf
->used
) {
1026 while (buf
->used
>= buf
->size
)
1028 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
1030 memmove(buf
->list
+from
+repl_len
, buf
->list
+from
+len
, strlen(buf
->list
+from
+len
));
1031 strcpy(buf
->list
+from
, repl
);
1034 struct string_list str_tab
;
1037 strtab(unsigned int ii
) {
1040 if (ii
> str_tab
.size
) {
1041 unsigned int old_size
= str_tab
.size
;
1042 while (ii
>= str_tab
.size
)
1044 str_tab
.list
= realloc(str_tab
.list
, str_tab
.size
*sizeof(str_tab
.list
[0]));
1045 memset(str_tab
.list
+old_size
, 0, (str_tab
.size
-old_size
)*sizeof(str_tab
.list
[0]));
1047 if (!str_tab
.list
[ii
]) {
1048 str_tab
.list
[ii
] = malloc(12);
1049 sprintf(str_tab
.list
[ii
], "%u", ii
);
1051 return str_tab
.list
[ii
];
1057 unsigned int upr
, lwr
;
1058 for (lwr
=0; lwr
<256; ++lwr
)
1060 for (upr
='A', lwr
='a'; lwr
<= 'z'; ++upr
, ++lwr
)
1062 #ifdef WITH_PROTOCOL_P10
1063 for (upr
='[', lwr
='{'; lwr
<= '~'; ++upr
, ++lwr
)
1065 for (upr
=0xc0, lwr
=0xe0; lwr
<= 0xf6; ++upr
, ++lwr
)
1067 for (upr
=0xd8, lwr
=0xf8; lwr
<= 0xfe; ++upr
, ++lwr
)
1070 str_tab
.size
= 1001;
1071 str_tab
.list
= calloc(str_tab
.size
, sizeof(str_tab
.list
[0]));
1078 for (ii
=0; ii
<str_tab
.size
; ++ii
)
1079 free(str_tab
.list
[ii
]);
1083 /* mysep() is my answer to the strtok/strsep
1084 * issue. strsep is nice but doesn't skip
1085 * multiple dilimiters, which can really
1086 * offset tokens and cause huge corruption
1087 * so this function will use strsep but
1088 * act like strtok in that sense.
1090 char *mysep(char **sepstr
, char *delim
)
1092 static char *retstr
;
1094 if(!*sepstr
|| !**sepstr
)
1099 retstr
= strsep(sepstr
, delim
);
1100 }while (retstr
&& !(*retstr
));
1105 char *time2str(time_t thetime
)
1109 buf
= ctime(&thetime
);
1110 tmp
= (char *)strchr(buf
, '\n');
1115 char* x3_strtok(char **save
, char *str
, char *fs
)
1117 char *pos
= *save
; /* keep last position across calls */
1121 pos
= str
; /* new string scan */
1123 while (pos
&& *pos
&& strchr(fs
, *pos
) != NULL
)
1124 pos
++; /* skip leading separators */
1127 return (pos
= *save
= NULL
); /* string contains only sep's */
1129 tmp
= pos
; /* now, keep position of the token */
1131 while (*pos
&& strchr(fs
, *pos
) == NULL
)
1132 pos
++; /* skip content of the token */
1135 *pos
++ = '\0'; /* remove first sep after the token */
1137 pos
= NULL
; /* end of string */
1143 int valid_email(const char *email
)
1146 for (i
=0;i
<strlen(email
);i
++)
1148 if(!isalnum(email
[i
]) &&
1156 if(strchr(email
, '@') == NULL
)
1162 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
1163 * as the parameters. If NULL, they become "*".
1165 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 10)
1166 static char *make_nick_user_host(char *namebuf
, const char *nick
,
1167 const char *name
, const char *host
)
1169 snprintf(namebuf
, NUH_BUFSIZE
, "%s!%s@%s", nick
, name
, host
);
1176 * by Carlo Wood (Run), 05 Oct 1998.
1180 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1181 * When the user name or host name are too long (USERLEN and HOSTLEN
1182 * respectively) then they are cut off at the start with a '*'.
1184 * The following transformations are made:
1186 * 1) xxx -> nick!*@*
1187 * 2) xxx.xxx -> *!*@host
1188 * 3) xxx!yyy -> nick!user@*
1189 * 4) xxx@yyy -> *!user@host
1190 * 5) xxx!yyy@zzz -> nick!user@host
1192 char *pretty_mask(char *mask
)
1194 static char star
[2] = { '*', 0 };
1195 static char retmask
[NUH_BUFSIZE
] = "";
1196 char *last_dot
= NULL
;
1199 /* Case 1: default */
1204 /* Do a _single_ pass through the characters of the mask: */
1205 for (ptr
= mask
; *ptr
; ++ptr
)
1209 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1213 else if (*ptr
== '@')
1215 /* Case 4: Found last '@' (without finding a '!' yet) */
1220 else if (*ptr
== '.')
1222 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1232 /* Case 4 or 5: Found last '@' */
1238 if (user
== star
&& last_dot
)
1248 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1249 if (nick_end
- nick
> NICKLEN
)
1255 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1256 if (user_end
- user
> USERLEN
)
1258 user
= user_end
- USERLEN
;
1263 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1265 host
= ptr
- HOSTLEN
;
1268 return make_nick_user_host(retmask
, nick
, user
, host
);