/* $Id: chanlog.c 341 2006-01-12 21:56:48Z tsaviran $
* -------------------------------------------------------
* Copyright (C) 2002-2006 Tommi Saviranta <wnd@iki.fi>
* (C) 2002 Lee Hardy <lee@leeh.co.uk>
* -------------------------------------------------------
* 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* ifdef HAVE_CONFIG_H */
#ifdef CHANLOG
#include "chanlog.h"
#include "llist.h"
#include "common.h"
#include "channels.h"
#include "client.h"
#include "miau.h"
#include "tools.h"
#include "messages.h"
#include "etc.h"
#include "log.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
int global_logtype;
llist_list chanlog_list;
/*
* Creates a logging entry in log_list.
*/
void
chanlog_add_rule(char *channels, char *file, int type)
{
char *chan;
int multi = 0;
/* Nothing to log. */
if (channels == NULL || channels[0] == '\0') {
return;
}
/*
* The "global" logentry, mark the logtype and then open logfiles
* for channels we dont have specific entries for.
*/
if (xstrcmp(channels, "*") == 0) {
global_logtype = type;
return;
}
/*
* If we're doing multi channels, mark as such so we don't use a
* specified logfile, revert to #channel.log.
*/
if (strchr(channels, ',') != NULL) {
multi = 1;
}
for (chan = strtok(channels, ","); chan != NULL;
chan = strtok(NULL, ",")) {
llist_node *node;
struct chanlogentry *logptr;
/* Check we haven't already done this channel */
for (node = chanlog_list.head; node != NULL;
node = node->next) {
logptr = (struct chanlogentry *) node->data;
if (xstrcasecmp(chan, logptr->channel) == 0) {
return;
}
}
logptr = (struct chanlogentry *)
xcalloc(sizeof(struct chanlogentry), 1);
node = llist_create(logptr);
llist_add(node, &chanlog_list);
logptr->channel = xstrdup(chan);
logptr->type = type;
/*
* If we were not given a logfilename or we're creating more
* than one entry at once, create a logfilename.
*/
if (file == NULL || multi) {
char *file;
size_t size;
/* termination and validity guaranteed */
size = strlen(LOGDIR) + strlen(chan)
+ strlen(cfg.logsuffix) + 3;
file = (char *) xmalloc(size);
snprintf(file, size, LOGDIR"/%s%s",
chan, cfg.logsuffix);
file[size - 1] = '\0';
logptr->filename = file;
} else { /* basically "if (file != NULL)" */
size_t size;
/* If filename is relative, add LOGDIR. */
/* termination and validity guaranteed */
size = strlen(LOGDIR) + strlen(file) + 3;
logptr->filename = (char *) xmalloc(size);
snprintf(logptr->filename, size, LOGDIR"/%s",
file);
logptr->filename[size - 1] = '\0';
}
}
} /* void chanlog_add_rule(char *channels, char *file, int type) */
/*
* Delete all logging rules.
*/
void
chanlog_del_rules(void)
{
LLIST_WALK_H(chanlog_list.head, struct chanlogentry *);
xfree(data->channel);
xfree(data->filename);
xfree(data);
llist_delete(node, &chanlog_list);
LLIST_WALK_F;
} /* void chanlog_del_rules(void) */
/*
* Open a logfile.
*/
void
chanlog_open(channel_type *channel)
{
/*
* Should have no need for this.
*
if (channel->log->logfile != NULL) {
return;
}
*/
/* See if a rule applies directly to this channel. */
LLIST_WALK_H(chanlog_list.head, struct chanlogentry *);
if (xstrcasecmp(channel->simple_name, data->channel) == 0) {
channel->log = (struct channel_log *)
xcalloc(sizeof(struct channel_log), 1);
/* filename termination and validity guaranteed */
channel->log->file = fopen(data->filename, "a");
if (channel->log->file == NULL) {
log_cannot_write(data->filename);
return;
}
channel->log->type = data->type;
break;
}
LLIST_WALK_F;
/* Didn't find a direct match. Use global logtype. */
if (channel->log == NULL && global_logtype) {
size_t plen;
char *p;
char *lowchan;
/* convert simple channel name to lowercase */
lowchan = xstrdup(channel->simple_name);
lowcase(lowchan);
channel->log = (struct channel_log *)
xcalloc(sizeof(struct channel_log), 1);
/* termination and validity guaranteed */
plen = strlen(LOGDIR) + strlen(lowchan)
+ strlen(cfg.logsuffix) + 3;
p = (char *) xmalloc(plen);
snprintf(p, plen, LOGDIR"/%s%s", lowchan, cfg.logsuffix);
p[plen - 1] = '\0';
channel->log->file = fopen(p, "a");
xfree(p);
xfree(lowchan);
if (channel->log->file == NULL) {
return;
}
channel->log->type = global_logtype;
}
/* Still unaware where to log ? */
if (channel->log == NULL) {
return;
}
/* ...and start logging. */
chanlog_write_entry(channel, LOGM_LOGOPEN,
get_timestamp(NULL, TIMESTAMP_LONG));
} /* void chanlog_open(channel_type *channel) */
/*
* Close logfile and free resources.
*/
void
chanlog_close(channel_type *channel)
{
if (channel->log != NULL) {
chanlog_write_entry(channel, LOGM_LOGCLOSE,
get_timestamp(NULL, TIMESTAMP_LONG));
if (channel->log->file != NULL) {
fclose(channel->log->file);
}
FREE(channel->log);
}
} /* void chanlog_close(channel_type *channel) */
/*
* Writes a logging entry to the logfile.
*/
void
chanlog_write_entry(channel_type *chptr, char *format, ...)
{
char buffer[1024];
va_list va;
/* No logfile for this channel. */
if (chptr->log == NULL || chptr->log->file == NULL) {
return;
}
/* Probably not logging when client is attached/detached. */
if ((c_clients.connected == 0 &&
! (chptr->log->type & LOG_DETACHED)) ||
(c_clients.connected > 0 &&
! (chptr->log->type & LOG_ATTACHED))) {
return;
}
va_start(va, format);
vsnprintf(buffer, 1024, format, va);
va_end(va);
buffer[1023] = '\0';
fprintf(chptr->log->file, "%s", buffer);
fflush(chptr->log->file);
} /* void chanlog_write_entry(channel_type *chptr, char *format, ...) */
/*
* Writes a logging entry to all matching logfiles.
*/
void
chanlog_write_entry_all(int type, char *format, ...)
{
char buffer[1024];
va_list va;
va_start(va, format);
vsnprintf(buffer, 1024, format, va);
va_end(va);
buffer[1023] = '\0';
LLIST_WALK_H(active_channels.head, channel_type *);
/*
* We could have it this way...
*
if (data->log == NULL || data->log->file == NULL) {
LLIST_WALK_CONTINUE;
}
if (data->log->type & type) {
log_write_entry(data, "%s", buffer);
}
*
* ...but this should compile shorter. ;-)
*/
if (! (data->log == NULL || data->log->file == NULL)
&& data->log->type & type) {
chanlog_write_entry(data, "%s", buffer);
}
LLIST_WALK_F;
} /* void chanlog_write_entry_all(int type, char *format, ...) */
int
chanlog_has_log(const channel_type *chan, int type)
{
if (chan == NULL || chan->log == NULL) {
return 0;
} else {
return (chan->log->type & type) == type;
}
} /* int chanlog_has_log(const channel_type *chan, int type) */
#endif /* ifdef CHANLOG */
syntax highlighted by Code2HTML, v. 0.9.1