]>
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
))
629 /* Match crypt hostname */
630 if (match_ircglob(user
->crypthost
, glob
))
634 if (match_ircglob(user
->cryptip
, glob
))
637 /* If only matching the visible hostnames, bail early. */
638 if ((flags
& MATCH_VISIBLE
) && IsHiddenHost(user
)
639 && (IsFakeHost(user
) || (hidden_host_suffix
&& user
->handle_info
)))
641 /* If it might be an IP glob, test that. */
642 if (!glob
[strspn(glob
, "0123456789./*?")]
643 && match_ircglob(irc_ntoa(&user
->ip
), glob
))
645 /* None of the above; could only be a hostname match. */
646 return match_ircglob(user
->hostname
, glob
);
650 is_ircmask(const char *text
)
652 while (*text
&& (isalnum((char)*text
) || strchr("-_[]|\\`^{}?*", *text
)))
656 while (*text
&& *text
!= '@' && !isspace((char)*text
))
660 while (*text
&& !isspace((char)*text
))
666 is_gline(const char *text
)
670 text
+= strcspn(text
, "@!% \t\r\n");
675 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
681 is_shun(const char *text
)
685 text
+= strcspn(text
, "@!% \t\r\n");
690 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
696 split_ircmask(char *text
, char **nick
, char **ident
, char **host
)
701 while (isalnum((char)*text
) || strchr("=[]\\`^{}?*", *text
))
703 if (*text
!= '!' || ((text
- start
) > NICKLEN
))
710 while (*text
&& *text
!= '@' && !isspace((char)*text
))
712 if (*text
!= '@' || ((text
- start
) > USERLEN
))
719 while (*text
&& (isalnum((char)*text
) || strchr(".-?*:", *text
)))
723 return !*text
&& ((text
- start
) <= HOSTLEN
) && nick
&& ident
&& host
;
727 sanitize_ircmask(char *input
)
729 unsigned int length
, flag
;
730 char *mask
, *start
, *output
;
732 /* Sanitize everything in place; input *must* be a valid
737 /* The nick is truncated at the end. */
740 while(*input
++ != '!')
749 /* This flag is used to indicate following parts should
758 /* The ident and host must be truncated at the beginning and
759 replaced with a '*' to be compatible with ircu. */
762 while(*input
++ != '@')
766 if(length
> USERLEN
|| flag
)
770 start
= input
- USERLEN
;
792 if(length
> HOSTLEN
|| flag
)
796 start
= input
- HOSTLEN
;
810 TypeLength(char type
)
813 case 'y': return 365*24*60*60;
814 case 'M': return 30*24*60*60;
815 case 'w': return 7*24*60*60;
816 case 'd': return 24*60*60;
817 case 'h': return 60*60;
824 /* This function is not entirely accurate as it does not take into account leap units
825 * or varying months. TODO: use proper dateadd functions to calculate real seconds
826 * from now for the units (eg 1M should be give us seconds till todays date next month)
829 ParseInterval(const char *interval
)
831 unsigned long seconds
= 0;
835 /* process the string, resetting the count if we find a unit character */
836 while ((c
= *interval
++)) {
837 if (isdigit((int)c
)) {
838 partial
= partial
*10 + c
- '0';
840 seconds
+= TypeLength(c
) * partial
;
844 /* assume the last chunk is seconds (the normal case) */
845 return seconds
+ partial
;
849 GetSizeMultiplier(char type
)
852 case 'G': case 'g': return 1024*1024*1024;
853 case 'M': case 'm': return 1024*1024;
854 case 'K': case 'k': return 1024;
855 case 'B': case 'b': return 1;
861 ParseVolume(const char *volume
)
863 unsigned long accum
= 0, partial
= 0;
865 while ((c
= *volume
++)) {
866 if (isdigit((int)c
)) {
867 partial
= partial
*10 + c
- '0';
869 accum
+= GetSizeMultiplier(c
) * partial
;
873 return accum
+ partial
;
877 unsplit_string(char *set
[], unsigned int max
, char *dest
)
879 static char unsplit_buffer
[MAXLEN
*2];
880 unsigned int ii
, jj
, pos
;
883 dest
= unsplit_buffer
;
884 for (ii
=pos
=0; ii
<max
; ii
++) {
885 for (jj
=0; set
[ii
][jj
]; jj
++)
886 dest
[pos
++] = set
[ii
][jj
];
894 intervalString(char *output
, time_t interval
, struct handle_info
*hi
)
896 static const struct {
897 const char *msg_single
;
898 const char *msg_plural
;
901 { "MSG_YEAR", "MSG_YEARS", 365 * 24 * 60 * 60 },
902 { "MSG_WEEK", "MSG_WEEKS", 7 * 24 * 60 * 60 },
903 { "MSG_DAY", "MSG_DAYS", 24 * 60 * 60 },
904 { "MSG_HOUR", "MSG_HOURS", 60 * 60 },
905 { "MSG_MINUTE", "MSG_MINUTES", 60 },
906 { "MSG_SECOND", "MSG_SECONDS", 1 }
908 struct language
*lang
;
910 unsigned int type
, words
, pos
, count
;
912 lang
= hi
? hi
->language
: lang_C
;
915 msg
= language_find_message(lang
, "MSG_0_SECONDS");
916 return strcpy(output
, msg
);
919 for (type
= 0, words
= pos
= 0;
920 interval
&& (words
< 2) && (type
< ArrayLength(unit
));
922 if (interval
< unit
[type
].length
)
924 count
= interval
/ unit
[type
].length
;
925 interval
= interval
% unit
[type
].length
;
928 msg
= language_find_message(lang
, "MSG_AND");
929 pos
+= sprintf(output
+ pos
, "%s ", msg
);
932 msg
= language_find_message(lang
, unit
[type
].msg_single
);
934 msg
= language_find_message(lang
, unit
[type
].msg_plural
);
935 pos
+= sprintf(output
+ pos
, "%d%s", count
, msg
);
943 getipbyname(const char *name
, unsigned long *ip
)
945 struct hostent
*he
= gethostbyname(name
);
948 if (he
->h_addrtype
!= AF_INET
)
950 memcpy(ip
, he
->h_addr_list
[0], sizeof(*ip
));
954 DEFINE_LIST(string_buffer
, char)
957 string_buffer_append_substring(struct string_buffer
*buf
, const char *tail
, unsigned int len
)
959 while (buf
->used
+ len
>= buf
->size
) {
964 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
966 memcpy(buf
->list
+ buf
->used
, tail
, len
+1);
971 string_buffer_append_string(struct string_buffer
*buf
, const char *tail
)
973 string_buffer_append_substring(buf
, tail
, strlen(tail
));
977 string_buffer_append_vprintf(struct string_buffer
*buf
, const char *fmt
, va_list args
)
983 VA_COPY(working
, args
);
985 if (!buf
->list
|| ((buf
->used
+ buf
->size
) < len
)) {
986 buf
->size
= buf
->used
+ len
;
987 buf
->list
= realloc(buf
->list
, buf
->size
);
989 ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
);
991 /* pre-C99 behavior; double buffer size until it is big enough */
993 VA_COPY(working
, args
);
994 while ((ret
= vsnprintf(buf
->list
+ buf
->used
, buf
->size
- buf
->used
, fmt
, working
)) <= 0) {
996 buf
->list
= realloc(buf
->list
, buf
->size
);
998 VA_COPY(working
, args
);
1001 } else if (buf
->used
+ ret
< buf
->size
) {
1002 /* no need to increase allocation size */
1005 /* now we know exactly how much space we need */
1006 if (buf
->size
<= buf
->used
+ ret
) {
1007 buf
->size
= buf
->used
+ ret
+ 1;
1008 buf
->list
= realloc(buf
->list
, buf
->size
);
1011 VA_COPY(working
, args
);
1012 buf
->used
+= vsnprintf(buf
->list
+ buf
->used
, buf
->size
, fmt
, working
);
1018 void string_buffer_append_printf(struct string_buffer
*buf
, const char *fmt
, ...)
1021 va_start(args
, fmt
);
1022 string_buffer_append_vprintf(buf
, fmt
, args
);
1026 string_buffer_replace(struct string_buffer
*buf
, unsigned int from
, unsigned int len
, const char *repl
)
1028 unsigned int repl_len
= strlen(repl
);
1029 if (from
> buf
->used
)
1031 if (len
+ from
> buf
->used
)
1032 len
= buf
->used
- from
;
1033 buf
->used
= buf
->used
+ repl_len
- len
;
1034 if (buf
->size
<= buf
->used
) {
1035 while (buf
->used
>= buf
->size
)
1037 buf
->list
= realloc(buf
->list
, buf
->size
*sizeof(buf
->list
[0]));
1039 memmove(buf
->list
+from
+repl_len
, buf
->list
+from
+len
, strlen(buf
->list
+from
+len
));
1040 strcpy(buf
->list
+from
, repl
);
1043 struct string_list str_tab
;
1046 strtab(unsigned int ii
) {
1049 if (ii
> str_tab
.size
) {
1050 unsigned int old_size
= str_tab
.size
;
1051 while (ii
>= str_tab
.size
)
1053 str_tab
.list
= realloc(str_tab
.list
, str_tab
.size
*sizeof(str_tab
.list
[0]));
1054 memset(str_tab
.list
+old_size
, 0, (str_tab
.size
-old_size
)*sizeof(str_tab
.list
[0]));
1056 if (!str_tab
.list
[ii
]) {
1057 str_tab
.list
[ii
] = malloc(12);
1058 sprintf(str_tab
.list
[ii
], "%u", ii
);
1060 return str_tab
.list
[ii
];
1066 unsigned int upr
, lwr
;
1067 for (lwr
=0; lwr
<256; ++lwr
)
1069 for (upr
='A', lwr
='a'; lwr
<= 'z'; ++upr
, ++lwr
)
1071 #ifdef WITH_PROTOCOL_P10
1072 for (upr
='[', lwr
='{'; lwr
<= '~'; ++upr
, ++lwr
)
1074 for (upr
=0xc0, lwr
=0xe0; lwr
<= 0xf6; ++upr
, ++lwr
)
1076 for (upr
=0xd8, lwr
=0xf8; lwr
<= 0xfe; ++upr
, ++lwr
)
1079 str_tab
.size
= 1001;
1080 str_tab
.list
= calloc(str_tab
.size
, sizeof(str_tab
.list
[0]));
1087 for (ii
=0; ii
<str_tab
.size
; ++ii
)
1088 free(str_tab
.list
[ii
]);
1092 /* mysep() is my answer to the strtok/strsep
1093 * issue. strsep is nice but doesn't skip
1094 * multiple dilimiters, which can really
1095 * offset tokens and cause huge corruption
1096 * so this function will use strsep but
1097 * act like strtok in that sense.
1099 char *mysep(char **sepstr
, char *delim
)
1101 static char *retstr
;
1103 if(!*sepstr
|| !**sepstr
)
1108 retstr
= strsep(sepstr
, delim
);
1109 }while (retstr
&& !(*retstr
));
1114 char *time2str(time_t thetime
)
1118 buf
= ctime(&thetime
);
1119 tmp
= (char *)strchr(buf
, '\n');
1124 char* x3_strtok(char **save
, char *str
, char *fs
)
1126 char *pos
= *save
; /* keep last position across calls */
1130 pos
= str
; /* new string scan */
1132 while (pos
&& *pos
&& strchr(fs
, *pos
) != NULL
)
1133 pos
++; /* skip leading separators */
1136 return (pos
= *save
= NULL
); /* string contains only sep's */
1138 tmp
= pos
; /* now, keep position of the token */
1140 while (*pos
&& strchr(fs
, *pos
) == NULL
)
1141 pos
++; /* skip content of the token */
1144 *pos
++ = '\0'; /* remove first sep after the token */
1146 pos
= NULL
; /* end of string */
1152 int valid_email(const char *email
)
1155 for (i
=0;i
<strlen(email
);i
++)
1157 if(!isalnum(email
[i
]) &&
1165 if(strchr(email
, '@') == NULL
)
1171 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
1172 * as the parameters. If NULL, they become "*".
1174 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 10)
1175 static char *make_nick_user_host(char *namebuf
, const char *nick
,
1176 const char *name
, const char *host
)
1178 snprintf(namebuf
, NUH_BUFSIZE
, "%s!%s@%s", nick
, name
, host
);
1185 * by Carlo Wood (Run), 05 Oct 1998.
1189 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1190 * When the user name or host name are too long (USERLEN and HOSTLEN
1191 * respectively) then they are cut off at the start with a '*'.
1193 * The following transformations are made:
1195 * 1) xxx -> nick!*@*
1196 * 2) xxx.xxx -> *!*@host
1197 * 3) xxx!yyy -> nick!user@*
1198 * 4) xxx@yyy -> *!user@host
1199 * 5) xxx!yyy@zzz -> nick!user@host
1201 char *pretty_mask(char *mask
)
1203 static char star
[2] = { '*', 0 };
1204 static char retmask
[NUH_BUFSIZE
] = "";
1205 char *last_dot
= NULL
;
1208 /* Case 1: default */
1213 /* Do a _single_ pass through the characters of the mask: */
1214 for (ptr
= mask
; *ptr
; ++ptr
)
1218 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1222 else if (*ptr
== '@')
1224 /* Case 4: Found last '@' (without finding a '!' yet) */
1229 else if (*ptr
== '.')
1231 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1241 /* Case 4 or 5: Found last '@' */
1247 if (user
== star
&& last_dot
)
1257 char *nick_end
= (user
!= star
) ? user
- 1 : ptr
;
1258 if (nick_end
- nick
> NICKLEN
)
1264 char *user_end
= (host
!= star
) ? host
- 1 : ptr
;
1265 if (user_end
- user
> USERLEN
)
1267 user
= user_end
- USERLEN
;
1272 if (host
!= star
&& ptr
- host
> HOSTLEN
)
1274 host
= ptr
- HOSTLEN
;
1277 return make_nick_user_host(retmask
, nick
, user
, host
);