Initial commit of code released on 2002-07-15
This commit is contained in:
755
Sources/dbio.c
Normal file
755
Sources/dbio.c
Normal file
@@ -0,0 +1,755 @@
|
||||
/* @(#)$Id: dbio.c,v 1.12 1998/01/02 18:30:08 seks Exp $ */
|
||||
|
||||
/* Undernet Channel Service (X)
|
||||
* Copyright (C) 1995-2002 Robin Thellend
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* The author can be contact by email at <csfeedback@robin.pfft.net>
|
||||
*
|
||||
* Please note that this software is unsupported and mostly
|
||||
* obsolete. It was replaced by GNUworld/CMaster. See
|
||||
* http://gnuworld.sourceforge.net/ for more information.
|
||||
*/
|
||||
|
||||
#include "h.h"
|
||||
|
||||
|
||||
char *make_dbfname(char *channel)
|
||||
{
|
||||
static char fname[600];
|
||||
char tmp[600];
|
||||
register char *ptr;
|
||||
|
||||
strcpy(tmp, channel);
|
||||
for (ptr = tmp; *ptr; ptr++)
|
||||
{
|
||||
if (*ptr == '/')
|
||||
*ptr = ' ';
|
||||
else
|
||||
*ptr = tolower(*ptr);
|
||||
}
|
||||
|
||||
sprintf(fname, "db/channels/%04X/%s", ul_hash(channel), tmp);
|
||||
return fname;
|
||||
}
|
||||
|
||||
|
||||
/* db_query()
|
||||
* This is used to *retreive* information from the database.
|
||||
* The arguments are:
|
||||
* channel := channel name (null terminated string)
|
||||
* type := query type, either of:
|
||||
* DBGETNICK (Get entry by nick)
|
||||
* DBGET1STUH (Get first matching userhost)
|
||||
* DBGETALLUH (Get all matching userhosts)
|
||||
* DBCOUNTUH (Count the number of matching userhosts)
|
||||
* ...
|
||||
* info := Either a nick or a userhost depending on type
|
||||
* action := value passed to the callback function
|
||||
* hook1 := pointer passed to the callback function
|
||||
* hook2 := pointer passed to the callback function
|
||||
* callback := callback function
|
||||
*
|
||||
* Since the database is accessed asychronously, 'hook' should not point to
|
||||
* a structure that can be free()'d by a function other than callback,
|
||||
* e.g. a pointer to a luser structure.
|
||||
*/
|
||||
int db_fetch(char *channel, unsigned int type, char *info, char *passwd,
|
||||
int action, void *hook1, void *hook2, DBCALLBACK(callback))
|
||||
{
|
||||
dbquery *new;
|
||||
int fd;
|
||||
|
||||
if ((fd = open(make_dbfname(channel), O_RDONLY | O_NONBLOCK)) < 0)
|
||||
{
|
||||
callback(&fd, (off_t) 0, action, hook1, hook2, NULL, 0);
|
||||
return -1; /* caller can check errno to see want happened */
|
||||
}
|
||||
|
||||
new = (dbquery *) malloc(sizeof(dbquery));
|
||||
new->fd = fd;
|
||||
new->offset = (off_t) 0;
|
||||
new->time = now;
|
||||
new->type = type;
|
||||
new->action = action;
|
||||
new->count = 0;
|
||||
new->callback = callback;
|
||||
new->buf = NULL;
|
||||
new->hook1 = hook1;
|
||||
new->hook2 = hook2;
|
||||
strcpy(new->info, info);
|
||||
strncpy(new->channel, channel, 79);
|
||||
new->channel[79] = '\0';
|
||||
if (passwd)
|
||||
strcpy(new->passwd, passwd);
|
||||
else
|
||||
new->passwd[0] = '\0';
|
||||
new->next = DBQuery;
|
||||
DBQuery = new;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fix_db()
|
||||
* Remove db entries that are not in the right file.
|
||||
*/
|
||||
static void fix_db(char *channel, off_t offset)
|
||||
{
|
||||
register RegUser *reg;
|
||||
register int idx;
|
||||
|
||||
idx = ul_hash(channel);
|
||||
/* check if already taken care of */
|
||||
reg = UserList[idx];
|
||||
while (reg != NULL && (reg->offset != offset || strcasecmp(reg->channel, channel)))
|
||||
reg = reg->next;
|
||||
|
||||
if (reg) /* already there.. disregard */
|
||||
return;
|
||||
|
||||
reg = (RegUser *) MALLOC(sizeof(RegUser));
|
||||
memset(reg, 0, sizeof(RegUser));
|
||||
reg->realname = (char *)MALLOC(6);
|
||||
strcpy(reg->realname, "!DEL!");
|
||||
reg->passwd = (char *)MALLOC(1);
|
||||
*reg->passwd = '\0';
|
||||
reg->match = (char *)MALLOC(6);
|
||||
strcpy(reg->match, "!DEL!");
|
||||
reg->channel = (char *)MALLOC(strlen(channel) + 1);
|
||||
strcpy(reg->channel, channel);
|
||||
reg->modif = (char *)MALLOC(1);
|
||||
*reg->modif = '\0';
|
||||
reg->modified = 1;
|
||||
reg->offset = offset;
|
||||
reg->next = UserList[idx];
|
||||
UserList[idx] = reg;
|
||||
}
|
||||
|
||||
/* read_db()
|
||||
* This should be called from the select() loop. Data is read sequentially
|
||||
* and the query is processed according to 'type'.
|
||||
*/
|
||||
void read_db(dbquery * query)
|
||||
{
|
||||
struct dbuser buffer[11];
|
||||
int size, status, end = 0;
|
||||
|
||||
size = read(query->fd, buffer, 10 * sizeof(dbuser));
|
||||
if (size <= 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
{
|
||||
close(query->fd);
|
||||
query->fd = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
copy_to_buffer(&query->buf, (char *)buffer, size);
|
||||
while (!end && look_in_buffer(&query->buf, (char *)buffer, '\0', sizeof(dbuser))
|
||||
== sizeof(dbuser))
|
||||
{
|
||||
if (buffer[0].header[0] == 0xFF && buffer[0].header[1] == 0xFF &&
|
||||
buffer[0].footer[0] == 0xFF && buffer[0].footer[1] == 0xFF)
|
||||
{
|
||||
status = 1; /* block is used */
|
||||
}
|
||||
else if (buffer[0].header[0] == 0x00 && buffer[0].header[1] == 0x00 &&
|
||||
buffer[0].footer[0] == 0x00 && buffer[0].footer[1] == 0x00)
|
||||
{
|
||||
status = 0; /* block is free */
|
||||
}
|
||||
else
|
||||
{
|
||||
status = -1; /* block has been written to while reading it */
|
||||
}
|
||||
|
||||
if (status == 1 && strcasecmp(query->channel, buffer[0].channel))
|
||||
{
|
||||
fix_db(query->channel, query->offset);
|
||||
skip_char_in_buffer(&query->buf, sizeof(dbuser));
|
||||
query->offset += sizeof(dbuser);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("hdr: %X%X nick: %s match: %s passwd: %s channel: %s "
|
||||
"modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X"
|
||||
"sta: %d\n",
|
||||
buffer[0].header[0], buffer[0].header[1], buffer[0].nick, buffer[0].match, buffer[0].passwd,
|
||||
buffer[0].channel, buffer[0].modif, buffer[0].access, buffer[0].flags, buffer[0].suspend,
|
||||
buffer[0].lastseen, buffer[0].footer[0], buffer[0].footer[1], status);
|
||||
#endif
|
||||
|
||||
switch (query->type)
|
||||
{
|
||||
case DBGETNICK:
|
||||
if (status == 1 && !strcasecmp(buffer[0].nick, query->info))
|
||||
{
|
||||
close(query->fd);
|
||||
query->fd = -1;
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
end = 1;
|
||||
}
|
||||
break;
|
||||
case DBGET1STUH:
|
||||
if (status == 1 && match(query->info, buffer[0].match))
|
||||
{
|
||||
close(query->fd);
|
||||
query->fd = -1;
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
end = 1;
|
||||
}
|
||||
break;
|
||||
case DBGETALLUH:
|
||||
if (status == 1 && match(query->info, buffer[0].match))
|
||||
{
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
}
|
||||
break;
|
||||
case DBGETUHPASS:
|
||||
if (status == 1 && match(query->info, buffer[0].match) &&
|
||||
!strcmp(query->passwd, buffer[0].passwd))
|
||||
{
|
||||
close(query->fd);
|
||||
query->fd = -1;
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
end = 1;
|
||||
}
|
||||
break;
|
||||
case DBCOUNTUH:
|
||||
if (status == 1 && match(query->info, buffer[0].match))
|
||||
{
|
||||
query->count++;
|
||||
}
|
||||
break;
|
||||
case DBGET1STCMP:
|
||||
if (status == 1 && (!*query->info || compare(query->info, buffer[0].match)))
|
||||
{
|
||||
close(query->fd);
|
||||
query->fd = -1;
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
end = 1;
|
||||
}
|
||||
break;
|
||||
case DBGETALLCMP:
|
||||
if (status == 1 && (!*query->info || compare(query->info, buffer[0].match)))
|
||||
{
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
}
|
||||
break;
|
||||
case DBCNTCMP:
|
||||
if (status == 1 && (!*query->info || compare(query->info, buffer[0].match)))
|
||||
{
|
||||
query->count++;
|
||||
}
|
||||
break;
|
||||
case DBGET1STFREE:
|
||||
if (status == 0)
|
||||
{
|
||||
close(query->fd);
|
||||
query->fd = -1;
|
||||
query->count++;
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, buffer, query->count);
|
||||
end = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
skip_char_in_buffer(&query->buf, sizeof(dbuser));
|
||||
query->offset += sizeof(dbuser);
|
||||
if (query->fd < 0)
|
||||
end = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void end_db_read(dbquery * query)
|
||||
{
|
||||
zap_buffer(&query->buf);
|
||||
query->callback(&query->fd, query->offset, query->action, query->hook1,
|
||||
query->hook2, NULL, query->count);
|
||||
}
|
||||
|
||||
|
||||
void make_dbuser(RegUser * reg, dbuser * dbu)
|
||||
{
|
||||
memset(dbu, 0, sizeof(dbuser));
|
||||
if (reg->access != 0)
|
||||
{
|
||||
strncpy(dbu->nick, reg->realname, 79);
|
||||
dbu->nick[79] = '\0';;
|
||||
strncpy(dbu->match, reg->match, 79);
|
||||
dbu->match[79] = '\0';
|
||||
strncpy(dbu->channel, reg->channel, 49);
|
||||
dbu->channel[49] = '\0';
|
||||
strncpy(dbu->passwd, reg->passwd, 19);
|
||||
dbu->passwd[19] = '\0';
|
||||
strncpy(dbu->modif, reg->modif, 79);
|
||||
dbu->modif[79] = '\0';
|
||||
dbu->access = reg->access;
|
||||
dbu->flags = reg->flags;
|
||||
dbu->suspend = reg->suspend;
|
||||
dbu->lastseen = reg->lastseen;
|
||||
dbu->header[0] = 0xFF;
|
||||
dbu->header[1] = 0xFF;
|
||||
dbu->footer[0] = 0xFF;
|
||||
dbu->footer[1] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void sync_next_channel(void)
|
||||
{
|
||||
register syncchan *tmp;
|
||||
|
||||
if ((tmp = SyncChan) != NULL)
|
||||
{
|
||||
SyncChan = SyncChan->next;
|
||||
db_sync(tmp->name);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_sync(dbsync * sync)
|
||||
{
|
||||
struct dbuser dbu;
|
||||
|
||||
if (*sync->reg == NULL)
|
||||
{
|
||||
close(sync->fd);
|
||||
sync->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*sync->reg)->access == 0) /* delete */
|
||||
{
|
||||
make_dbuser(*sync->reg, &dbu);
|
||||
zap_buffer(&sync->buf);
|
||||
copy_to_buffer(&sync->buf, (char *)&dbu, sizeof(dbuser));
|
||||
sync->type = SYNC_DELETE;
|
||||
sync->status = SYNC_PENDWRITE;
|
||||
sync->offset = (*sync->reg)->offset;
|
||||
lseek(sync->fd, (*sync->reg)->offset, SEEK_SET);
|
||||
}
|
||||
else if ((*sync->reg)->offset != (off_t) - 1) /* update */
|
||||
{
|
||||
make_dbuser(*sync->reg, &dbu);
|
||||
zap_buffer(&sync->buf);
|
||||
copy_to_buffer(&sync->buf, (char *)&dbu, sizeof(dbuser));
|
||||
sync->type = SYNC_UPDATE;
|
||||
sync->status = SYNC_PENDWRITE;
|
||||
sync->offset = (*sync->reg)->offset;
|
||||
lseek(sync->fd, (*sync->reg)->offset, SEEK_SET);
|
||||
}
|
||||
else
|
||||
/* add */
|
||||
{
|
||||
sync->type = SYNC_ADD;
|
||||
sync->status = SYNC_SEEKFREE;
|
||||
sync->offset = (off_t) 0;
|
||||
lseek(sync->fd, 0L, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sync_next(dbsync * sync, char *channel)
|
||||
{
|
||||
register RegUser **reg = sync->reg;
|
||||
|
||||
if (*reg == NULL)
|
||||
{
|
||||
close(sync->fd);
|
||||
sync->fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
while (*reg != NULL && ((*reg)->modified == 0 || (*reg)->access == 1000 ||
|
||||
strcasecmp((*reg)->channel, channel)))
|
||||
{
|
||||
if ((*reg)->inuse == 0 && (*reg)->lastused + CACHE_TIMEOUT < now)
|
||||
free_user(reg);
|
||||
else
|
||||
reg = &(*reg)->next;
|
||||
}
|
||||
|
||||
sync->time = now;
|
||||
sync->reg = reg;
|
||||
set_sync(sync);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void db_sync(char *channel)
|
||||
{
|
||||
register RegUser **reg, *tmp;
|
||||
register char *ch;
|
||||
register dbsync *sync;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("SYNC: %s\n", channel);
|
||||
#endif
|
||||
|
||||
if (DBSync != NULL && (DBSync->fd != -1 || DBSync->next != NULL))
|
||||
{
|
||||
log("ERROR: simultaneous syncs??");
|
||||
return;
|
||||
}
|
||||
|
||||
ch = make_dbfname(channel);
|
||||
|
||||
/* IF file does not exist.. remove all deletes and mark
|
||||
* all other entries as new.
|
||||
*/
|
||||
if (stat(ch, &st) < 0)
|
||||
{
|
||||
/* remove all deletes */
|
||||
reg = &UserList[ul_hash(channel)];
|
||||
while (*reg)
|
||||
{
|
||||
(*reg)->offset = (off_t) - 1;
|
||||
if ((*reg)->access == 0 && (*reg)->inuse == 0 &&
|
||||
!strcasecmp((*reg)->channel, channel))
|
||||
{
|
||||
tmp = *reg;
|
||||
*reg = (*reg)->next;
|
||||
free_user(reg);
|
||||
}
|
||||
else
|
||||
reg = &(*reg)->next;
|
||||
}
|
||||
fd = open(ch, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0600);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open(ch, O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
|
||||
/* create new sync struct
|
||||
*/
|
||||
sync = (dbsync *) malloc(sizeof(dbsync));
|
||||
sync->fd = fd;
|
||||
sync->reg = &UserList[ul_hash(channel)];
|
||||
sync->buf = NULL;
|
||||
sync->next = DBSync;
|
||||
DBSync = sync;
|
||||
|
||||
sync_next(sync, channel);
|
||||
}
|
||||
|
||||
|
||||
void db_sync_ready(dbsync * sync)
|
||||
{
|
||||
struct dbuser buffer[10];
|
||||
register RegUser **reg = sync->reg;
|
||||
int size;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("SYNC_READY: status= %d\n", sync->status);
|
||||
#endif
|
||||
|
||||
if (sync->status == SYNC_PENDWRITE)
|
||||
{
|
||||
size = look_in_buffer(&sync->buf, (char *)buffer, '\0', sizeof(dbuser));
|
||||
if (size == 0)
|
||||
zap_buffer(&sync->buf);
|
||||
if (sync->buf == NULL)
|
||||
{
|
||||
if ((*reg)->access == 0 && (*reg)->inuse == 0)
|
||||
free_user(reg);
|
||||
else
|
||||
(*reg)->modified = 0;
|
||||
sync_next(sync, (*reg)->channel);
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PENDWRITE: %d bytes to write...", size);
|
||||
#endif
|
||||
size = write(sync->fd, buffer, size);
|
||||
#ifdef DEBUG
|
||||
printf("%d written\n", size);
|
||||
#endif
|
||||
if (size <= 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK && errno != EAGAIN)
|
||||
{
|
||||
close(sync->fd);
|
||||
sync->fd = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
skip_char_in_buffer(&sync->buf, size);
|
||||
}
|
||||
|
||||
else if (sync->status == SYNC_SEEKFREE)
|
||||
{
|
||||
size = read(sync->fd, buffer, 10 * sizeof(dbuser));
|
||||
if (size <= 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
{
|
||||
make_dbuser(*sync->reg, buffer);
|
||||
zap_buffer(&sync->buf);
|
||||
copy_to_buffer(&sync->buf, (char *)buffer, sizeof(dbuser));
|
||||
sync->status = SYNC_PENDWRITE;
|
||||
lseek(sync->fd, 0L, SEEK_END);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
copy_to_buffer(&sync->buf, (char *)buffer, size);
|
||||
while (look_in_buffer(&sync->buf, (char *)buffer, '\0', sizeof(dbuser))
|
||||
== sizeof(dbuser))
|
||||
{
|
||||
if (buffer[0].header[0] == 0x00 && buffer[0].header[1] == 0x00 &&
|
||||
buffer[0].footer[0] == 0x00 && buffer[0].footer[1] == 0x00)
|
||||
{
|
||||
make_dbuser(*sync->reg, buffer);
|
||||
zap_buffer(&sync->buf);
|
||||
copy_to_buffer(&sync->buf, (char *)buffer, sizeof(dbuser));
|
||||
sync->status = SYNC_PENDWRITE;
|
||||
(*sync->reg)->offset = sync->offset;
|
||||
lseek(sync->fd, sync->offset, SEEK_SET);
|
||||
return;
|
||||
}
|
||||
skip_char_in_buffer(&sync->buf, sizeof(dbuser));
|
||||
sync->offset += sizeof(dbuser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void end_db_sync(dbsync * sync)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("SYNC_END\n");
|
||||
#endif
|
||||
sync_next_channel();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void cold_save_one(RegUser * reg)
|
||||
{
|
||||
struct stat st;
|
||||
dbuser dbu;
|
||||
char *fname;
|
||||
register int fd;
|
||||
off_t off;
|
||||
|
||||
fname = make_dbfname(reg->channel);
|
||||
|
||||
if (stat(fname, &st) < 0) /* file doesn't exist -- don't save delete */
|
||||
{
|
||||
if (reg->access == 0)
|
||||
return;
|
||||
fd = open(fname, O_RDWR | O_CREAT, 0600);
|
||||
}
|
||||
else
|
||||
fd = open(fname, O_RDWR | O_EXCL);
|
||||
|
||||
if (fd < 0) /* hmmm? */
|
||||
return;
|
||||
|
||||
if (reg->offset == (off_t) - 1) /* new ==> seek for empty slot */
|
||||
{
|
||||
lseek(fd, 0L, SEEK_SET);
|
||||
off = (off_t) 0;
|
||||
while (read(fd, &dbu, sizeof(dbuser)) == sizeof(dbuser))
|
||||
{
|
||||
if (dbu.header[0] == 0x00 && dbu.header[1] == 0x00 &&
|
||||
dbu.footer[0] == 0x00 && dbu.footer[1] == 0x00)
|
||||
break; /* found empty slot */
|
||||
off += sizeof(dbuser);
|
||||
}
|
||||
}
|
||||
else
|
||||
off = reg->offset;
|
||||
|
||||
lseek(fd, off, SEEK_SET); /* go to write position */
|
||||
|
||||
if (reg->access != 0)
|
||||
make_dbuser(reg, &dbu);
|
||||
else
|
||||
memset(&dbu, 0, sizeof(dbuser));
|
||||
|
||||
write(fd, &dbu, sizeof(dbuser));
|
||||
|
||||
if (reg->access != 0)
|
||||
reg->offset = off;
|
||||
else
|
||||
reg->offset = (off_t) - 1;
|
||||
|
||||
reg->modified = 0;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
void do_cold_sync_slice(void)
|
||||
{
|
||||
register RegUser **reg;
|
||||
|
||||
if (DB_Save_Status < 0)
|
||||
return;
|
||||
|
||||
reg = &UserList[DB_Save_Status];
|
||||
while (*reg != NULL)
|
||||
{
|
||||
if ((*reg)->modified && (*reg)->access < 1000)
|
||||
cold_save_one(*reg);
|
||||
if ((*reg)->inuse == 0 && (*reg)->access < 1000 &&
|
||||
((*reg)->access == 0 || (*reg)->lastused + CACHE_TIMEOUT < now))
|
||||
free_user(reg);
|
||||
else
|
||||
reg = &(*reg)->next;
|
||||
}
|
||||
|
||||
if (++DB_Save_Status == 1000)
|
||||
{
|
||||
DB_Save_Status = -1;
|
||||
if (*DB_Save_Nick)
|
||||
notice(DB_Save_Nick, "Userlist sync complete!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void do_cold_sync(void)
|
||||
{
|
||||
register dbsync *sync;
|
||||
register syncchan *schan;
|
||||
register RegUser **reg;
|
||||
register int i;
|
||||
char buffer[200];
|
||||
|
||||
/* SET AWAY MESSAGE */
|
||||
sprintf(buffer, ":%s AWAY :Busy saving precious user list\n", mynick);
|
||||
sendtoserv(buffer);
|
||||
dumpbuff();
|
||||
|
||||
/* First, cancel *all* sync requests */
|
||||
while ((sync = DBSync) != NULL)
|
||||
{
|
||||
DBSync = DBSync->next;
|
||||
if (sync->fd >= 0)
|
||||
close(sync->fd);
|
||||
zap_buffer(&sync->buf);
|
||||
free(sync);
|
||||
}
|
||||
|
||||
/* Also, clear *all* pending syncs */
|
||||
while ((schan = SyncChan) != NULL)
|
||||
{
|
||||
SyncChan = SyncChan->next;
|
||||
free(schan);
|
||||
}
|
||||
|
||||
/* Now, go thru *all* the user entries in memory and save them
|
||||
* to their respective files.
|
||||
*/
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
reg = &UserList[i];
|
||||
while (*reg != NULL)
|
||||
{
|
||||
if ((*reg)->modified && (*reg)->access < 1000)
|
||||
cold_save_one(*reg);
|
||||
if ((*reg)->inuse == 0 && (*reg)->access < 1000 &&
|
||||
((*reg)->access == 0 || (*reg)->lastused + CACHE_TIMEOUT < now))
|
||||
free_user(reg);
|
||||
else
|
||||
reg = &(*reg)->next;
|
||||
}
|
||||
}
|
||||
sprintf(buffer, ":%s AWAY\n", mynick);
|
||||
sendtoserv(buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void db_test_callback(int *fd, off_t off, int action, void *hook1, void *hook2,
|
||||
dbuser * dbu, int count)
|
||||
{
|
||||
char buffer[512];
|
||||
|
||||
sprintf(buffer, "off: %ld act: %d hook=%p cnt: %d", off, action, hook1, count);
|
||||
notice((char *)hook1, buffer);
|
||||
|
||||
if (dbu)
|
||||
{
|
||||
sprintf(buffer, "hdr: %X%X nick: %s match: %s passwd: %s channel: %s "
|
||||
"modif: %s access: %d flags: %ld susp: %ld last: %ld ftr: %X%X",
|
||||
dbu->header[0], dbu->header[1], dbu->nick, dbu->match, dbu->passwd,
|
||||
dbu->channel, dbu->modif, dbu->access, dbu->flags, dbu->suspend,
|
||||
dbu->lastseen, dbu->footer[0], dbu->footer[1]);
|
||||
notice((char *)hook1, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
notice((char *)hook1, "End.");
|
||||
free(hook1);
|
||||
}
|
||||
}
|
||||
|
||||
void db_test(char *source, char *chan, char *args)
|
||||
{
|
||||
char channel[80], type[80], info[80], *hook;
|
||||
|
||||
GetWord(0, args, channel);
|
||||
GetWord(1, args, type);
|
||||
GetWord(2, args, info);
|
||||
hook = (char *)malloc(strlen(source) + 1);
|
||||
strcpy(hook, source);
|
||||
|
||||
if (!strcmp(type, "nick"))
|
||||
db_fetch(channel, DBGETNICK, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "alluh"))
|
||||
db_fetch(channel, DBGETALLUH, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "1stuh"))
|
||||
db_fetch(channel, DBGET1STUH, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "count"))
|
||||
db_fetch(channel, DBCOUNTUH, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "1stcmp"))
|
||||
db_fetch(channel, DBGET1STCMP, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "allcmp"))
|
||||
db_fetch(channel, DBGETALLCMP, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "cntcmp"))
|
||||
db_fetch(channel, DBCNTCMP, info, NULL, 0, hook, NULL, db_test_callback);
|
||||
|
||||
else if (!strcmp(type, "sync"))
|
||||
db_sync(channel);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user