/*
ctrlproxy: A modular IRC proxy
(c) 2002-2003 Jelmer Vernooij <jelmer@nl.linux.org>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ctrlproxy.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "log_irssi"
static char *logfile = NULL;
static GHashTable *files = NULL;
static FILE *find_add_channel_file(struct network *s, const char *name)
{
char *n = NULL;
FILE *f;
char *hash_name;
int i;
char *lowercase;
lowercase = g_ascii_strdown(name?name:"messages", -1);
hash_name = g_strdup_printf("%s/%s", s->info.name, lowercase);
g_free(lowercase);
f = g_hash_table_lookup(files, hash_name);
if(!f) {
char *cn;
const char *server_name;
server_name = s->info.name;
if(strchr(server_name, '/'))server_name = strrchr(server_name, '/');
n = g_strdup_printf("%s/%s", logfile, server_name);
/* Check if directory needs to be created */
if(!g_file_test(n, G_FILE_TEST_IS_DIR) && g_mkdir(n, 0700) == -1) {
log_network(LOG_ERROR, s, "Couldn't create directory %s for logging!", n);
g_free(hash_name);
g_free(n);
return NULL;
}
g_free(n);
/* Then open the correct filename */
cn = g_ascii_strdown(name?name:"messages", -1);
for (i = 0; cn[i]; i++) if (cn[i] == '/') cn[i] = '_';
n = g_strdup_printf("%s/%s/%s", logfile, server_name, cn);
g_free(cn);
f = fopen(n, "a+");
if(!f) {
log_network(LOG_ERROR, s, "Couldn't open file %s for logging!", n);
g_free(n);
return NULL;
}
g_free(n);
g_hash_table_insert(files, hash_name, f);
} else g_free(hash_name);
g_assert(f);
return f;
}
static void target_vprintf(struct network *n, const char *name,
char *fmt, va_list ap)
{
FILE *f = find_add_channel_file(n, name);
if (f != NULL) {
vfprintf(f, fmt, ap);
fflush(f);
}
}
static void target_printf(struct network *n, const char *name,
char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (strchr(name, ',') != NULL) {
char **channels = g_strsplit(name, ",", 0);
int i;
for (i = 0; channels[i]; i++) {
target_vprintf(n, channels[i], fmt, ap);
}
g_strfreev(channels);
} else
target_vprintf(n, name, fmt, ap);
va_end(ap);
}
static gboolean log_data(struct network *n, const struct line *l,
enum data_direction dir, void *userdata)
{
char *nick = NULL;
const char *dest = NULL;
time_t ti = time(NULL);
char *user = NULL;
struct tm *t = localtime(&ti);
if (l->args == NULL|| l->args[0] == NULL)
return TRUE;
if (l->origin) {
nick = line_get_nick(l);
user = strchr(l->origin, '!');
if (user) user++;
}
if(dir == FROM_SERVER && !g_strcasecmp(l->args[0], "JOIN")) {
target_printf(n, l->args[1], "%02d:%02d -!- %s [%s] has joined %s\n", t->tm_hour, t->tm_min, nick, user, l->args[1]);
} else if(dir == FROM_SERVER && !g_strcasecmp(l->args[0], "PART")) {
target_printf(n, l->args[1], "%02d:%02d -!- %s [%s] has left %s [%s]\n", t->tm_hour, t->tm_min, nick, user, l->args[1], l->args[2]?l->args[2]:"");
} else if(!g_strcasecmp(l->args[0], "PRIVMSG") && l->argc > 2) {
dest = l->args[1];
if (!irccmp(&n->state->info, dest, n->state->me.nick)) dest = nick;
if (l->args[2][0] == '\001') {
l->args[2][strlen(l->args[2])-1] = '\0';
if(!g_ascii_strncasecmp(l->args[2], "\001ACTION ", 8)) {
target_printf(n, dest, "%02d:%02d * %s %s\n", t->tm_hour, t->tm_min, nick, l->args[2]+8);
}
l->args[2][strlen(l->args[2])] = '\001';
/* Ignore all other ctcp messages */
} else {
target_printf(n, dest, "%02d:%02d < %s> %s\n", t->tm_hour, t->tm_min, nick, l->args[2]);
}
} else if(!g_strcasecmp(l->args[0], "MODE") && l->args[1] &&
is_channelname(l->args[1], &n->state->info) && dir == FROM_SERVER) {
target_printf(n, l->args[1], "%02d:%02d -!- mode/%s [%s %s] by %s\n", t->tm_hour, t->tm_min, l->args[1], l->args[2], l->args[3], nick);
} else if(!g_strcasecmp(l->args[0], "QUIT")) {
/* Loop thru the channels this user is on */
GList *gl;
struct network_nick *nn = find_network_nick(n->state, nick);
if (nn) {
for (gl = nn->channel_nicks; gl; gl = gl ->next) {
struct channel_nick *cn = (struct channel_nick *)gl->data;
target_printf(n, cn->channel->name, "%02d:%02d -!- %s [%s] has quit [%s]\n", t->tm_hour, t->tm_min, nick, user, l->args[1]?l->args[1]:"");
}
}
} else if(!g_strcasecmp(l->args[0], "KICK") && l->args[1] && l->args[2] && dir == FROM_SERVER) {
if(!strchr(l->args[1], ',')) {
target_printf(n, l->args[1], "%02d:%02d -!- %s has been kicked by %s [%s]\n", t->tm_hour, t->tm_min, l->args[2], nick, l->args[3]?l->args[3]:"");
} else {
char *channels = g_strdup(l->args[1]);
char *nicks = g_strdup(l->args[1]);
char *p,*nx; char cont = 1;
char *_nick;
p = channels;
_nick = nicks;
while(cont) {
nx = strchr(p, ',');
if(!nx) cont = 0;
else *nx = '\0';
target_printf(n, p, "%02d:%02d -!- %s has been kicked by %s [%s]\n", t->tm_hour, t->tm_min, _nick, nick, l->args[3]?l->args[3]:"");
p = nx+1;
_nick = strchr(_nick, ',');
if(!_nick)break;
_nick++;
}
g_free(channels);
g_free(nicks);
}
} else if(!g_strcasecmp(l->args[0], "TOPIC") && dir == FROM_SERVER && l->args[1]) {
if(l->args[2])target_printf(n, l->args[1], "%02d:%02d -!- %s has changed the topic to %s\n", t->tm_hour, t->tm_min, nick, l->args[2]);
else target_printf(n, l->args[1], "%02d:%02d -!- %s has removed the topic\n", t->tm_hour, t->tm_min, nick);
} else if (!g_strcasecmp(l->args[0], "NICK") &&
dir == FROM_SERVER && l->args[1]) {
struct network_nick *nn = find_network_nick(n->state, nick);
GList *gl;
if (nn != NULL) {
for (gl = nn->channel_nicks; gl; gl = gl->next) {
struct channel_nick *cn = gl->data;
target_printf(n, cn->channel->name, "%02d:%02d -!- %s is now known as %s\n", t->tm_hour, t->tm_min, nick, l->args[1]);
}
}
}
g_free(nick);
return TRUE;
}
static void load_config(struct global *global)
{
GKeyFile *kf = global->config->keyfile;
if (!g_key_file_has_group(kf, "log-irssi")) {
del_log_filter("log_irssi");
return;
}
if(!g_key_file_has_key(kf, "log-irssi", "logfile", NULL)) {
logfile = g_build_filename(global->config->config_dir, "log_irssi", NULL);
} else {
logfile = g_key_file_get_string(kf, "log-irssi", "logfile", NULL);
}
/* Create logfile directory if it doesn't exist yet */
g_mkdir(logfile, 0700);
add_log_filter("log_irssi", log_data, NULL, 1000);
}
static gboolean init_plugin()
{
files = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)fclose);
register_load_config_notify(load_config);
return TRUE;
}
struct plugin_ops plugin = {
.name = "log_irssi",
.version = 0,
.init = init_plugin
};
syntax highlighted by Code2HTML, v. 0.9.1