270 lines
4.8 KiB
C
270 lines
4.8 KiB
C
#include <cdb.h>
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "def.h"
|
|
#include "node.h"
|
|
#include "vector.h"
|
|
|
|
struct cdb cdb;
|
|
unsigned pos;
|
|
|
|
void cdb_startup()
|
|
{
|
|
int fd = open("calc.cdb", O_RDONLY);
|
|
if (fd == -1) {
|
|
perror("open");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
cdb_init(&cdb, fd);
|
|
}
|
|
|
|
char *cdballoc(char *key)
|
|
{
|
|
char *val = 0;
|
|
if (cdb_find(&cdb, key, strlen(key)) > 0) {
|
|
unsigned vpos = cdb_datapos(&cdb);
|
|
unsigned vlen = cdb_datalen(&cdb);
|
|
val = malloc(vlen + 1);
|
|
if (!val)
|
|
return 0;
|
|
cdb_read(&cdb, val, vlen, vpos);
|
|
val[vlen] = 0;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
int cdb_exists(char *name)
|
|
{
|
|
if (!name)
|
|
return 0;
|
|
|
|
char key[strlen(name) + strlen("/") + strlen("bot") + 1];
|
|
char *p = key, *n = name;
|
|
while (*n)
|
|
*p++ = tolower(*n++);
|
|
*p = 0;
|
|
strcat(key, "/");
|
|
strcat(key, "bot");
|
|
|
|
int cdbret = cdb_find(&cdb, key, strlen(key));
|
|
assert(cdbret != -1);
|
|
|
|
return cdbret;
|
|
}
|
|
|
|
static char *name;
|
|
static char *sub;
|
|
static char *val;
|
|
|
|
static void split_key(char *key)
|
|
{
|
|
name = sub = 0;
|
|
|
|
if (!key || !*key)
|
|
return;
|
|
|
|
char tmp[strlen(key) + 1];
|
|
|
|
char *slash = strrchr(key, '/');
|
|
if (!slash || !*slash)
|
|
return;
|
|
|
|
char *p = tmp;
|
|
while (key != slash)
|
|
*p++ = *key++;
|
|
*p = 0;
|
|
|
|
name = strdup(tmp);
|
|
sub = strdup(slash + 1);
|
|
}
|
|
|
|
|
|
static bool build_next()
|
|
{
|
|
if (cdb_seqnext(&pos, &cdb) <= 0)
|
|
return false;
|
|
|
|
unsigned keylen = cdb_keylen(&cdb);
|
|
char *key = malloc(keylen + 1);
|
|
cdb_read(&cdb, key, keylen, cdb_keypos(&cdb));
|
|
key[keylen] = 0;
|
|
unsigned datalen = cdb_datalen(&cdb);
|
|
val = malloc(datalen + 1);
|
|
cdb_read(&cdb, val, datalen, cdb_datapos(&cdb));
|
|
val[datalen] = 0;
|
|
|
|
split_key(key);
|
|
free(key);
|
|
return true;
|
|
}
|
|
|
|
void cdb_loadall_init()
|
|
{
|
|
cdb_seqinit(&pos, &cdb);
|
|
if (name) {
|
|
free(name);
|
|
name = 0;
|
|
}
|
|
if (sub) {
|
|
free(sub);
|
|
sub = 0;
|
|
}
|
|
if (val) {
|
|
free(val);
|
|
val = 0;
|
|
}
|
|
|
|
build_next();
|
|
}
|
|
|
|
|
|
|
|
struct vector *cdb_loadall_next()
|
|
{
|
|
if (!name)
|
|
cdb_loadall_init();
|
|
|
|
struct vector *v = vector_create();
|
|
struct node *node = node_create(name, BF_TYPE_STRING);
|
|
char cur_name[strlen(name) + 1];
|
|
strcpy(cur_name, name);
|
|
vector_put(v, "eintrag", node);
|
|
|
|
while (!strcmp(cur_name, name)) {
|
|
if (!sub)
|
|
continue;
|
|
node = node_create(val, BF_TYPE_STRING);
|
|
vector_put(v, sub, node);
|
|
if (!build_next())
|
|
return 0;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
static void build_node(char *name, struct vector *v, char *sub)
|
|
{
|
|
if (!sub) {
|
|
struct node *node = node_create(name, BF_TYPE_STRING);
|
|
vector_put(v, "eintrag", node);
|
|
return;
|
|
}
|
|
|
|
char key[strlen(name) + strlen("/") + strlen(sub) + 1];
|
|
char *p = key, *n = name;
|
|
while (*n)
|
|
*p++ = tolower(*n++);
|
|
*p = 0;
|
|
strcat(key, "/");
|
|
strcat(key, sub);
|
|
|
|
char *val = cdballoc(key);
|
|
struct node *node = node_create(val, BF_TYPE_STRING);
|
|
vector_put(v, sub, node);
|
|
}
|
|
|
|
struct vector *cdb_load(char *name)
|
|
{
|
|
int cdbret = cdb_exists(name);
|
|
if (!cdbret)
|
|
return 0;
|
|
|
|
struct vector *vc = vector_create();
|
|
build_node(name, vc, "auth");
|
|
build_node(name, vc, "name");
|
|
build_node(name, vc, 0); // „eintrag“
|
|
build_node(name, vc, "inhalt");
|
|
build_node(name, vc, "zeit");
|
|
build_node(name, vc, "bot");
|
|
build_node(name, vc, "protected");
|
|
build_node(name, vc, "channel");
|
|
build_node(name, vc, "network");
|
|
build_node(name, vc, "count");
|
|
build_node(name, vc, "type");
|
|
build_node(name, vc, "tag");
|
|
build_node(name, vc, "lastcall");
|
|
|
|
return vc;
|
|
}
|
|
|
|
void uint32_unpack(const char s[4], uint32_t * u)
|
|
{
|
|
uint32_t result;
|
|
|
|
result = (unsigned char) s[3];
|
|
result <<= 8;
|
|
result += (unsigned char) s[2];
|
|
result <<= 8;
|
|
result += (unsigned char) s[1];
|
|
result <<= 8;
|
|
result += (unsigned char) s[0];
|
|
|
|
*u = result;
|
|
}
|
|
|
|
struct vector *cdb_load_random(bool cmd)
|
|
{
|
|
int guard;
|
|
for (guard = 0; guard < 23; guard++) {
|
|
char *fname = cmd ? "calc.cdb.index.cmd" :
|
|
"calc.cdb.index.nocmd";
|
|
int fd = open(fname, O_RDONLY);
|
|
if (fd == -1) {
|
|
perror("open");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
off_t size = lseek(fd, 0, SEEK_END);
|
|
assert(size > 0 && size % 4 == 0);
|
|
|
|
int rndmax = min(RAND_MAX, size / 4);
|
|
int rnd = rand() % rndmax;
|
|
off_t off = rnd;
|
|
off *= 4;
|
|
lseek(fd, off, SEEK_SET);
|
|
|
|
char buf_pos[4];
|
|
read(fd, buf_pos, 4);
|
|
uint32_t pos;
|
|
uint32_unpack(buf_pos, &pos);
|
|
close(fd);
|
|
|
|
fd = open("calc.cdb", O_RDONLY);
|
|
if (fd == -1) {
|
|
perror("open");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
off_t loc = lseek(fd, pos, SEEK_SET);
|
|
assert(loc == pos);
|
|
char buf_keylen[4];
|
|
read(fd, buf_keylen, 4);
|
|
char buf_datalen[4];
|
|
read(fd, buf_datalen, 4);
|
|
uint32_t keylen;
|
|
uint32_unpack(buf_keylen, &keylen);
|
|
uint32_t datalen;
|
|
uint32_unpack(buf_datalen, &datalen);
|
|
if (!datalen) {
|
|
continue;
|
|
}
|
|
char key[keylen + 1];
|
|
read(fd, key, keylen);
|
|
key[keylen] = 0;
|
|
close(fd);
|
|
split_key(key);
|
|
struct vector *vc = cdb_load(name);
|
|
if (vc)
|
|
return vc;
|
|
}
|
|
|
|
return 0;
|
|
}
|