#ifdef RCS
static char rcsid[]="$Id: function.c,v 1.1.1.1 2000/11/13 02:42:42 holsta Exp $";
#endif
/******************************************************************************
* Internetting Cooperating Programmers
* ----------------------------------------------------------------------------
*
* ____ PROJECT
* | _ \ __ _ _ __ ___ ___ _ __
* | | | |/ _` | '_ \ / __/ _ \ '__|
* | |_| | (_| | | | | (_| __/ |
* |____/ \__,_|_| |_|\___\___|_| the IRC bot
*
* All files in this archive are subject to the GNU General Public License.
*
* $Source: /cvsroot/dancer/dancer/src/function.c,v $
* $Revision: 1.1.1.1 $
* $Date: 2000/11/13 02:42:42 $
* $Author: holsta $
* $State: Exp $
* $Locker: $
*
* ---------------------------------------------------------------------------
*****************************************************************************/
#include "dancer.h"
#include "trio.h"
#include "strio.h"
#include "regex.h"
#include "function.h"
#include "transfer.h"
#include "user.h"
#define RNDMAX ULONG_MAX
/* RNDSIZE must be an integral number of 2 (and at least 8) */
#define RNDSIZE 64
#define RNDMASK RNDSIZE-1
/* --- Global ----------------------------------------------------- */
extern time_t now;
extern char nickname[];
extern char nickstring[];
/* tolowertab, used by HashU(), Match(), MatchEsc() and IRCEqual functions */
#define IRC_tolower(c) (tolowertab[(u_char)(c)])
const unsigned char tolowertab[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
'*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
':', ';', '<', '=', '>', '?',
'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
'_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
static ulong rnd1;
static ulong rnd2;
static ulong rndValues[RNDSIZE];
/* --- IsChannel -------------------------------------------------- */
inline bool IsChannel(char *name)
{
return (name && (('#' == name[0]) || ('&' == name[0]) ||
('+' == name[0]) || ('!' == name[0])));
}
/* --- IsServer --------------------------------------------------- */
inline bool IsServer(char *name)
{
return (name && StrIndex(name, '.'));
}
/* --- TimeAgo ---------------------------------------------------- */
char *TimeAgo(time_t when)
{
static char timebuf[MIDBUFFER];
int a, b, diff;
snapshot;
diff = now - when;
diff = abs(diff);
if (diff < SECINMIN) {
StrFormatMax(timebuf, sizeof(timebuf), "%d %s",
diff, ((1 == diff) ? GetText(msg_second) : GetText(msg_seconds)));
}
else if (diff < SECINHOUR) {
a = diff/SECINMIN;
b = diff%SECINMIN;
StrFormatMax(timebuf, sizeof(timebuf), "%d %s %s %d %s",
a, ((1 == a) ? GetText(msg_minute) : GetText(msg_minutes)),
GetText(msg_and),
b, ((1 == b) ? GetText(msg_second): GetText(msg_seconds)));
}
else if (diff < SECINDAY) {
a = diff/SECINHOUR;
b = (diff%SECINHOUR)/SECINMIN;
StrFormatMax(timebuf, sizeof(timebuf), "%d %s %s %d %s",
a, ((1 == a) ? GetText(msg_hour) : GetText(msg_hours)),
GetText(msg_and),
b, ((1 == b) ? GetText(msg_minute) : GetText(msg_minutes)));
}
else if (diff < SECINMONTH) {
a = diff/SECINDAY;
b = (diff%SECINDAY)/SECINHOUR;
StrFormatMax(timebuf, sizeof(timebuf), "%d %s %s %d %s",
a, ((1 == a) ? GetText(msg_day) : GetText(msg_days)),
GetText(msg_and),
b, ((1 == b) ? GetText(msg_hour) : GetText(msg_hours)));
}
else {
a = diff/SECINMONTH;
b = (diff%SECINMONTH)/SECINDAY;
StrFormatMax(timebuf, sizeof(timebuf), "%d %s %s %d %s",
a, ((1 == a) ? GetText(msg_month) : GetText(msg_months)),
GetText(msg_and),
b, ((1 == b) ? GetText(msg_day) : GetText(msg_days)));
}
return timebuf;
}
/* --- SecToString ------------------------------------------------ */
char *SecsToString(int secs)
{
static char buffer[25];
int hours;
int minutes;
snapshot;
hours = secs/3600;
secs -= hours*3600;
minutes = secs/60;
secs -= minutes*60;
StrFormatMax(buffer, sizeof(buffer), "%02d.%02d:%02d", hours, minutes, secs);
return buffer;
}
/* --- ToSeconds -------------------------------------------------- */
int ToSeconds(char *string)
{
char *next;
int secs = 0;
do {
secs *= 60;
secs += StrToLong(string, &next, 10);
string = next + 1;
} while (':' == *next);
return secs;
}
/* --- GetOption -------------------------------------------------- */
itemopt option = {NULL, (char)0};
bool GetOption(char *line)
{
if (line && ('-' == *line)) {
line++;
option.copt = *line++;
while (*line && !iswhite(*line))
line++;
while (iswhite(*line))
line++;
option.newpos = line;
return TRUE;
}
option.copt = (char)0;
option.newpos = line;
return FALSE;
}
/* --- Boolean ---------------------------------------------------- */
inline char *OnOff(bool toggle)
{
return (toggle ? "on" : "off");
}
inline bool IsOn(char *string)
{
return (string && StrEqual(string, "ON"));
}
/* --- Hash ------------------------------------------------------- */
inline unsigned int HashU(char *key)
{
unsigned int k;
for (k = 0; *key; key++)
k = 31*k + IRC_tolower(*key);
return (k % HASHSIZE);
}
inline unsigned int Hash(char *key)
{
unsigned int k;
for (k = 0; *key; key++)
k = 31*k + *key;
return (k % HASHSIZE);
}
/* --- HashSignatureU --------------------------------------------- */
/* Used for fast text searching. To check if a certain word could
* occur in a static block of text, a hashed 2-signature of the
* text must be pre-calculated. When searching for a word, calculate
* it's signature and compare with the signature of the text.
*
* if ( (textsignature & signature) == signature )
* // word _could_ be in text, check further
* else
* // word is definitely not in text
*
* To find possible match between two string where one contains
* wildcard the check must be
*
* if ( (patternsignature & signature) == patternsignature )
*/
ulong HashSignatureU(char *name)
{
char a, b;
bool bvalid = FALSE; /* Does b contain a valid char */
ulong sig = 0L;
while (a = IRC_tolower(*name++)) {
/* Don't hash wildcards and bigrams */
if (('*' != a) && ('?' != a)) {
if (bvalid && (a != b))
sig |= 1 << (((int)a + (int)b) % ULONG_BIT);
b = a;
bvalid = TRUE;
}
else
bvalid = FALSE;
}
return sig;
}
/* --- OurNextWord ------------------------------------------------ */
char *OurNextWord(char *line, char **rest)
{
char *pointer;
if (line) {
while (iswhite(*line))
line++;
for (pointer = line; *pointer && !iswhite(*pointer); pointer++);
if (*pointer)
*pointer++ = (char)0;
if (rest)
*rest = *pointer ? pointer : NULL;
}
else if (rest) {
*rest = NULL;
}
return ((line && *line) ? line : NULL);
}
/* --- OurNextQuoteWord ------------------------------------------- */
char *OurNextQuoteWord(char *line, char **rest)
{
char *pointer;
if (line) {
while (iswhite(*line))
line++;
if ('\"' == *line) {
for (pointer = ++line; *pointer && ('\"' != *pointer); pointer++);
}
else {
for (pointer = line; *pointer && !iswhite(*pointer); pointer++);
}
if (*pointer)
*pointer++ = (char)0;
if (rest)
*rest = *pointer ? pointer : NULL;
}
else if (rest) {
*rest = NULL;
}
return ((line && *line) ? line : NULL);
}
#if 0
/* --- PatternInit() ---------------------------------------------- */
/* Setup the translation table fo the pattern mach (case insensitive) */
/* How many characters in the character set. */
#define CHAR_SET_SIZE 256
static char p_translate[CHAR_SET_SIZE];
void PatternInit(void)
{
unsigned i;
/* Map uppercase characters to corresponding lowercase ones. */
for (i=0; i < CHAR_SET_SIZE; i++)
p_translate[i] = isupper(i) ? tolower(i) : i;
}
#endif
/* --- PatternExist ----------------------------------------------- */
bool PatternExist(char *line, char *pattern)
{
char const *error;
int retcode;
struct re_pattern_buffer patbuf;
memset(&patbuf, 0, sizeof(struct re_pattern_buffer));
#if 0
patbuf.translate = p_translate; /* case insensitive table */
#endif
error = re_compile_pattern(pattern, StrLength(pattern), &patbuf);
if (error)
Debug("Pattern error: %s", error);
retcode = re_search(&patbuf, line, StrLength(line), 0, StrLength(line), NULL);
regfree(&patbuf);
return ((retcode >= 0) ? TRUE : FALSE); /* return hit */
}
#if 0
inline bool SearchPattern(re_compile_pattern *p, char *line)
{
return (re_search(p, line, StrLength(line), 0, StrLength(line), NULL) >= 0);
}
void *FreePattern(struct re_pattern_buffer *p)
{
regfree(p);
free(p);
}
struct re_pattern_buffer *PrecalcPattern(char *pattern)
{
char const *errtxt;
struct re_pattern_buffer *p;
if ( p=(struct re_pattern_buffer *)calloc(1, sizeof(struct re_pattern_buffer)) ) {
if ( errtxt=re_compile_pattern(pattern, StrLength(pattern), p) ) {
Debug("Pattern error: %s", errtxt);
FreePattern(p);
p = NULL;
}
}
return (p);
}
#endif
/* --- Match ------------------------------------------------------ */
/* Using a slightly modified version of the iterative match() function
* from ircd sources (irc2.10.1/common/match.c), which is twice or
* sometimes even multiple times faster than the recursive Match().
* Most of the blame goes to toupper, but the iterative version would
* still be faster than the recursive one, regardless of toupper.
* Inverted the return values, removed the possibility to escape the
* wildcards in the pattern with a '\' and some other minor changes.
*/
#define MAX_ITERATIONS 512
bool Match(char *string, char *pattern)
{
register u_char *s = (u_char *)string;
register u_char *p = (u_char *)pattern;
char *str = string;
char *pat = pattern;
bool wild = FALSE;
int calls = 0;
if (string && pattern) {
while (1) {
#ifdef MAX_ITERATIONS
if (calls++ > MAX_ITERATIONS)
break;
#endif
if ('*' == *p) {
while ('*' == *p)
p++;
wild = TRUE;
pat = (char *)p;
str = (char *)s;
}
if ((char)0 == *p) {
if ((char)0 == *s)
return TRUE;
if (p > (u_char *)pattern)
p--;
while ((p > (u_char *)pattern) && ('?' == *p))
p--;
if ('*' == *p)
return TRUE;
if (!wild)
return FALSE;
p = (u_char *)pat;
s = (u_char *)++str;
}
else if ((char)0 == *s)
return FALSE;
if ((IRC_tolower(*p) != IRC_tolower(*s)) && ('?' != *p)) {
if (!wild)
return FALSE;
p = (u_char *)pat;
s = (u_char *)++str;
}
else {
if (*p)
p++;
if (*s)
s++;
}
}
}
return FALSE;
}
/* --- MatchEsc --------------------------------------------------- */
/* Allows you to escape the wildcards in pattern using '\' */
bool MatchEsc(char *string, char *pattern)
{
register u_char *s = (u_char *)string;
register u_char *p = (u_char *)pattern;
char *str = string;
char *pat = pattern;
bool wild = FALSE, q;
int calls = 0;
if (string && pattern) {
while (1) {
#ifdef MAX_ITERATIONS
if (calls++ > MAX_ITERATIONS)
break;
#endif
if ('*' == *p) {
while ('*' == *p)
p++;
wild = TRUE;
pat = (char *)p;
str = (char *)s;
}
if ((char)0 == *p) {
if ((char)0 == *s)
return TRUE;
if (p > (u_char *)pattern)
p--;
while ((p > (u_char *)pattern) && ('?' == *p))
p--;
if (('*' == *p) && ((p <= (u_char *)pattern) || ('\\' != p[-1])))
return TRUE;
if (!wild)
return FALSE;
p = (u_char *)pat;
s = (u_char *)++str;
}
else if ((char)0 == *s)
return FALSE;
if (('\\' == *p) && (('*' == p[1]) || ('?' == p[1]))) {
p++;
q = TRUE;
}
else
q = FALSE;
if ((IRC_tolower(*p) != IRC_tolower(*s)) && (('?' != *p) || q)) {
if (!wild)
return FALSE;
p = (u_char *)pat;
s = (u_char *)++str;
}
else {
if (*p)
p++;
if (*s)
s++;
}
}
}
return FALSE;
}
/* --- MatchMatch ------------------------------------------------- */
bool MatchMatch(char *pattern1, char *pattern2)
{
return (Match(pattern1, pattern2) || Match(pattern2, pattern1));
}
/* --- IRCEqual --------------------------------------------------- */
bool IRCEqual(const char *first, const char *second)
{
register const u_char *tt = tolowertab,
*s1 = (const u_char *)first,
*s2 = (const u_char *)second;
if (first && second) {
while (tt[*s1] == tt[*s2++]) {
if ((char)0 == *s1++)
return TRUE;
}
}
return FALSE;
}
/* --- Userdomain ------------------------------------------------- */
/*
* Transforms host name to a masked domain name.
*
* This function allocates a string, which you must free()
* yourself. {a=Userhost(b); ...use it...; free(a);}
*
* Machine names may start with a digit (if they've got a really
* stupid sysadm) but top level domains always start with an
* alphabetic char. Use top level domain to distinguish between
* IP names and IP numeric adresses.
*
* Both '@' and at least one '.' must be present in 'host'.
*
* Furthermore, some people use '@' in their (faked) user name,
* so search for the last '@'.
*
* For example:
* "user@machine.host.domain" becomes "user@*.host.domain"
* and "user@127.0.0.1" becomes "user@127.0.0.*"
*
* From 3rd of January, 1997 (v4.1.3) also:
*
* Check if the host is an ISP listed as hostisp: in .config and then make the
* pattern like:
*
* "user@machine.host.domain" becomes "*@machine.host.domain"
*
* From 25th of February, 1999:
*
* "user@machine.top-domain" style hosts are returned unchanged.
*/
char *Userdomain(char *host)
{
char *userdomain, *m, *t;
bool smallone;
snapshot;
userdomain = StrDuplicate(host);
if (userdomain) {
m = StrIndexLast(userdomain, '@'); /* Userhost requires a '@' */
if (m) {
t = StrIndexLast(m, '.');
if (t) {
/* Now check for a @host.topdomain style name */
smallone = (StrIndex(m, '.') == t) ? TRUE : FALSE;
t++; /* Points to top level domain name */
if (isdigit(*t)) {
*t++ = '*';
*t = (char)0;
}
else if (HostISP(userdomain)) {
if (m > userdomain) {
t = userdomain;
*t++ = '*';
while (*m)
*t++ = *m++;
*t = (char)0;
}
}
else if (!smallone) {
m++; /* Points to machine name */
t = StrIndex(m, '.');
if (t && (t > m)) {
*m++ = '*';
while (*t)
*m++ = *t++;
*m = (char)0;
}
}
}
}
}
return userdomain;
}
/* --- NewNick ---------------------------------------------------- */
void NewNick(void)
{
static int num = 0;
char *from = nickstring, *to = nickname;
char c;
bool bracket = FALSE;
int sep = 0;
snapshot;
while (c = *from++) {
switch (c) {
case '[':
bracket = TRUE;
sep = 0;
break;
case '|':
sep++;
break;
case ']':
bracket = FALSE;
break;
default:
if ((to - nickname) < NICKLEN) { /* Avoid overflow */
if (!bracket)
*to++ = c;
else if (sep == num)
*to++ = c;
}
break;
}
}
*to = (char)0;
if (sep <= num++)
num = 0;
}
/* --- Random ----------------------------------------------------- */
inline ulong Random(void)
{
rnd1 = (rnd1 - 3) & RNDMASK;
rnd2 = (rnd2 - 1) & RNDMASK;
return (rndValues[rnd2] += rndValues[rnd1]);
}
/* --- RandomInit ------------------------------------------------- */
void RandomInit(int s)
{
int i;
for (i=0; i < RNDSIZE; i++) {
rndValues[i] = (ulong)s;
/* --- randqd1() from Numerical Recipes --- */
s = 0x0019660dL * s + 0x3c6ef35fL;
}
rnd1 = 0;
rnd2 = RNDSIZE/2 - 3;
/* --- Remove initial errors of bad seeding (warn-up) --- */
for (i=0; i < RNDSIZE; i++) {
Random();
}
}
/* --- Rnd -------------------------------------------------------- */
float Rnd(void)
{
float a;
a = (float)Random();
a /= (float)RNDMAX;
return a;
}
/* --- Top -------------------------------------------------------- */
struct Top {
char name[40];
long value;
long flags;
};
#define NUM_TOP 7
struct Top realtop[NUM_TOP];
struct Top *newtop[NUM_TOP];
int compar(struct Top **t1, struct Top **t2)
{
return ((*t2)->value - (*t1)->value);
}
void AddToTop(char *name, long value)
{
snapshot;
if (value > newtop[NUM_TOP-1]->value) {
StrCopy(newtop[NUM_TOP-1]->name, name);
newtop[NUM_TOP-1]->value = value;
qsort((void *)newtop, NUM_TOP, sizeof(struct Top *), (int (*)(const void *, const void *))compar);
}
}
void InitTop(void)
{
int n;
snapshot;
memset(realtop, 0, sizeof(realtop)); /* reset all */
for (n=0; n < NUM_TOP; n++) {
newtop[n] = &realtop[n];
}
}
char *PresentTop(void)
{
static char buffer[256];
int len = 0;
int n;
snapshot;
for (n=0; (n < NUM_TOP) && newtop[n]->name[0]; n++) {
StrFormatMax(&buffer[len], sizeof(buffer) - len, "%s (%d) ",
newtop[n]->name, (int)newtop[n]->value);
len += StrLength(&buffer[len]);
}
if (0 == n) {
StrCopyMax(buffer, sizeof(buffer), GetText(msg_no_info_for_toplist));
}
return buffer;
}
/* --- fcopy ------------------------------------------------------ */
#if 0
/* fcopy() was only used by seenbackup, we don't need it now? */
/* MAX_COPY_SIZE determines how big of a buffer to use */
#define MAX_COPY_BLOCK 1024
void fcopy(char *src, char *dest)
{
char buffer[MAX_COPY_BLOCK];
size_t bytes;
FILE *fsrc, *fdest;
fsrc = fopen(src, "rb");
if (fsrc) {
fdest = fopen(dest, "wb");
if (fdest) {
/* copy in 1K chunks by default */
while (MAX_COPY_BLOCK == (bytes = fread(buffer, 1, MAX_COPY_BLOCK, fsrc)))
fwrite(buffer, MAX_COPY_BLOCK, 1, fdest);
fwrite(buffer, bytes, 1, fdest);
fclose(fdest);
}
fclose(fsrc);
}
}
#endif
/* --- FileExist -------------------------------------------------- */
bool FileExist(char *filename)
{
FILE *f;
if (filename && filename[0]) {
f = fopen(filename, "r");
if (f) {
fclose(f);
return TRUE;
}
}
return FALSE;
}
/* --- StrSplitMax ------------------------------------------------ */
/*
* A silly function used by SendMulti() to split the allocated string in
* shorter strings. Got any better solution?
*/
char *StrSplitMax(char *source, size_t size)
{
static char *next_string = NULL;
static char buffer_char;
char *target = NULL;
if (source) {
next_string = source;
buffer_char = (char)0;
}
if (next_string && (size > 1)) {
if (buffer_char) {
*next_string = buffer_char;
buffer_char = (char)0;
}
/* Skip any whitespace at the start */
while (iswhite(*next_string))
next_string++;
if (*next_string) {
target = next_string;
if ((StrLength(next_string) + 1) > size) {
char *pointer;
pointer = next_string + size - 1;
while ((pointer > next_string) && !iswhite(pointer[0]))
pointer--;
while ((pointer > next_string) && iswhite(pointer[-1]))
pointer--;
if (pointer == next_string) {
pointer = next_string + size - 1;
buffer_char = *pointer;
*pointer = (char)0;
}
else {
*pointer++ = (char)0;
}
next_string = pointer;
}
else {
next_string = NULL;
}
}
}
return target;
}
syntax highlighted by Code2HTML, v. 0.9.1