1
0
mirror of https://github.com/irssi/irssi.git synced 2024-11-03 04:27:19 -05:00

..adding new files..

git-svn-id: http://svn.irssi.org/repos/irssi/trunk@171 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2000-04-26 08:03:38 +00:00 committed by cras
parent d01b094151
commit c95034c6de
206 changed files with 31247 additions and 0 deletions

59
src/core/Makefile.am Normal file
View File

@ -0,0 +1,59 @@
noinst_LTLIBRARIES = libcore.la
INCLUDES = \
$(GLIB_CFLAGS) \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core
if BUILD_MEMDEBUG
memdebug_src=memdebug.c
else
memdebug_src=
endif
libcore_la_SOURCES = \
args.c \
commands.c \
core.c \
levels.c \
line-split.c \
log.c \
$(memdebug_src) \
misc.c \
modules.c \
net-disconnect.c \
net-nonblock.c \
network.c \
pidwait.c \
rawlog.c \
server.c \
server-redirect.c \
settings.c \
signals.c \
special-vars.c
noinst_HEADERS = \
args.h \
commands.h \
core.h \
levels.h \
line-split.h \
log.h \
memdebug.h \
misc.h \
module.h \
modules.h \
net-disconnect.h \
net-nonblock.h \
network.h \
pidwait.h \
rawlog.h \
server.h \
server-redirect.h \
settings.h \
signals.h \
special-vars.h
EXTRA_DIST = \
memdebug.c

60
src/core/args.c Normal file
View File

@ -0,0 +1,60 @@
/*
args.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "args.h"
GArray *iopt_tables = NULL;
void args_register(struct poptOption *options)
{
if (iopt_tables == NULL)
iopt_tables = g_array_new(TRUE, TRUE, sizeof(struct poptOption));
while (options->longName != NULL || options->shortName != '\0' || options->arg != NULL) {
g_array_append_val(iopt_tables, *options);
options = options+1;
}
}
void args_execute(int argc, char *argv[])
{
poptContext con;
int nextopt;
if (iopt_tables == NULL)
return;
con = poptGetContext(PACKAGE, argc, argv, (struct poptOption *) (iopt_tables->data), 0);
poptReadDefaultConfig(con, TRUE);
while ((nextopt = poptGetNextOpt(con)) > 0) ;
if (nextopt != -1) {
printf(_("Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n"),
poptBadOption(con, 0),
poptStrerror(nextopt),
argv[0]);
exit(1);
}
g_array_free(iopt_tables, TRUE);
iopt_tables = NULL;
}

15
src/core/args.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __ARGS_H
#define __ARGS_H
#ifdef HAVE_POPT_H
# include <popt.h>
#else
# include "lib-popt/popt.h"
#endif
extern GArray *iopt_tables;
void args_register(struct poptOption *options);
void args_execute(int argc, char *argv[]);
#endif

462
src/core/commands.c Normal file
View File

@ -0,0 +1,462 @@
/*
commands.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "misc.h"
#include "server.h"
#include "server-redirect.h"
#include "special-vars.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#define alias_find(alias) \
iconfig_get_str("aliases", alias, NULL)
GSList *commands;
char *current_command;
static GSList *cmdget_funcs;
static int signal_default_command;
void command_bind(const char *cmd, const char *category, SIGNAL_FUNC func)
{
COMMAND_REC *rec;
char *str;
g_return_if_fail(cmd != NULL);
rec = g_new0(COMMAND_REC, 1);
rec->cmd = g_strdup(cmd);
rec->category = category == NULL ? NULL : g_strdup(category);
commands = g_slist_append(commands, rec);
if (func != NULL) {
str = g_strconcat("command ", cmd, NULL);
signal_add(str, func);
g_free(str);
}
signal_emit("commandlist new", 1, rec);
}
void command_free(COMMAND_REC *rec)
{
commands = g_slist_remove(commands, rec);
signal_emit("commandlist remove", 1, rec);
g_free_not_null(rec->category);
g_free(rec->cmd);
g_free(rec);
}
void command_unbind(const char *cmd, SIGNAL_FUNC func)
{
GSList *tmp;
char *str;
g_return_if_fail(cmd != NULL);
for (tmp = commands; tmp != NULL; tmp = tmp->next) {
COMMAND_REC *rec = tmp->data;
if (g_strcasecmp(rec->cmd, cmd) == 0) {
command_free(rec);
break;
}
}
if (func != NULL) {
str = g_strconcat("command ", cmd, NULL);
signal_remove(str, func);
g_free(str);
}
}
void command_runsub(const char *cmd, const char *data, void *p1, void *p2)
{
char *subcmd, *defcmd, *args;
g_return_if_fail(data != NULL);
/* get command.. */
subcmd = g_strdup_printf("command %s %s", cmd, data);
args = strchr(subcmd+9 + strlen(cmd), ' ');
if (args != NULL) *args++ = '\0'; else args = "";
while (*args == ' ') args++;
g_strdown(subcmd);
if (!signal_emit(subcmd, 3, args, p1, p2)) {
defcmd = g_strdup_printf("default command %s", cmd);
if (!signal_emit(defcmd, 3, data, p1, p2))
signal_emit("unknown command", 3, strchr(subcmd, ' ')+1, p1, p2);
g_free(defcmd);
}
g_free(subcmd);
}
char *cmd_get_param(char **data)
{
char *pos;
g_return_val_if_fail(data != NULL, NULL);
g_return_val_if_fail(*data != NULL, NULL);
while (**data == ' ') (*data)++;
pos = *data;
while (**data != '\0' && **data != ' ') (*data)++;
if (**data == ' ') *(*data)++ = '\0';
return pos;
}
char *cmd_get_quoted_param(char **data)
{
char *pos, quote;
g_return_val_if_fail(data != NULL, NULL);
g_return_val_if_fail(*data != NULL, NULL);
while (**data == ' ') (*data)++;
if (**data != '\'' && **data != '"')
return cmd_get_param(data);
quote = **data; (*data)++;
pos = *data;
while (**data != '\0' && **data != quote) {
if (**data == '\\' && (*data)[1] != '\0')
g_memmove(*data, (*data)+1, strlen(*data));
(*data)++;
}
if (**data != '\0') *(*data)++ = '\0';
return pos;
}
static char *get_opt_args(char **data)
{
/* -cmd1 -cmd2 -cmd3 ... */
char *p, *ret;
g_return_val_if_fail(data != NULL, NULL);
g_return_val_if_fail(*data != NULL, NULL);
ret = NULL;
for (p = *data;;) {
if (*p != '-') {
if (p == *data) return "";
while (isspace(p[-1]) && p > *data) p--;
if (*p != '\0') *p++ = '\0';
ret = *data;
*data = p;
return ret;
}
while (!isspace(*p) && *p != '\0') p++;
while (isspace(*p)) p++;
}
}
static void cmd_params_pack(char ***subargs, char *end, char *start, char *newstart)
{
char ***tmp;
char *data;
int bufsize, datalen, len;
bufsize = (int) (end-newstart)+1;
data = g_malloc(bufsize); datalen = 0;
for (tmp = subargs; *tmp != NULL; tmp++) {
if (**tmp < start || **tmp > end)
continue;
len = strlen(**tmp)+1;
if (datalen+len > bufsize)
g_error("cmd_params_pack() : buffer overflow!");
memcpy(data+datalen, **tmp, len);
**tmp = newstart+datalen;
datalen += len;
}
g_memmove(newstart, data, datalen);
g_free(data);
}
int arg_find(char **array, const char *item)
{
char **tmp;
int index;
g_return_val_if_fail(array != NULL, 0);
g_return_val_if_fail(item != NULL, 0);
index = 0;
for (tmp = array; *tmp != NULL; tmp++, index++) {
if (g_strcasecmp(*tmp + (**tmp == '@'), item) == 0)
return index;
}
return -1;
}
static int get_multi_args(char **data, va_list va)
{
/* -cmd1 arg1 -cmd2 "argument two" -cmd3 */
GString *returnargs;
char **args, **arglist, *arg, *origdata;
char **nextarg, ***subargs;
int eat, pos;
eat = 0;
args = (char **) va_arg(va, char **);
g_return_val_if_fail(args != NULL && *args != NULL && **args != '\0', 0);
arglist = g_strsplit(*args, " ", -1);
eat = strarray_length(arglist);
subargs = g_new(char **, eat+1);
for (pos = 0; pos < eat; pos++) {
subargs[pos] = (char **) va_arg(va, char **);
if (subargs[pos] == NULL) {
g_free(subargs);
g_warning("get_multi_args() : subargument == NULL");
return eat;
}
*subargs[pos] = "";
}
subargs[eat] = NULL;
origdata = *data;
returnargs = g_string_new(NULL);
nextarg = NULL;
for (;;) {
if (**data == '-') {
(*data)++; arg = cmd_get_param(data);
g_string_sprintfa(returnargs, "-%s ", arg);
/* check if this argument can have parameter */
pos = arg_find(arglist, arg);
nextarg = pos == -1 ? NULL : subargs[pos];
while (isspace(**data)) (*data)++;
continue;
}
if (nextarg == NULL)
break;
if (*arglist[pos] == '@' && !isdigit(**data))
break; /* expected a numeric argument */
/* save the sub-argument to `nextarg' */
arg = cmd_get_quoted_param(data);
*nextarg = arg; nextarg = NULL;
while (isspace(**data)) (*data)++;
}
/* ok, this is a bit stupid. this will pack the arguments in `data'
like "-arg1 subarg -arg2 sub2\0" -> "-arg1 -arg2\0subarg\0sub2\0"
this is because it's easier to free only _one_ string instead of
two (`args') when using PARAM_FLAG_MULTIARGS. */
if (origdata == *data)
*args = "";
else {
cmd_params_pack(subargs, **data == '\0' ? *data : (*data)-1,
origdata, origdata+returnargs->len);
g_string_truncate(returnargs, returnargs->len-1);
strcpy(origdata, returnargs->str);
*args = origdata;
}
g_string_free(returnargs, TRUE);
g_strfreev(arglist);
g_free(subargs);
return eat;
}
char *cmd_get_callfuncs(const char *data, int *count, va_list *args)
{
CMD_GET_FUNC func;
GSList *tmp;
char *ret, *old;
ret = g_strdup(data);
for (tmp = cmdget_funcs; tmp != NULL; tmp = tmp->next) {
func = tmp->data;
old = ret;
ret = func(ret, count, args);
g_free(old);
}
return ret;
}
char *cmd_get_params(const char *data, int count, ...)
{
char **str, *arg, *ret, *datad;
va_list args;
int cnt, eat;
g_return_val_if_fail(data != NULL, NULL);
va_start(args, count);
ret = datad = cmd_get_callfuncs(data, &count, &args);
cnt = PARAM_WITHOUT_FLAGS(count);
while (cnt-- > 0) {
if (count & PARAM_FLAG_OPTARGS) {
arg = get_opt_args(&datad);
count &= ~PARAM_FLAG_OPTARGS;
} else if (count & PARAM_FLAG_MULTIARGS) {
eat = get_multi_args(&datad, args)+1;
count &= ~PARAM_FLAG_MULTIARGS;
cnt -= eat-1;
while (eat-- > 0)
str = (char **) va_arg(args, char **);
continue;
} else if (cnt == 0 && count & PARAM_FLAG_GETREST) {
/* get rest */
arg = datad;
} else {
arg = cmd_get_quoted_param(&datad);
}
str = (char **) va_arg(args, char **);
if (str != NULL) *str = arg;
}
va_end(args);
return ret;
}
void cmd_get_add_func(CMD_GET_FUNC func)
{
cmdget_funcs = g_slist_prepend(cmdget_funcs, func);
}
void cmd_get_remove_func(CMD_GET_FUNC func)
{
cmdget_funcs = g_slist_prepend(cmdget_funcs, func);
}
static void parse_outgoing(const char *line, SERVER_REC *server, void *item)
{
const char *cmdchars, *alias;
char *cmd, *str, *args, *oldcmd;
int use_alias = TRUE;
g_return_if_fail(line != NULL);
if (*line == '\0') {
/* empty line, forget it. */
signal_stop();
return;
}
cmdchars = settings_get_str("cmdchars");
if (strchr(cmdchars, *line) == NULL)
return; /* handle only /commands here */
line++;
/* //command ignores aliases */
if (strchr(cmdchars, *line) != NULL) {
line++;
use_alias = FALSE;
}
cmd = str = g_strconcat("command ", line, NULL);
args = strchr(cmd+8, ' ');
if (args != NULL) *args++ = '\0'; else args = "";
/* check if there's an alias for command */
alias = use_alias ? alias_find(cmd+8) : NULL;
if (alias != NULL)
eval_special_string(alias, args, server, item);
else {
if (server != NULL)
server_redirect_default((SERVER_REC *) server, cmd);
g_strdown(cmd);
oldcmd = current_command;
current_command = cmd+8;
if (!signal_emit(cmd, 3, args, server, item))
signal_emit_id(signal_default_command, 3, line, server, item);
current_command = oldcmd;
}
g_free(str);
}
static void cmd_eval(const char *data, SERVER_REC *server, void *item)
{
g_return_if_fail(data != NULL);
eval_special_string(data, "", server, item);
}
static void cmd_cd(const char *data)
{
char *str;
g_return_if_fail(data != NULL);
if (*data == '\0') return;
str = convert_home(data);
chdir(str);
g_free(str);
}
void commands_init(void)
{
cmdget_funcs = NULL;
current_command = NULL;
signal_default_command = module_get_uniq_id_str("signals", "default command");
settings_add_str("misc", "cmdchars", "/");
signal_add("send command", (SIGNAL_FUNC) parse_outgoing);
command_bind("eval", NULL, (SIGNAL_FUNC) cmd_eval);
command_bind("cd", NULL, (SIGNAL_FUNC) cmd_cd);
}
void commands_deinit(void)
{
g_free_not_null(current_command);
g_slist_free(cmdget_funcs);
signal_remove("send command", (SIGNAL_FUNC) parse_outgoing);
command_unbind("eval", (SIGNAL_FUNC) cmd_eval);
command_unbind("cd", (SIGNAL_FUNC) cmd_cd);
}

74
src/core/commands.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef __COMMANDS_H
#define __COMMANDS_H
#include "signals.h"
typedef struct {
char *category;
char *cmd;
}
COMMAND_REC;
enum {
CMDERR_PARAM, /* invalid parameter */
CMDERR_NOT_ENOUGH_PARAMS, /* not enough parameters given */
CMDERR_NOT_CONNECTED, /* not connected to IRC server */
CMDERR_NOT_JOINED, /* not joined to any channels in this window */
CMDERR_GETSOCKNAME, /* getsockname() failed */
CMDERR_LISTEN, /* listen() failed */
CMDERR_MULTIPLE_MATCHES, /* multiple matches found, didn't do anything */
CMDERR_NICK_NOT_FOUND, /* nick not found */
CMDERR_CHAN_NOT_FOUND, /* channel not found */
CMDERR_SERVER_NOT_FOUND, /* server not found */
CMDERR_CHAN_NOT_SYNCED, /* channel not fully synchronized yet */
CMDERR_NOT_GOOD_IDEA /* not good idea to do, -yes overrides this */
};
#define cmd_return_error(a) { signal_emit("error command", 1, GINT_TO_POINTER(a)); return; }
#define cmd_param_error(a) { g_free(params); cmd_return_error(a); }
extern GSList *commands;
extern char *current_command;
void command_bind(const char *cmd, const char *category, SIGNAL_FUNC func);
void command_unbind(const char *cmd, SIGNAL_FUNC func);
void command_runsub(const char *cmd, const char *data, void *p1, void *p2);
/* count can have these flags: */
#define PARAM_WITHOUT_FLAGS(a) ((a) & 0x00ffffff)
/* cmd_get_params() */
#define PARAM_FLAG_GETREST 0x02000000
/* optional arguments (-cmd -cmd2 -cmd3) */
#define PARAM_FLAG_OPTARGS 0x04000000
/* arguments can have arguments too. Example:
-cmd arg -noargcmd -cmd2 "another arg -optnumarg rest of the text
You would call this with:
args = "cmd cmd2 @optnumarg";
cmd_get_params(data, 5 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST,
&args, &arg_cmd, &arg_cmd2, &arg_optnum, &rest);
The variables are filled as following:
args = "-cmd -noargcmd -cmd2 -optnumarg"
arg_cmd = "arg"
arg_cmd2 = "another arg"
rest = "rest of the text"
arg_optnum = "" - this is because "rest" isn't a numeric value
*/
#define PARAM_FLAG_MULTIARGS 0x08000000
char *cmd_get_param(char **data);
char *cmd_get_params(const char *data, int count, ...);
typedef char* (*CMD_GET_FUNC) (const char *data, int *count, va_list *args);
void cmd_get_add_func(CMD_GET_FUNC func);
void cmd_get_remove_func(CMD_GET_FUNC func);
void commands_init(void);
void commands_deinit(void);
#endif

68
src/core/core.c Normal file
View File

@ -0,0 +1,68 @@
/*
core.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "modules.h"
#include "pidwait.h"
#include "net-disconnect.h"
#include "signals.h"
#include "settings.h"
#include "server.h"
#include "commands.h"
#include "log.h"
#include "rawlog.h"
#include "special-vars.h"
int irssi_gui;
void core_init(void)
{
modules_init();
pidwait_init();
net_disconnect_init();
signals_init();
settings_init();
servers_init();
commands_init();
log_init();
rawlog_init();
special_vars_init();
}
void core_deinit(void)
{
special_vars_deinit();
rawlog_deinit();
log_deinit();
commands_deinit();
servers_deinit();
settings_deinit();
signals_deinit();
net_disconnect_deinit();
pidwait_deinit();
modules_deinit();
}

17
src/core/core.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef __IRSSI_CORE_H
#define __IRSSI_CORE_H
/* for determining what GUI is currently in use: */
#define IRSSI_GUI_NONE 0
#define IRSSI_GUI_TEXT 1
#define IRSSI_GUI_GTK 2
#define IRSSI_GUI_GNOME 3
#define IRSSI_GUI_QT 4
#define IRSSI_GUI_KDE 5
extern int irssi_gui;
void core_init(void);
void core_deinit(void);
#endif

160
src/core/levels.c Normal file
View File

@ -0,0 +1,160 @@
/*
levels.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "levels.h"
static char *levels[] =
{
"CRAP",
"MSGS",
"PUBLICS",
"NOTICES",
"SNOTES",
"CTCPS",
"ACTIONS",
"JOINS",
"PARTS",
"QUITS",
"KICKS",
"MODES",
"TOPICS",
"WALLS",
"WALLOPS",
"INVITES",
"NICKS",
"DCC",
"CLIENTNOTICES",
"CLIENTCRAP",
"CLIENTERRORS",
"HILIGHT",
"NOHILIGHT",
NULL
};
int level_get(const char *level)
{
int n, len;
if (strcmp(level, "ALL") == 0)
return MSGLEVEL_ALL;
if (strcmp(level, "NEVER") == 0)
return MSGLEVEL_NEVER;
/* I never remember if it was PUBLIC or PUBLICS, MSG or MSGS, etc.
So, make it work with both. */
len = strlen(level);
if (toupper(level[len-1]) == 'S') len--;
for (n = 0; levels[n] != NULL; n++) {
if (strncmp(levels[n], level, len) == 0 &&
(levels[n][len] == '\0' || strcmp(levels[n]+len, "S") == 0))
return 1 << n;
}
return 0;
}
int level2bits(const char *level)
{
char *orig, *str, *ptr;
int ret, slevel, neg;
g_return_val_if_fail(level != NULL, 0);
if (*level == '\0')
return 0;
orig = str = g_strdup(level);
g_strup(str);
ret = 0;
for (ptr = str; ; str++) {
if (*str == ' ')
*str++ = '\0';
else if (*str != '\0')
continue;
neg = *ptr == '-' ? 1 : 0;
if (*ptr == '-' || *ptr == '+') ptr++;
slevel = level_get(ptr);
if (slevel != 0) {
ret = !neg ? (ret | slevel) :
(ret & ~slevel);
}
while (*str == ' ') str++;
if (*str == '\0') break;
ptr = str;
}
g_free(orig);
return ret;
}
char *bits2level(int bits)
{
GString *str;
char *ret;
int n;
if (bits == MSGLEVEL_ALL)
return g_strdup("ALL");
str = g_string_new(NULL);
if (bits & MSGLEVEL_NEVER)
g_string_append(str, "NEVER ");
for (n = 0; levels[n] != NULL; n++) {
if (bits & (1 << n))
g_string_sprintfa(str, "%s ", levels[n]);
}
g_string_truncate(str, str->len-1);
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
int combine_level(int dest, const char *src)
{
char **list, **item;
int itemlevel;
g_return_val_if_fail(src != NULL, dest);
list = g_strsplit(src, " ", -1);
for (item = list; *item != NULL; item++) {
g_strup(*item);
itemlevel = level_get(*item + (**item == '+' || **item == '-' ? 1 : 0));
if (**item == '-')
dest &= ~(itemlevel);
else
dest |= itemlevel;
}
g_strfreev(list);
return dest;
}

44
src/core/levels.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef __LEVELS_H
#define __LEVELS_H
/* This is pretty much IRC specific, but I think it would be easier for
other chats to try to use these same levels instead of implementing too
difficult message leveling system (which might be done if really
needed..). */
/* Message levels */
#define MSGLEVEL_CRAP 0x0000001
#define MSGLEVEL_MSGS 0x0000002
#define MSGLEVEL_PUBLIC 0x0000004
#define MSGLEVEL_NOTICES 0x0000008
#define MSGLEVEL_SNOTES 0x0000010
#define MSGLEVEL_CTCPS 0x0000020
#define MSGLEVEL_ACTIONS 0x0000040
#define MSGLEVEL_JOINS 0x0000080
#define MSGLEVEL_PARTS 0x0000100
#define MSGLEVEL_QUITS 0x0000200
#define MSGLEVEL_KICKS 0x0000400
#define MSGLEVEL_MODES 0x0000800
#define MSGLEVEL_TOPICS 0x0001000
#define MSGLEVEL_WALLS 0x0002000
#define MSGLEVEL_WALLOPS 0x0004000
#define MSGLEVEL_INVITES 0x0008000
#define MSGLEVEL_NICKS 0x0010000
#define MSGLEVEL_DCC 0x0020000
#define MSGLEVEL_CLIENTNOTICE 0x0040000
#define MSGLEVEL_CLIENTCRAP 0x0080000
#define MSGLEVEL_CLIENTERROR 0x0100000
#define MSGLEVEL_HILIGHT 0x0200000
#define MSGLEVEL_ALL 0x03fffff
#define MSGLEVEL_NOHILIGHT 0x1000000 /* Don't try to hilight words in this message */
#define MSGLEVEL_NO_ACT 0x2000000 /* Don't trigger channel activity */
#define MSGLEVEL_NEVER 0x4000000 /* never ignore / never log */
#define MSGLEVEL_LASTLOG 0x8000000 /* never ignore / never log */
int level2bits(const char *level);
char *bits2level(int bits);
int combine_level(int dest, const char *src);
#endif

147
src/core/line-split.c Normal file
View File

@ -0,0 +1,147 @@
/*
line-split.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
/* Maximum line length - split to two lines if it's longer than this.
This is mostly to prevent excessive memory usage. Like if someone DCC
chats you, you both have very fast connections and the other side sends
you 100 megs of text without any line feeds -> irssi will (try to)
allocate 128M of memory for the line and will eventually crash when it
can't allocate any more memory. If the line is split at every 64k the
text buffer will free the old lines and the memory usage never gets
too high. */
#define MAX_CHARS_IN_LINE 65536
typedef struct {
int len;
int alloc;
int remove;
char *str;
} LINEBUF_REC;
static inline int nearest_power(int num)
{
int n = 1;
while (n < num) n <<= 1;
return n;
}
static void linebuf_append(LINEBUF_REC *rec, const char *data, int len)
{
if (rec->len+len > rec->alloc) {
rec->alloc = nearest_power(rec->len+len);;
rec->str = rec->str == NULL ? g_malloc(rec->alloc) :
g_realloc(rec->str, rec->alloc);
}
memcpy(rec->str + rec->len, data, len);
rec->len += len;
}
static char *linebuf_find(LINEBUF_REC *rec, char chr)
{
int n;
for (n = 0; n < rec->len; n++)
if (rec->str[n] == chr) return rec->str+n;
return NULL;
}
static int remove_newline(LINEBUF_REC *rec)
{
char *ptr;
ptr = linebuf_find(rec, '\n');
if (ptr == NULL) {
/* LF wasn't found, wait for more data.. */
if (rec->len < MAX_CHARS_IN_LINE)
return 0;
/* line buffer is too big - force a newline. */
linebuf_append(rec, "\n", 1);
ptr = rec->str+rec->len-1;
}
rec->remove = (int) (ptr-rec->str)+1;
if (ptr != rec->str && ptr[-1] == '\r') {
/* remove CR too. */
ptr--;
}
*ptr = '\0';
return 1;
}
/* line-split `data'. Initially `*buffer' should contain NULL. */
int line_split(const char *data, int len, char **output, LINEBUF_REC **buffer)
{
LINEBUF_REC *rec;
g_return_val_if_fail(data != NULL, -1);
g_return_val_if_fail(output != NULL, -1);
g_return_val_if_fail(buffer != NULL, -1);
if (*buffer == NULL)
*buffer = g_new0(LINEBUF_REC, 1);
rec = *buffer;
if (rec->remove > 0) {
rec->len = rec->len - rec->remove;
memcpy(rec->str, rec->str+rec->remove, rec->len);
rec->remove = 0;
}
if (len > 0)
linebuf_append(rec, data, len);
else if (len < 0) {
/* connection closed.. */
if (rec->len == 0)
return -1;
/* no new data got but still something in buffer.. */
len = 0;
if (linebuf_find(rec, '\n') == NULL) {
/* connection closed and last line is missing \n ..
just add it so we can see if it had anything useful.. */
linebuf_append(rec, "\n", 1);
}
}
*output = rec->str;
return remove_newline(rec);
}
void line_split_free(LINEBUF_REC *buffer)
{
if (buffer != NULL) {
if (buffer->str != NULL) g_free(buffer->str);
g_free(buffer);
}
}
/* Return 1 if there is no data in the buffer */
int line_split_is_empty(LINEBUF_REC *buffer)
{
return buffer->len == 0;
}

13
src/core/line-split.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __LINE_SPLIT_H
#define __LINE_SPLIT_H
typedef struct _LINEBUF_REC LINEBUF_REC;
/* line-split `data'. Initially `*buffer' should contain NULL. */
int line_split(const char *data, int len, char **output, LINEBUF_REC **buffer);
void line_split_free(LINEBUF_REC *buffer);
/* Return 1 if there is no data in the buffer */
int line_split_is_empty(LINEBUF_REC *buffer);
#endif

438
src/core/log.c Normal file
View File

@ -0,0 +1,438 @@
/*
log.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "commands.h"
#include "levels.h"
#include "misc.h"
#include "log.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#define LOG_FILE_CREATE_MODE 644
#ifdef HAVE_FCNTL
static struct flock lock;
#endif
GSList *logs;
const char *log_timestamp;
static int log_file_create_mode;
static int rotate_tag;
static void log_write_timestamp(int handle, const char *format, const char *suffix, time_t t)
{
struct tm *tm;
char str[256];
tm = localtime(&t);
str[sizeof(str)-1] = '\0';
strftime(str, sizeof(str)-1, format, tm);
write(handle, str, strlen(str));
if (suffix != NULL) write(handle, suffix, strlen(suffix));
}
int log_start_logging(LOG_REC *log)
{
char *str, fname[1024];
struct tm *tm;
time_t t;
g_return_val_if_fail(log != NULL, FALSE);
if (log->handle != -1)
return TRUE;
t = time(NULL);
tm = localtime(&t);
/* Append/create log file */
str = convert_home(log->fname);
strftime(fname, sizeof(fname), str, tm);
log->handle = open(fname, O_WRONLY | O_APPEND | O_CREAT, log_file_create_mode);
g_free(str);
if (log->handle == -1) return FALSE;
#ifdef HAVE_FCNTL
memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
if (fcntl(log->handle, F_SETLK, &lock) == -1) {
close(log->handle);
log->handle = -1;
signal_emit("log locked", 1, log);
return FALSE;
}
#endif
lseek(log->handle, 0, SEEK_END);
log->opened = log->last = time(NULL);
log_write_timestamp(log->handle, settings_get_str("log_open_string"), "\n", log->last);
signal_emit("log started", 1, log);
return TRUE;
}
void log_stop_logging(LOG_REC *log)
{
g_return_if_fail(log != NULL);
if (log->handle == -1)
return;
signal_emit("log stopped", 1, log);
log_write_timestamp(log->handle, settings_get_str("log_close_string"), "\n", time(NULL));
#ifdef HAVE_FCNTL
memset(&lock, 0, sizeof(lock));
lock.l_type = F_UNLCK;
fcntl(log->handle, F_SETLK, &lock);
#endif
close(log->handle);
log->handle = -1;
}
void log_write_rec(LOG_REC *log, const char *str)
{
struct tm *tm;
time_t t;
int day;
g_return_if_fail(log != NULL);
g_return_if_fail(str != NULL);
if (log->handle == -1)
return;
t = time(NULL);
tm = localtime(&t);
day = tm->tm_mday;
tm = localtime(&log->last);
if (tm->tm_mday != day) {
/* day changed */
log_write_timestamp(log->handle, settings_get_str("log_day_changed"), "\n", t);
}
log->last = t;
log_write_timestamp(log->handle, log_timestamp, str, t);
write(log->handle, "\n", 1);
signal_emit("log written", 2, log, str);
}
void log_file_write(const char *item, int level, const char *str, int no_fallbacks)
{
GSList *tmp, *fallbacks;
char *tmpstr;
int found;
g_return_if_fail(str != NULL);
fallbacks = NULL; found = FALSE;
for (tmp = logs; tmp != NULL; tmp = tmp->next) {
LOG_REC *rec = tmp->data;
if (rec->handle == -1)
continue; /* log not opened yet */
if ((level & rec->level) == 0)
continue;
if (rec->items == NULL)
fallbacks = g_slist_append(fallbacks, rec);
else if (item != NULL && strarray_find(rec->items, item) != -1)
log_write_rec(rec, str);
}
if (!found && !no_fallbacks && fallbacks != NULL) {
/* not found from any items, so write it to all main logs */
tmpstr = NULL;
if (level & MSGLEVEL_PUBLIC)
tmpstr = g_strconcat(item, ": ", str, NULL);
g_slist_foreach(fallbacks, (GFunc) log_write_rec, tmpstr ? tmpstr : (char *)str);
g_free_not_null(tmpstr);
}
g_slist_free(fallbacks);
}
void log_write(const char *item, int level, const char *str)
{
log_file_write(item, level, str, TRUE);
}
LOG_REC *log_find(const char *fname)
{
GSList *tmp;
for (tmp = logs; tmp != NULL; tmp = tmp->next) {
LOG_REC *rec = tmp->data;
if (strcmp(rec->fname, fname) == 0)
return rec;
}
return NULL;
}
const char *log_rotate2str(int rotate)
{
switch (rotate) {
case LOG_ROTATE_HOUR:
return "hour";
case LOG_ROTATE_DAY:
return "day";
case LOG_ROTATE_WEEK:
return "week";
case LOG_ROTATE_MONTH:
return "month";
}
return NULL;
}
int log_str2rotate(const char *str)
{
if (str == NULL)
return -1;
if (g_strncasecmp(str, "hour", 4) == 0)
return LOG_ROTATE_HOUR;
if (g_strncasecmp(str, "day", 3) == 0)
return LOG_ROTATE_DAY;
if (g_strncasecmp(str, "week", 4) == 0)
return LOG_ROTATE_WEEK;
if (g_strncasecmp(str, "month", 5) == 0)
return LOG_ROTATE_MONTH;
if (g_strncasecmp(str, "never", 5) == 0)
return LOG_ROTATE_NEVER;
return -1;
}
static void log_set_config(LOG_REC *log)
{
CONFIG_NODE *node;
char *levelstr;
node = iconfig_node_traverse("logs", TRUE);
node = config_node_section(node, log->fname, NODE_TYPE_BLOCK);
if (log->autoopen)
config_node_set_bool(node, "auto_open", TRUE);
else
config_node_set_str(node, "auto_open", NULL);
config_node_set_str(node, "rotate", log_rotate2str(log->rotate));
levelstr = bits2level(log->level);
config_node_set_str(node, "level", levelstr);
g_free(levelstr);
config_node_set_str(node, "items", NULL);
if (log->items != NULL && *log->items != NULL) {
node = config_node_section(node, "items", NODE_TYPE_LIST);
config_node_add_list(node, log->items);
}
}
static void log_remove_config(LOG_REC *log)
{
iconfig_set_str("logs", log->fname, NULL);
}
LOG_REC *log_create_rec(const char *fname, int level, const char *items)
{
LOG_REC *rec;
g_return_val_if_fail(fname != NULL, NULL);
rec = log_find(fname);
if (rec == NULL) {
rec = g_new0(LOG_REC, 1);
rec->fname = g_strdup(fname);
rec->handle = -1;
} else {
g_strfreev(rec->items);
}
rec->items = items == NULL || *items == '\0' ? NULL :
g_strsplit(items, " ", -1);
rec->level = level;
return rec;
}
void log_update(LOG_REC *log)
{
g_return_if_fail(log != NULL);
if (log_find(log->fname) == NULL) {
logs = g_slist_append(logs, log);
log->handle = -1;
}
log_set_config(log);
signal_emit("log new", 1, log);
}
void log_close(LOG_REC *log)
{
g_return_if_fail(log != NULL);
log_remove_config(log);
if (log->handle != -1)
log_stop_logging(log);
logs = g_slist_remove(logs, log);
signal_emit("log remove", 1, log);
if (log->items != NULL) g_strfreev(log->items);
g_free(log->fname);
g_free(log);
}
static void sig_printtext_stripped(void *server, const char *item, gpointer levelp, const char *str)
{
int level;
g_return_if_fail(str != NULL);
level = GPOINTER_TO_INT(levelp);
if (logs != NULL && level != MSGLEVEL_NEVER)
log_file_write(item, level, str, FALSE);
}
static int sig_rotate_check(void)
{
static int last_hour = -1;
struct tm tm_now, *tm;
GSList *tmp;
time_t now;
/* don't do anything until hour is changed */
now = time(NULL);
memcpy(&tm_now, localtime(&now), sizeof(tm_now));
if (tm_now.tm_hour == last_hour) return 1;
last_hour = tm_now.tm_hour;
for (tmp = logs; tmp != NULL; tmp = tmp->next) {
LOG_REC *rec = tmp->data;
if (rec->handle == -1 || rec->rotate == LOG_ROTATE_NEVER)
continue;
tm = localtime(&rec->opened);
if (rec->rotate == LOG_ROTATE_MONTH) {
if (tm->tm_mon == tm_now.tm_mon)
continue;
} else if (rec->rotate == LOG_ROTATE_WEEK) {
if (tm->tm_wday != 1 || tm->tm_mday == tm_now.tm_mday)
continue;
} else if (rec->rotate == LOG_ROTATE_DAY) {
if (tm->tm_mday == tm_now.tm_mday)
continue;
}
log_stop_logging(rec);
log_start_logging(rec);
}
return 1;
}
static void log_read_config(void)
{
CONFIG_NODE *node;
LOG_REC *log;
GSList *tmp;
while (logs != NULL)
log_close(logs->data);
node = iconfig_node_traverse("logs", FALSE);
if (node == NULL) return;
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
node = tmp->data;
if (node->type != NODE_TYPE_BLOCK)
continue;
log = g_new0(LOG_REC, 1);
logs = g_slist_append(logs, log);
log->handle = -1;
log->fname = g_strdup(node->key);
log->autoopen = config_node_get_bool(node, "auto_open", FALSE);
log->level = level2bits(config_node_get_str(node, "level", 0));
log->rotate = log_str2rotate(config_node_get_str(node, "rotate", NULL));
if (log->rotate < 0) log->rotate = LOG_ROTATE_NEVER;
node = config_node_section(node, "items", -1);
if (node != NULL) log->items = config_node_get_list(node);
if (log->autoopen) log_start_logging(log);
}
}
static void read_settings(void)
{
log_timestamp = settings_get_str("log_timestamp");
log_file_create_mode = octal2dec(settings_get_int("log_create_mode"));
}
void log_init(void)
{
rotate_tag = g_timeout_add(60000, (GSourceFunc) sig_rotate_check, NULL);
logs = NULL;
settings_add_int("log", "log_create_mode", LOG_FILE_CREATE_MODE);
settings_add_str("log", "log_timestamp", "%H:%M ");
settings_add_str("log", "log_open_string", "--- Log opened %a %b %d %H:%M:%S %Y");
settings_add_str("log", "log_close_string", "--- Log closed %a %b %d %H:%M:%S %Y");
settings_add_str("log", "log_day_changed", "--- Day changed %a %b %d %Y");
read_settings();
log_read_config();
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
signal_add("setup reread", (SIGNAL_FUNC) log_read_config);
signal_add("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped);
}
void log_deinit(void)
{
g_source_remove(rotate_tag);
while (logs != NULL)
log_close(logs->data);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
signal_remove("setup reread", (SIGNAL_FUNC) log_read_config);
signal_remove("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped);
}

49
src/core/log.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef __LOG_H
#define __LOG_H
enum {
LOG_ROTATE_NEVER,
LOG_ROTATE_HOUR,
LOG_ROTATE_DAY,
LOG_ROTATE_WEEK,
LOG_ROTATE_MONTH
};
typedef struct {
char *fname; /* file name */
int handle; /* file handle */
time_t opened;
int level; /* log only these levels */
char **items; /* log only on these items (channels, queries, window refnums) */
time_t last; /* when last message was written */
int rotate;
int autoopen:1; /* automatically start logging at startup */
int temp:1; /* don't save this to config file */
} LOG_REC;
extern GSList *logs;
/* Create log record - you still need to call log_update() to actually add it
into log list */
LOG_REC *log_create_rec(const char *fname, int level, const char *items);
void log_update(LOG_REC *log);
void log_close(LOG_REC *log);
LOG_REC *log_find(const char *fname);
void log_write(const char *item, int level, const char *str);
void log_write_rec(LOG_REC *log, const char *str);
const char *log_rotate2str(int rotate);
int log_str2rotate(const char *str);
int log_start_logging(LOG_REC *log);
void log_stop_logging(LOG_REC *log);
void log_init(void);
void log_deinit(void);
#endif

356
src/core/memdebug.c Normal file
View File

@ -0,0 +1,356 @@
/*
memdebug.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#define ENABLE_BUFFER_CHECKS
#define BUFFER_CHECK_SIZE 5
#define MIN_BUFFER_CHECK_SIZE 2
typedef struct {
void *p;
int size;
char *file;
int line;
char *comment;
} MEM_REC;
static GHashTable *data = NULL, *preallocs = NULL;
static const char *comment = "";
static void add_flow_checks(guchar *p, unsigned long size)
{
#ifdef ENABLE_BUFFER_CHECKS
int n;
for (n = 0; n < BUFFER_CHECK_SIZE; n++)
p[n] = n ^ 0x7f;
for (n = 0; n < BUFFER_CHECK_SIZE; n++)
p[size-BUFFER_CHECK_SIZE+n] = n ^ 0x7f;
#endif
}
void ig_memcheck_rec(void *key, MEM_REC *rec)
{
guchar *p;
int n;
if (rec->size != INT_MIN){
p = rec->p;
for (n = 0; n < MIN_BUFFER_CHECK_SIZE; n++)
if (p[n] != (n ^ 0x7f))
g_error("buffer underflow, file %s line %d!\n", rec->file, rec->line);
for (n = 0; n < MIN_BUFFER_CHECK_SIZE; n++)
if (p[rec->size-BUFFER_CHECK_SIZE+n] != (n ^ 0x7f))
g_error("buffer overflow, file %s line %d!\n", rec->file, rec->line);
}
}
static void mem_check(void)
{
#ifdef ENABLE_BUFFER_CHECKS
g_hash_table_foreach(data, (GHFunc) ig_memcheck_rec, NULL);
#endif
}
static void data_add(void *p, int size, const char *file, int line)
{
MEM_REC *rec;
if (size <= 0 && size != INT_MIN)
g_error("size = %d, file %s line %d", size, file, line);
if (data == NULL) {
data = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
preallocs = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
}
if (g_hash_table_lookup(data, p) != NULL)
g_error("data_add() already malloc()'ed %p (in %s:%d)", p, file, line);
rec = g_new(MEM_REC, 1);
g_hash_table_insert(data, p, rec);
rec->p = p;
rec->size = size;
rec->file = (char *) file;
rec->line = line;
rec->comment = g_strdup(comment);
if (size == INT_MIN)
g_hash_table_insert(preallocs, p-BUFFER_CHECK_SIZE, p);
else
add_flow_checks(p, size);
mem_check();
}
static void *data_remove(void *p, const char *file, int line)
{
MEM_REC *rec;
mem_check();
if (g_hash_table_lookup(preallocs, p) != NULL) {
g_hash_table_remove(preallocs, p);
p += BUFFER_CHECK_SIZE;
}
rec = g_hash_table_lookup(data, p);
if (rec == NULL) {
g_warning("data_remove() data %p not found (in %s:%d)", p, file, line);
return p+BUFFER_CHECK_SIZE;
}
g_hash_table_remove(data, p);
g_free(rec->comment);
g_free(rec);
return p;
}
void *ig_malloc(int size, const char *file, int line)
{
#if 1
void *p;
size += BUFFER_CHECK_SIZE*2;
p = g_malloc(size);
data_add(p, size, file, line);
return p+BUFFER_CHECK_SIZE;
#else
return g_malloc(size);
#endif
}
void *ig_malloc0(int size, const char *file, int line)
{
#if 1
void *p;
size += BUFFER_CHECK_SIZE*2;
p = g_malloc0(size);
data_add(p, size, file, line);
return p+BUFFER_CHECK_SIZE;
#else
return g_malloc0(size);
#endif
}
void *ig_realloc(void *mem, unsigned long size, const char *file, int line)
{
#if 1
void *p;
size += BUFFER_CHECK_SIZE*2;
mem -= BUFFER_CHECK_SIZE;
data_remove(mem, file, line);
p = g_realloc(mem, size);
data_add(p, size, file, line);
return p+BUFFER_CHECK_SIZE;
#else
return g_realloc(mem, size);
#endif
}
char *ig_strdup(const char *str, const char *file, int line)
{
void *p;
if (str == NULL) return NULL;
p = ig_malloc(strlen(str)+1, file, line);
strcpy(p, str);
return p;
}
char *ig_strndup(const char *str, int count, const char *file, int line)
{
char *p;
if (str == NULL) return NULL;
p = ig_malloc(count+1, file, line);
strncpy(p, str, count); p[count] = '\0';
return p;
}
char *ig_strconcat(const char *file, int line, const char *str, ...)
{
guint l;
va_list args;
char *s;
char *concat;
g_return_val_if_fail (str != NULL, NULL);
l = 1 + strlen (str);
va_start (args, str);
s = va_arg (args, char*);
while (s)
{
l += strlen (s);
s = va_arg (args, char*);
}
va_end (args);
concat = ig_malloc(l, file, line);
concat[0] = 0;
strcat (concat, str);
va_start (args, str);
s = va_arg (args, char*);
while (s)
{
strcat (concat, s);
s = va_arg (args, char*);
}
va_end (args);
return concat;
}
char *ig_strdup_printf(const char *file, int line, const char *format, ...)
{
char *buffer, *p;
va_list args;
va_start (args, format);
buffer = g_strdup_vprintf (format, args);
va_end (args);
p = ig_malloc(strlen(buffer)+1, file, line);
strcpy(p, buffer);
g_free(buffer);
return p;
}
char *ig_strdup_vprintf(const char *file, int line, const char *format, va_list args)
{
char *buffer, *p;
buffer = g_strdup_vprintf (format, args);
p = ig_malloc(strlen(buffer)+1, file, line);
strcpy(p, buffer);
g_free(buffer);
return p;
}
void ig_free(void *p)
{
#if 1
p -= BUFFER_CHECK_SIZE;
p = data_remove(p, "??", 0);
if (p != NULL)
#endif
g_free(p);
}
GString *ig_string_new(const char *file, int line, const char *str)
{
GString *ret;
ret = g_string_new(str);
data_add(ret, INT_MIN, file, line);
return ret;
}
void ig_string_free(const char *file, int line, GString *str, gboolean freeit)
{
data_remove(str, file, line);
if (!freeit)
data_add(str->str, INT_MIN, file, line);
g_string_free(str, freeit);
}
char *ig_strjoinv(const char *file, int line, const char *sepa, char **array)
{
char *ret;
ret = g_strjoinv(sepa, array);
data_add(ret, INT_MIN, file, line);
return ret;
}
void ig_profile_line(void *key, MEM_REC *rec)
{
char *data;
if (*rec->comment == '\0' &&
(strcmp(rec->file, "ig_strdup_printf") == 0 ||
strcmp(rec->file, "ig_strdup_vprintf") == 0 ||
strcmp(rec->file, "ig_strconcat") == 0 ||
strcmp(rec->file, "ig_string_free (free = FALSE)") == 0))
data = rec->p + BUFFER_CHECK_SIZE;
else
data = rec->comment;
fprintf(stderr, "%s:%d %d bytes (%s)\n", rec->file, rec->line, rec->size, data);
}
void ig_mem_profile(void)
{
g_hash_table_foreach(data, (GHFunc) ig_profile_line, NULL);
g_hash_table_destroy(data);
g_hash_table_destroy(preallocs);
}
static MEM_REC *largest[10];
void ig_profile_largest(void *key, MEM_REC *rec)
{
int n;
for (n = 0; n < 10; n++)
{
if (largest[n] == NULL || rec->size > largest[n]->size)
{
g_memmove(largest+n+1, largest+n, sizeof(void *)*(9-n));
largest[n] = rec;
}
}
}
void ig_mem_profile_largest(void)
{
/*int n;*/
memset(&largest, 0, sizeof(MEM_REC*)*10);
/*g_hash_table_foreach(data, (GHFunc) ig_profile_largest, NULL);
for (n = 0; n < 10 && largest[n] != NULL; n++)
{
ig_profile_line(NULL, largest[n]);
}*/
}
void ig_set_data(const char *data)
{
comment = data;
}

31
src/core/memdebug.h Normal file
View File

@ -0,0 +1,31 @@
#ifdef MEM_DEBUG
void ig_mem_profile(void);
void ig_set_data(const char *data);
void *ig_malloc(int size, const char *file, int line);
void *ig_malloc0(int size, const char *file, int line);
void *ig_realloc(void *mem, unsigned long size, const char *file, int line);
char *ig_strdup(const char *str, const char *file, int line);
char *ig_strndup(const char *str, int count, const char *file, int line);
char *ig_strconcat(const char *file, int line, const char *str, ...);
char *ig_strdup_printf(const char *file, int line, const char *format, ...) G_GNUC_PRINTF (3, 4);
char *ig_strdup_vprintf(const char *file, int line, const char *format, va_list args);
void ig_free(void *p);
GString *ig_string_new(const char *file, int line, const char *str);
void ig_string_free(const char *file, int line, GString *str, int freeit);
char *ig_strjoinv(const char *file, int line, const char *sepa, char **array);
#define g_malloc(a) ig_malloc(a, __FILE__, __LINE__)
#define g_malloc0(a) ig_malloc0(a, __FILE__, __LINE__)
#define g_realloc(a,b) ig_realloc(a, b, __FILE__, __LINE__)
#define g_strdup(a) ig_strdup(a, __FILE__, __LINE__)
#define g_strndup(a, b) ig_strndup(a, b, __FILE__, __LINE__)
#define g_strconcat(a...) ig_strconcat(__FILE__, __LINE__, ##a)
#define g_strdup_printf(a, b...) ig_strdup_printf(__FILE__, __LINE__, a, ##b)
#define g_strdup_vprintf(a, b...) ig_strdup_vprintf(__FILE__, __LINE__, a, ##b)
#define g_free ig_free
#define g_string_new(a) ig_string_new(__FILE__, __LINE__, a)
#define g_string_free(a, b) ig_string_free(__FILE__, __LINE__, a, b)
#define g_strjoinv(a,b) ig_strjoinv(__FILE__, __LINE__, a, b)
#endif

467
src/core/misc.c Normal file
View File

@ -0,0 +1,467 @@
/*
misc.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "misc.h"
#include "pidwait.h"
#include <errno.h>
#include <regex.h>
typedef struct {
GInputCondition condition;
GInputFunction function;
gpointer data;
} IRSSI_INPUT_REC;
static gboolean irssi_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
{
IRSSI_INPUT_REC *rec = data;
GInputCondition icond = 0;
if (condition & (G_IO_IN | G_IO_PRI))
icond |= G_INPUT_READ;
if (condition & G_IO_OUT)
icond |= G_INPUT_WRITE;
if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
icond |= G_INPUT_EXCEPTION;
if (rec->condition & icond)
rec->function(rec->data, g_io_channel_unix_get_fd(source), icond);
return TRUE;
}
int g_input_add(int source, GInputCondition condition,
GInputFunction function, gpointer data)
{
IRSSI_INPUT_REC *rec;
unsigned int result;
GIOChannel *channel;
GIOCondition cond = 0;
rec = g_new(IRSSI_INPUT_REC, 1);
rec->condition = condition;
rec->function = function;
rec->data = data;
if (condition & G_INPUT_READ)
cond |= (G_IO_IN | G_IO_PRI);
if (condition & G_INPUT_WRITE)
cond |= G_IO_OUT;
if (condition & G_INPUT_EXCEPTION)
cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
channel = g_io_channel_unix_new (source);
result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
irssi_io_invoke, rec, g_free);
g_io_channel_unref(channel);
return result;
}
long get_timeval_diff(const GTimeVal *tv1, const GTimeVal *tv2)
{
long secs, usecs;
secs = tv1->tv_sec - tv2->tv_sec;
usecs = tv1->tv_usec - tv2->tv_usec;
if (usecs < 0) {
usecs += 1000000;
secs--;
}
usecs = usecs/1000 + secs * 1000;
return usecs;
}
int find_substr(const char *list, const char *item)
{
const char *ptr;
g_return_val_if_fail(list != NULL, FALSE);
g_return_val_if_fail(item != NULL, FALSE);
if (*item == '\0')
return FALSE;
for (;;) {
while (isspace((gint) *list)) list++;
if (*list == '\0') break;
ptr = strchr(list, ' ');
if (ptr == NULL) ptr = list+strlen(list);
if (g_strncasecmp(list, item, ptr-list) == 0 && item[ptr-list] == '\0')
return TRUE;
list = ptr;
}
return FALSE;
}
int strarray_length(char **array)
{
int len;
g_return_val_if_fail(array != NULL, 0);
len = 0;
while (*array) {
len++;
array++;
}
return len;
}
int strarray_find(char **array, const char *item)
{
char **tmp;
int index;
g_return_val_if_fail(array != NULL, 0);
g_return_val_if_fail(item != NULL, 0);
index = 0;
for (tmp = array; *tmp != NULL; tmp++, index++) {
if (g_strcasecmp(*tmp, item) == 0)
return index;
}
return -1;
}
int copyfile(const char *src, const char *dest)
{
FILE *fs, *fd;
int ret;
g_return_val_if_fail(src != NULL, FALSE);
g_return_val_if_fail(dest != NULL, FALSE);
fs = fopen(src, "rb");
if (fs == NULL) return FALSE;
ret = FALSE;
remove(dest); /* just to be sure there's no link already in dest */
fd = fopen(dest, "w+");
if (fd != NULL) {
int len;
char buf[1024];
while ((len = fread(buf, 1, sizeof(buf), fs)) > 0)
if (fwrite(buf, 1, len, fd) != len) break;
fclose(fd);
ret = TRUE;
}
fclose(fs);
return ret;
}
int execute(const char *cmd)
{
char **args;
char *prev, *dupcmd;
int pid, max, cnt;
g_return_val_if_fail(cmd != NULL, -1);
pid = fork();
if (pid == -1) return FALSE;
if (pid != 0) {
pidwait_add(pid);
return pid;
}
dupcmd = g_strdup(cmd);
max = 5; cnt = 0;
args = g_malloc(sizeof(char *)*max);
for (prev = dupcmd; ; dupcmd++) {
if (*dupcmd == '\0' || *dupcmd == ' ') {
args[cnt++] = prev;
if (cnt == max) {
max += 5;
args = g_realloc(args, sizeof(char *)*max);
}
if (*dupcmd == '\0') break;
*dupcmd++ = '\0';
prev = dupcmd;
}
}
args[cnt] = NULL;
execvp(args[0], args);
g_free(dupcmd);
_exit(99);
return -1;
}
GSList *gslist_find_string(GSList *list, const char *key)
{
for (list = list; list != NULL; list = list->next)
if (strcmp(list->data, key) == 0) return list;
return NULL;
}
GSList *gslist_find_icase_string(GSList *list, const char *key)
{
for (list = list; list != NULL; list = list->next)
if (g_strcasecmp(list->data, key) == 0) return list;
return NULL;
}
void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, void *data)
{
void *ret;
while (list != NULL) {
ret = func(list->data, data);
if (ret != NULL) return ret;
list = list->next;
}
return NULL;
}
char *gslist_to_string(GSList *list, int offset, const char *delimiter)
{
GString *str;
char **data, *ret;
str = g_string_new(NULL);
while (list != NULL) {
data = G_STRUCT_MEMBER_P(list->data, offset);
if (str->len != 0) g_string_append(str, delimiter);
g_string_append(str, *data);
list = list->next;
}
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
GList *glist_find_string(GList *list, const char *key)
{
for (list = list; list != NULL; list = list->next)
if (strcmp(list->data, key) == 0) return list;
return NULL;
}
GList *glist_find_icase_string(GList *list, const char *key)
{
for (list = list; list != NULL; list = list->next)
if (g_strcasecmp(list->data, key) == 0) return list;
return NULL;
}
char *stristr(const char *data, const char *key)
{
const char *pos, *max;
int keylen, datalen;
keylen = strlen(key);
datalen = strlen(data);
if (keylen > datalen)
return NULL;
max = data+datalen-keylen;
for (pos = data; pos <= max; pos++)
if (g_strncasecmp(pos, key, keylen) == 0) return (char *) pos;
return NULL;
}
#define isbound(c) \
((unsigned char) (c) < 128 && \
(isspace((int) (c)) || ispunct((int) (c))))
char *stristr_full(const char *data, const char *key)
{
const char *pos, *max;
int keylen, datalen;
keylen = strlen(key);
datalen = strlen(data);
if (keylen > datalen)
return NULL;
max = data+datalen-keylen;
for (pos = data; pos <= max; pos++) {
if (pos > data && !isbound(pos[-1])) continue;
if (g_strncasecmp(pos, key, keylen) == 0 &&
(pos[keylen] == '\0' || isbound(pos[keylen])))
return (char *) pos;
}
return NULL;
}
int regexp_match(const char *str, const char *regexp)
{
regex_t preg;
int ret;
if (regcomp(&preg, regexp, REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
return 0;
ret = regexec(&preg, str, 0, NULL, 0);
regfree(&preg);
return ret == 0;
}
char *convert_home(const char *path)
{
return *path == '~' && (*(path+1) == '/' || *(path+1) == '\0') ?
g_strconcat(g_get_home_dir(), path+1, NULL) :
g_strdup(path);
}
int g_istr_equal(gconstpointer v, gconstpointer v2)
{
return g_strcasecmp((const char *) v, (const char *) v2) == 0;
}
/* a char* hash function from ASU */
unsigned int g_istr_hash(gconstpointer v)
{
const char *s = (char *) v;
unsigned int h = 0, g;
while (*s != '\0') {
h = (h << 4) + toupper(*s);
if ((g = h & 0xf0000000)) {
h = h ^ (g >> 24);
h = h ^ g;
}
s++;
}
return h /* % M */;
}
/* Find `mask' from `data', you can use * and ? wildcards. */
int match_wildcards(const char *cmask, const char *data)
{
char *mask, *newmask, *p1, *p2;
int ret;
newmask = mask = strdup(cmask);
for (; *mask != '\0' && *data != '\0'; mask++) {
if (*mask == '?' || toupper(*mask) == toupper(*data)) {
data++;
continue;
}
if (*mask != '*')
break;
while (*mask == '?' || *mask == '*') mask++;
if (*mask == '\0') {
data += strlen(data);
break;
}
p1 = strchr(mask, '*');
p2 = strchr(mask, '?');
if (p1 == NULL || (p2 < p1 && p2 != NULL)) p1 = p2;
if (p1 != NULL) *p1 = '\0';
data = stristr(data, mask);
if (data == NULL) break;
data += strlen(mask);
mask += strlen(mask)-1;
if (p1 != NULL) *p1 = p1 == p2 ? '?' : '*';
}
ret = data != NULL && *data == '\0' && *mask == '\0';
free(newmask);
return ret;
}
/* Return TRUE if all characters in `str' are numbers.
Stop when `end_char' is found from string. */
int is_numeric(const char *str, char end_char)
{
g_return_val_if_fail(str != NULL, FALSE);
while (*str != '\0' && *str != end_char) {
if (!isdigit(*str)) return FALSE;
str++;
}
return TRUE;
}
/* replace all `from' chars in string to `to' chars. returns `str' */
char *replace_chars(char *str, char from, char to)
{
char *p;
for (p = str; *p != '\0'; p++) {
if (*p == from) *p = to;
}
return str;
}
int octal2dec(int octal)
{
int dec, n;
dec = 0; n = 1;
while (octal != 0) {
dec += n*(octal%10);
octal /= 10; n *= 8;
}
return dec;
}
int dec2octal(int decimal)
{
int octal, pos;
octal = 0; pos = 0;
while (decimal > 0) {
octal += (decimal & 7)*(pos == 0 ? 1 : pos);
decimal /= 8;
pos += 10;
}
return octal;
}

57
src/core/misc.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef __MISC_H
#define __MISC_H
/* `str' should be type char[MAX_INT_STRLEN] */
#define ltoa(str, num) \
g_snprintf(str, sizeof(str), "%d", num)
typedef void* (*FOREACH_FIND_FUNC) (void *item, void *data);
long get_timeval_diff(const GTimeVal *tv1, const GTimeVal *tv2);
/* find `item' from a space separated `list' */
int find_substr(const char *list, const char *item);
/* return how many items `array' has */
int strarray_length(char **array);
/* return index of `item' in `array' or -1 if not found */
int strarray_find(char **array, const char *item);
int copyfile(const char *src, const char *dest);
int execute(const char *cmd); /* returns pid or -1 = error */
GSList *gslist_find_string(GSList *list, const char *key);
GSList *gslist_find_icase_string(GSList *list, const char *key);
GList *glist_find_string(GList *list, const char *key);
GList *glist_find_icase_string(GList *list, const char *key);
void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, void *data);
char *gslist_to_string(GSList *list, int offset, const char *delimiter);
/* strstr() with case-ignoring */
char *stristr(const char *data, const char *key);
/* stristr(), but matches only for full words */
char *stristr_full(const char *data, const char *key);
/* easy way to check if regexp matches */
int regexp_match(const char *str, const char *regexp);
char *convert_home(const char *path);
/* Case-insensitive string hash functions */
int g_istr_equal(gconstpointer v, gconstpointer v2);
unsigned int g_istr_hash(gconstpointer v);
/* Find `mask' from `data', you can use * and ? wildcards. */
int match_wildcards(const char *mask, const char *data);
/* Return TRUE if all characters in `str' are numbers.
Stop when `end_char' is found from string. */
int is_numeric(const char *str, char end_char);
/* replace all `from' chars in string to `to' chars. returns `str' */
char *replace_chars(char *str, char from, char to);
/* octal <-> decimal conversions */
int octal2dec(int octal);
int dec2octal(int decimal);
#endif

3
src/core/module.h Normal file
View File

@ -0,0 +1,3 @@
#include "common.h"
#define MODULE_NAME "core"

185
src/core/modules.c Normal file
View File

@ -0,0 +1,185 @@
/*
modules.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "modules.h"
static GHashTable *uniqids, *uniqstrids;
static GHashTable *idlookup, *stridlookup;
static int next_uniq_id;
/* return unique number across all modules for `id' */
int module_get_uniq_id(const char *module, int id)
{
GHashTable *ids;
gpointer origkey, uniqid;
int ret;
g_return_val_if_fail(module != NULL, -1);
ids = g_hash_table_lookup(idlookup, module);
if (ids == NULL) {
/* new module */
ids = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
g_hash_table_insert(idlookup, g_strdup(module), ids);
}
if (!g_hash_table_lookup_extended(ids, GINT_TO_POINTER(id), &origkey, &uniqid)) {
/* not found */
ret = next_uniq_id++;
g_hash_table_insert(ids, GINT_TO_POINTER(id), GINT_TO_POINTER(ret));
g_hash_table_insert(uniqids, GINT_TO_POINTER(ret), GINT_TO_POINTER(id));
} else {
ret = GPOINTER_TO_INT(uniqid);
}
return ret;
}
/* return unique number across all modules for `id' */
int module_get_uniq_id_str(const char *module, const char *id)
{
GHashTable *ids;
gpointer origkey, uniqid;
int ret;
g_return_val_if_fail(module != NULL, -1);
ids = g_hash_table_lookup(stridlookup, module);
if (ids == NULL) {
/* new module */
ids = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
g_hash_table_insert(stridlookup, g_strdup(module), ids);
}
if (!g_hash_table_lookup_extended(ids, id, &origkey, &uniqid)) {
/* not found */
char *saveid;
saveid = g_strdup(id);
ret = next_uniq_id++;
g_hash_table_insert(ids, saveid, GINT_TO_POINTER(ret));
g_hash_table_insert(uniqstrids, GINT_TO_POINTER(ret), saveid);
} else {
ret = GPOINTER_TO_INT(uniqid);
}
return ret;
}
/* returns the original module specific id, -1 = not found */
int module_find_id(const char *module, int uniqid)
{
GHashTable *ids;
gpointer origkey, id;
int ret;
g_return_val_if_fail(module != NULL, -1);
ret = g_hash_table_lookup_extended(uniqids, GINT_TO_POINTER(uniqid), &origkey, &id) ?
GPOINTER_TO_INT(id) : -1;
if (ret != -1) {
/* check that module matches */
ids = g_hash_table_lookup(idlookup, module);
if (ids == NULL || !g_hash_table_lookup_extended(ids, GINT_TO_POINTER(ret), &origkey, &id))
ret = -1;
}
return ret;
}
/* returns the original module specific id, NULL = not found */
const char *module_find_id_str(const char *module, int uniqid)
{
GHashTable *ids;
gpointer origkey, id;
const char *ret;
g_return_val_if_fail(module != NULL, NULL);
ret = g_hash_table_lookup_extended(uniqstrids, GINT_TO_POINTER(uniqid),
&origkey, &id) ? id : NULL;
if (ret != NULL) {
/* check that module matches */
ids = g_hash_table_lookup(stridlookup, module);
if (ids == NULL || !g_hash_table_lookup_extended(ids, GINT_TO_POINTER(ret), &origkey, &id))
ret = NULL;
}
return ret;
}
static void gh_uniq_destroy(gpointer key, gpointer value)
{
g_hash_table_remove(uniqids, value);
}
static void gh_uniq_destroy_str(gpointer key, gpointer value)
{
g_hash_table_remove(uniqstrids, value);
g_free(key);
}
/* Destroy unique IDs from `module'. This function is automatically called
when module is destroyed with module's name as the parameter. */
void module_uniq_destroy(const char *module)
{
GHashTable *ids;
gpointer key;
if (g_hash_table_lookup_extended(idlookup, module, &key, (gpointer *) &ids)) {
g_hash_table_remove(idlookup, key);
g_free(key);
g_hash_table_foreach(ids, (GHFunc) gh_uniq_destroy, NULL);
g_hash_table_destroy(ids);
}
if (g_hash_table_lookup_extended(stridlookup, module, &key, (gpointer *) &ids)) {
g_hash_table_remove(stridlookup, key);
g_free(key);
g_hash_table_foreach(ids, (GHFunc) gh_uniq_destroy_str, NULL);
g_hash_table_destroy(ids);
}
}
void modules_init(void)
{
idlookup = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
uniqids = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
stridlookup = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
uniqstrids = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
next_uniq_id = 0;
}
void modules_deinit(void)
{
g_hash_table_foreach(idlookup, (GHFunc) module_uniq_destroy, NULL);
g_hash_table_destroy(idlookup);
g_hash_table_destroy(uniqids);
g_hash_table_foreach(stridlookup, (GHFunc) module_uniq_destroy, NULL);
g_hash_table_destroy(stridlookup);
g_hash_table_destroy(uniqstrids);
}

33
src/core/modules.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef __MODULES_H
#define __MODULES_H
#define MODULE_DATA_INIT(rec) \
(rec)->module_data = g_hash_table_new(g_str_hash, g_str_equal)
#define MODULE_DATA_DEINIT(rec) \
g_hash_table_destroy((rec)->module_data)
#define MODULE_DATA_SET(rec, data) \
g_hash_table_insert((rec)->module_data, MODULE_NAME, data)
#define MODULE_DATA(rec) \
g_hash_table_lookup((rec)->module_data, MODULE_NAME)
/* return unique number across all modules for `id' */
int module_get_uniq_id(const char *module, int id);
/* return unique number across all modules for `id'. */
int module_get_uniq_id_str(const char *module, const char *id);
/* returns the original module specific id, -1 = not found */
int module_find_id(const char *module, int uniqid);
/* returns the original module specific id, NULL = not found */
const char *module_find_id_str(const char *module, int uniqid);
/* Destroy unique IDs from `module'. This function is automatically called
when module is destroyed with module's name as the parameter. */
void module_uniq_destroy(const char *module);
void modules_init(void);
void modules_deinit(void);
#endif

155
src/core/net-disconnect.c Normal file
View File

@ -0,0 +1,155 @@
/*
net-disconnect.c :
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "network.h"
/* when quitting, wait for max. 5 seconds before forcing to close the socket */
#define MAX_QUIT_CLOSE_WAIT 5
/* wait for max. 2 minutes for other side to close the socket */
#define MAX_CLOSE_WAIT (60*2)
typedef struct {
time_t created;
int handle;
int tag;
} NET_DISCONNECT_REC;
static GSList *disconnects;
static int timeout_tag;
static void net_disconnect_remove(NET_DISCONNECT_REC *rec)
{
disconnects = g_slist_remove(disconnects, rec);
g_source_remove(rec->tag);
g_free(rec);
}
static void sig_disconnect(NET_DISCONNECT_REC *rec)
{
char buf[128];
int ret;
/* check if there's any data waiting in socket */
for (;;) {
ret = net_receive(rec->handle, buf, sizeof(buf));
if (ret <= 0)
break;
}
if (ret == -1) {
/* socket was closed */
net_disconnect_remove(rec);
}
}
static int sig_timeout_disconnect(void)
{
NET_DISCONNECT_REC *rec;
GSList *tmp, *next;
time_t now;
int ret;
/* check if we've waited enough for sockets to close themselves */
now = time(NULL);
for (tmp = disconnects; tmp != NULL; tmp = next) {
rec = tmp->data;
next = tmp->next;
if (rec->created+MAX_CLOSE_WAIT <= now)
sig_disconnect(rec);
}
if (disconnects == NULL) {
/* no more sockets in disconnect queue, stop calling this
function */
timeout_tag = -1;
}
ret = disconnects != NULL ? 1 : 0;
return ret;
}
/* Try to let the other side close the connection, if it still isn't
disconnected after certain amount of time, close it ourself */
void net_disconnect_later(int handle)
{
NET_DISCONNECT_REC *rec;
rec = g_new(NET_DISCONNECT_REC, 1);
disconnects = g_slist_append(disconnects, rec);
rec->created = time(NULL);
rec->handle = handle;
rec->tag = g_input_add(handle, G_INPUT_READ, (GInputFunction) sig_disconnect, rec);
if (timeout_tag == -1)
timeout_tag = g_timeout_add(10000, (GSourceFunc) sig_timeout_disconnect, NULL);
}
void net_disconnect_init(void)
{
disconnects = NULL;
timeout_tag = -1;
}
void net_disconnect_deinit(void)
{
NET_DISCONNECT_REC *rec;
time_t now, max;
int first;
struct timeval tv;
fd_set set;
if (disconnects == NULL)
return;
/* give the sockets a chance to disconnect themselves.. */
max = time(NULL)+MAX_QUIT_CLOSE_WAIT;
first = 1;
while (disconnects != NULL) {
rec = disconnects->data;
now = time(NULL);
if (rec->created+MAX_QUIT_CLOSE_WAIT <= now || max <= now) {
/* this one has waited enough */
net_disconnect_remove(rec);
continue;
}
FD_ZERO(&set);
FD_SET(rec->handle, &set);
tv.tv_sec = first ? 0 : max-now;
tv.tv_usec = first ? 100000 : 0;
if (select(rec->handle+1, &set, NULL, NULL, &tv) > 0 && FD_ISSET(rec->handle, &set)) {
/* data coming .. check if we can close the handle */
sig_disconnect(rec);
} else if (first) {
/* Display the text when we have already waited for a while */
printf(_("Please wait, waiting for servers to close connections..\n"));
fflush(stdout);
first = 0;
}
}
}

View File

@ -0,0 +1,7 @@
#ifndef __NET_DISCONNECT_H
#define __NET_DISCONNECT_H
void net_disconnect_init(void);
void net_disconnect_deinit(void);
#endif

6
src/core/net-internal.h Normal file
View File

@ -0,0 +1,6 @@
#ifdef HAVE_SOCKS_H
#include <socks.h>
#endif
#include <netdb.h>
#include <arpa/inet.h>

210
src/core/net-nonblock.c Normal file
View File

@ -0,0 +1,210 @@
/*
net-nonblock.c : Nonblocking net_connect()
Copyright (C) 1998-2000 Timo Sirainen
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
*/
#include "module.h"
#include <signal.h>
#include "pidwait.h"
#include "net-nonblock.h"
typedef struct
{
NET_CALLBACK func;
void *data;
int pipes[2];
int port;
IPADDR *my_ip;
int tag;
}
SIMPLE_THREAD_REC;
/* nonblocking gethostbyname(), ip (IPADDR) + error (int, 0 = not error) is
written to pipe when found PID of the resolver child is returned */
int net_gethostname_nonblock(const char *addr, int pipe)
{
RESOLVED_IP_REC rec;
const char *errorstr;
int pid;
g_return_val_if_fail(addr != NULL, FALSE);
pid = fork();
if (pid > 0) {
/* parent */
pidwait_add(pid);
return pid;
}
if (pid != 0) {
/* failed! */
g_warning("net_connect_thread(): fork() failed! Using blocking resolving");
}
/* child */
rec.error = net_gethostname(addr, &rec.ip);
if (rec.error == 0) {
errorstr = NULL;
} else {
errorstr = net_gethosterror(rec.error);
rec.errlen = strlen(errorstr)+1;
}
write(pipe, &rec, sizeof(rec));
if (rec.error != 0)
write(pipe, errorstr, rec.errlen);
if (pid == 0)
_exit(99);
/* we used blocking lookup */
return 0;
}
/* get the resolved IP address */
int net_gethostbyname_return(int pipe, RESOLVED_IP_REC *rec)
{
time_t maxwait;
int len, ret;
rec->error = -1;
rec->errorstr = NULL;
/* get ip+error - try for max. 1-2 seconds */
fcntl(pipe, F_SETFL, O_NONBLOCK);
maxwait = time(NULL)+2;
len = 0;
do {
ret = read(pipe, (char *) rec+len, sizeof(*rec)-len);
if (ret == -1) return -1;
len += ret;
} while (len < sizeof(*rec) && time(NULL) < maxwait);
if (len < sizeof(*rec))
return -1; /* timeout */
if (rec->error) {
/* read error string */
rec->errorstr = g_malloc(rec->errlen);
len = 0;
do {
ret = read(pipe, rec->errorstr+len, rec->errlen-len);
if (ret == -1) break;
len += ret;
} while (len < rec->errlen && time(NULL) < maxwait);
if (len < rec->errlen) {
/* just ignore the rest of the error message.. */
rec->errorstr[len] = '\0';
}
}
return 0;
}
/* Kill the resolver child */
void net_disconnect_nonblock(int pid)
{
g_return_if_fail(pid > 0);
kill(pid, SIGKILL);
}
static void simple_init(SIMPLE_THREAD_REC *rec, int handle)
{
g_return_if_fail(rec != NULL);
g_source_remove(rec->tag);
if (net_geterror(handle) != 0) {
/* failed */
close(handle);
handle = -1;
}
rec->func(handle, rec->data);
g_free(rec);
}
static void simple_readpipe(SIMPLE_THREAD_REC *rec, int pipe)
{
RESOLVED_IP_REC iprec;
int handle;
g_return_if_fail(rec != NULL);
g_source_remove(rec->tag);
net_gethostbyname_return(pipe, &iprec);
g_free_not_null(iprec.errorstr);
close(rec->pipes[0]);
close(rec->pipes[1]);
handle = iprec.error == -1 ? -1 :
net_connect_ip(&iprec.ip, rec->port, rec->my_ip);
g_free_not_null(rec->my_ip);
if (handle == -1) {
/* failed */
rec->func(-1, rec->data);
g_free(rec);
return;
}
rec->tag = g_input_add(handle, G_INPUT_WRITE,
(GInputFunction) simple_init, rec);
}
/* Connect to server, call func when finished */
int net_connect_nonblock(const char *server, int port, const IPADDR *my_ip, NET_CALLBACK func, void *data)
{
SIMPLE_THREAD_REC *rec;
int fd[2];
g_return_val_if_fail(server != NULL, FALSE);
g_return_val_if_fail(func != NULL, FALSE);
if (pipe(fd) != 0) {
g_warning("net_connect_nonblock(): pipe() failed.");
return FALSE;
}
/* start nonblocking host name lookup */
net_gethostname_nonblock(server, fd[1]);
rec = g_new0(SIMPLE_THREAD_REC, 1);
rec->port = port;
if (my_ip != NULL) {
rec->my_ip = g_malloc(sizeof(IPADDR));
memcpy(rec->my_ip, my_ip, sizeof(IPADDR));
}
rec->func = func;
rec->data = data;
rec->pipes[0] = fd[0];
rec->pipes[1] = fd[1];
rec->tag = g_input_add(fd[0], G_INPUT_READ, (GInputFunction) simple_readpipe, rec);
return 1;
}

26
src/core/net-nonblock.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __NET_NONBLOCK_H
#define __NET_NONBLOCK_H
#include "network.h"
typedef struct {
IPADDR ip; /* resolved ip addres */
int error; /* error, 0 = no error, -1 = error: */
int errlen; /* error text length */
char *errorstr; /* error string - dynamically allocated, you'll
need to free() it yourself unless it's NULL */
} RESOLVED_IP_REC;
typedef void (*NET_CALLBACK) (int, void *);
/* nonblocking gethostbyname(), PID of the resolver child is returned. */
int net_gethostname_nonblock(const char *addr, int pipe);
/* get the resolved IP address. returns -1 if some error occured with read() */
int net_gethostbyname_return(int pipe, RESOLVED_IP_REC *rec);
/* Connect to server, call func when finished */
int net_connect_nonblock(const char *server, int port, const IPADDR *my_ip, NET_CALLBACK func, void *data);
/* Kill the resolver child */
void net_disconnect_nonblock(int pid);
#endif

451
src/core/network.c Normal file
View File

@ -0,0 +1,451 @@
/*
network.c : Network stuff
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "network.h"
#include "net-internal.h"
union sockaddr_union {
struct sockaddr sa;
struct sockaddr_in sin;
#ifdef HAVE_IPV6
struct sockaddr_in6 sin6;
#endif
};
/* Cygwin need this, don't know others.. */
/*#define BLOCKING_SOCKETS 1*/
int net_ip_compare(IPADDR *ip1, IPADDR *ip2)
{
if (ip1->family != ip2->family)
return 0;
#ifdef HAVE_IPV6
if (ip1->family == AF_INET6)
return memcmp(&ip1->addr, &ip2->addr, sizeof(ip1->addr)) == 0;
#endif
return memcmp(&ip1->addr, &ip2->addr, 4) == 0;
}
/* copy IP to sockaddr */
inline void sin_set_ip(union sockaddr_union *so, const IPADDR *ip)
{
so->sin.sin_family = ip->family;
#ifdef HAVE_IPV6
if (ip->family == AF_INET6)
memcpy(&so->sin6.sin6_addr, &ip->addr, sizeof(ip->addr.ip6));
else
#endif
memcpy(&so->sin.sin_addr, &ip->addr, 4);
}
inline void sin_get_ip(const union sockaddr_union *so, IPADDR *ip)
{
ip->family = so->sin.sin_family;
#ifdef HAVE_IPV6
if (ip->family == AF_INET6)
memcpy(&ip->addr, &so->sin6.sin6_addr, sizeof(ip->addr.ip6));
else
#endif
memcpy(&ip->addr, &so->sin.sin_addr, 4);
}
G_INLINE_FUNC void sin_set_port(union sockaddr_union *so, int port)
{
#ifdef HAVE_IPV6
if (so->sin.sin_family == AF_INET6)
so->sin6.sin6_port = htons(port);
else
#endif
so->sin.sin_port = htons(port);
}
G_INLINE_FUNC int sin_get_port(union sockaddr_union *so)
{
#ifdef HAVE_IPV6
if (so->sin.sin_family == AF_INET6)
return ntohs(so->sin6.sin6_port);
#endif
return ntohs(so->sin.sin_port);
}
/* Connect to socket */
int net_connect(const char *addr, int port, IPADDR *my_ip)
{
IPADDR ip;
g_return_val_if_fail(addr != NULL, -1);
if (net_gethostname(addr, &ip) == -1)
return -1;
return net_connect_ip(&ip, port, my_ip);
}
/* Connect to socket with ip address */
int net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip)
{
union sockaddr_union so;
int handle, ret, opt = 1;
/* create the socket */
memset(&so, 0, sizeof(so));
so.sin.sin_family = ip->family;
handle = socket(ip->family, SOCK_STREAM, 0);
if (handle == -1)
return -1;
/* set socket options */
fcntl(handle, F_SETFL, O_NONBLOCK);
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt));
setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt));
/* set our own address, ignore if bind() fails */
if (my_ip != NULL) {
sin_set_ip(&so, my_ip);
bind(handle, &so.sa, sizeof(so));
}
/* connect */
sin_set_ip(&so, ip);
sin_set_port(&so, port);
ret = connect(handle, &so.sa, sizeof(so));
if (ret < 0 && errno != EINPROGRESS) {
close(handle);
return -1;
}
return handle;
}
/* Disconnect socket */
void net_disconnect(int handle)
{
g_return_if_fail(handle != -1);
close(handle);
}
/* Listen for connections on a socket */
int net_listen(IPADDR *my_ip, int *port)
{
union sockaddr_union so;
int ret, handle, opt = 1;
socklen_t len = sizeof(so);
g_return_val_if_fail(my_ip != NULL, -1);
g_return_val_if_fail(port != NULL, -1);
/* create the socket */
memset(&so, 0, sizeof(so));
so.sin.sin_family = my_ip->family;
handle = socket(my_ip->family, SOCK_STREAM, 0);
if (handle == -1)
return -1;
/* set socket options */
fcntl(handle, F_SETFL, O_NONBLOCK);
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt));
setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt));
/* specify the address/port we want to listen in */
sin_set_port(&so, *port);
ret = bind(handle, &so.sa, sizeof(so));
if (ret < 0) {
close(handle);
return -1;
}
/* get the actual port we started listen */
ret = getsockname(handle, &so.sa, &len);
if (ret < 0) {
close(handle);
return -1;
}
*port = sin_get_port(&so);
/* start listening */
if (listen(handle, 1) < 0)
{
close(handle);
return -1;
}
return handle;
}
/* Accept a connection on a socket */
int net_accept(int handle, IPADDR *addr, int *port)
{
union sockaddr_union so;
int ret;
socklen_t addrlen;
g_return_val_if_fail(handle != -1, -1);
g_return_val_if_fail(addr != NULL, -1);
g_return_val_if_fail(port != NULL, -1);
addrlen = sizeof(so);
ret = accept(handle, &so.sa, &addrlen);
if (ret < 0)
return -1;
sin_get_ip(&so, addr);
*port = sin_get_port(&so);
fcntl(ret, F_SETFL, O_NONBLOCK);
return ret;
}
/* Read data from socket, return number of bytes read, -1 = error */
int net_receive(int handle, char *buf, int len)
{
#ifdef BLOCKING_SOCKETS
fd_set set;
struct timeval tv;
#endif
int ret;
g_return_val_if_fail(handle != -1, -1);
g_return_val_if_fail(buf != NULL, -1);
#ifdef BLOCKING_SOCKETS
FD_ZERO(&set);
FD_SET(handle, &set);
tv.tv_sec = 0;
tv.tv_usec = 0;
if (select(handle+1, &set, NULL, NULL, &tv) <= 0 ||
!FD_ISSET(handle, &set)) return 0;
#endif
ret = recv(handle, buf, len, 0);
if (ret == 0)
return -1; /* disconnected */
if (ret == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
return 0; /* no bytes received */
return ret;
}
/* Transmit data, return number of bytes sent, -1 = error */
int net_transmit(int handle, const char *data, int len)
{
int n;
g_return_val_if_fail(handle != -1, -1);
g_return_val_if_fail(data != NULL, -1);
n = send(handle, data, len, 0);
if (n == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
return 0;
return n > 0 ? n : -1;
}
/* Get socket address/port */
int net_getsockname(int handle, IPADDR *addr, int *port)
{
union sockaddr_union so;
#ifdef HAVE_IPV6
socklen_t len = sizeof(so.sin6);
#else
socklen_t len = sizeof(so.sin);
#endif
g_return_val_if_fail(handle != -1, -1);
g_return_val_if_fail(addr != NULL, -1);
#ifdef HAVE_IPV6
if (getsockname(handle, &so.sin6, &len) == -1)
#else
if (getsockname(handle, &so.sin, &len) == -1)
#endif
return -1;
sin_get_ip(&so, addr);
if (port) *port = sin_get_port(&so);
return 0;
}
/* Get IP address for host, returns 0 = ok,
others = error code for net_gethosterror() */
int net_gethostname(const char *addr, IPADDR *ip)
{
#ifdef HAVE_IPV6
union sockaddr_union *so;
struct addrinfo req, *ai;
char hbuf[NI_MAXHOST];
int host_error;
#else
struct hostent *hp;
#endif
g_return_val_if_fail(addr != NULL, -1);
/* host name */
#ifdef HAVE_IPV6
memset(ip, 0, sizeof(IPADDR));
memset(&req, 0, sizeof(struct addrinfo));
req.ai_socktype = SOCK_STREAM;
/* save error to host_error for later use */
host_error = getaddrinfo(addr, NULL, &req, &ai);
if (host_error != 0)
return host_error;
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
return 1;
so = (union sockaddr_union *) ai->ai_addr;
sin_get_ip(so, ip);
freeaddrinfo(ai);
#else
hp = gethostbyname(addr);
if (hp == NULL) return -1;
ip->family = AF_INET;
memcpy(&ip->addr, hp->h_addr, 4);
#endif
return 0;
}
int net_ip2host(IPADDR *ip, char *host)
{
#ifdef HAVE_IPV6
if (!inet_ntop(ip->family, &ip->addr, host, MAX_IP_LEN))
return -1;
#else
unsigned long ip4;
ip4 = ntohl(ip->addr.ip.s_addr);
sprintf(host, "%lu.%lu.%lu.%lu",
(ip4 & 0xff000000) >> 24,
(ip4 & 0x00ff0000) >> 16,
(ip4 & 0x0000ff00) >> 8,
(ip4 & 0x000000ff));
#endif
return 0;
}
int net_host2ip(const char *host, IPADDR *ip)
{
unsigned long addr;
#ifdef HAVE_IPV6
if (strchr(host, ':') != NULL) {
/* IPv6 */
ip->family = AF_INET6;
if (inet_pton(AF_INET6, host, &ip->addr) == 0)
return -1;
} else
#endif
{
/* IPv4 */
ip->family = AF_INET;
#ifdef HAVE_INET_ATON
if (inet_aton(host, &ip->addr.ip.s_addr) == 0)
return -1;
#else
addr = inet_addr(host);
if (addr == INADDR_NONE)
return -1;
memcpy(&ip->addr, &addr, 4);
#endif
}
return 0;
}
/* Get socket error */
int net_geterror(int handle)
{
int data;
socklen_t len = sizeof(data);
if (getsockopt(handle, SOL_SOCKET, SO_ERROR, &data, &len) == -1)
return -1;
return data;
}
/* get error of net_gethostname() */
const char *net_gethosterror(int error)
{
#ifdef HAVE_IPV6
g_return_val_if_fail(error != 0, NULL);
if (error == 1) {
/* getnameinfo() failed ..
FIXME: does strerror return the right error message?? */
return g_strerror(errno);
}
return gai_strerror(error);
#else
switch (h_errno) {
case HOST_NOT_FOUND:
return _("Host not found");
case NO_ADDRESS:
return _("No IP address found for name");
case NO_RECOVERY:
return _("A non-recovable name server error occurred");
case TRY_AGAIN:
return _("A temporary error on an authoritative name server");
}
/* unknown error */
return NULL;
#endif
}
int is_ipv4_address(const char *host)
{
while (*host != '\0') {
if (*host != '.' && !isdigit(*host))
return 0;
host++;
}
return 1;
}
int is_ipv6_address(const char *host)
{
while (*host != '\0') {
if (*host != ':' && !isxdigit(*host))
return 0;
host++;
}
return 1;
}

71
src/core/network.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef __NETWORK_H
#define __NETWORK_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
struct _ipaddr {
unsigned short family;
union {
#ifdef HAVE_IPV6
struct in6_addr ip6;
#else
struct in_addr ip;
#endif
} addr;
};
typedef struct _ipaddr IPADDR;
/* maxmimum string length of IP address */
#ifdef HAVE_IPV6
# define MAX_IP_LEN INET6_ADDRSTRLEN
#else
# define MAX_IP_LEN 20
#endif
#define is_ipv6_addr(ip) ((ip)->family != AF_INET)
/* returns 1 if IPADDRs are the same */
int net_ip_compare(IPADDR *ip1, IPADDR *ip2);
/* Connect to socket */
int net_connect(const char *addr, int port, IPADDR *my_ip);
/* Connect to socket with ip address */
int net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
/* Disconnect socket */
void net_disconnect(int handle);
/* Try to let the other side close the connection, if it still isn't
disconnected after certain amount of time, close it ourself */
void net_disconnect_later(int handle);
/* Listen for connections on a socket */
int net_listen(IPADDR *my_ip, int *port);
/* Accept a connection on a socket */
int net_accept(int handle, IPADDR *addr, int *port);
/* Read data from socket, return number of bytes read, -1 = error */
int net_receive(int handle, char *buf, int len);
/* Transmit data, return number of bytes sent, -1 = error */
int net_transmit(int handle, const char *data, int len);
/* Get IP address for host, returns 0 = ok,
others = error code for net_gethosterror() */
int net_gethostname(const char *addr, IPADDR *ip);
/* get error of net_gethostname() */
const char *net_gethosterror(int error);
/* Get socket address/port */
int net_getsockname(int handle, IPADDR *addr, int *port);
int net_ip2host(IPADDR *ip, char *host);
int net_host2ip(const char *host, IPADDR *ip);
/* Get socket error */
int net_geterror(int handle);
int is_ipv4_address(const char *host);
int is_ipv6_address(const char *host);
#endif

74
src/core/pidwait.c Normal file
View File

@ -0,0 +1,74 @@
/*
pidwait.c :
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "modules.h"
#include <sys/wait.h>
static GSList *pids;
static unsigned int childcheck_tag;
static int signal_pidwait;
/* add a pid to wait list */
void pidwait_add(int pid)
{
pids = g_slist_append(pids, GINT_TO_POINTER(pid));
}
/* remove pid from wait list */
void pidwait_remove(int pid)
{
pids = g_slist_remove(pids, GINT_TO_POINTER(pid));
}
static int child_check(void)
{
GSList *tmp, *next;
int status;
/* wait for each pid.. */
for (tmp = pids; tmp != NULL; tmp = next) {
next = tmp->next;
if (waitpid(GPOINTER_TO_INT(tmp->data), &status, WNOHANG) > 0) {
/* process terminated, remove from list */
pids = g_slist_remove(pids, tmp->data);
signal_emit_id(signal_pidwait, 1, GPOINTER_TO_INT(tmp->data));
}
}
return 1;
}
void pidwait_init(void)
{
pids = NULL;
childcheck_tag = g_timeout_add(1000, (GSourceFunc) child_check, NULL);
signal_pidwait = module_get_uniq_id_str("signals", "pidwait");
}
void pidwait_deinit(void)
{
g_slist_free(pids);
g_source_remove(childcheck_tag);
}

12
src/core/pidwait.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __PIDWAIT_H
#define __PIDWAIT_H
void pidwait_init(void);
void pidwait_deinit(void);
/* add a pid to wait list */
void pidwait_add(int pid);
/* remove pid from wait list */
void pidwait_remove(int pid);
#endif

167
src/core/rawlog.c Normal file
View File

@ -0,0 +1,167 @@
/*
rawlog.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "rawlog.h"
#include "modules.h"
#include "signals.h"
#include "misc.h"
#include "settings.h"
#include "common-setup.h"
static int rawlog_lines;
static int signal_rawlog;
RAWLOG_REC *rawlog_create(void)
{
RAWLOG_REC *rec;
rec = g_new0(RAWLOG_REC, 1);
return rec;
}
void rawlog_destroy(RAWLOG_REC *rawlog)
{
g_return_if_fail(rawlog != NULL);
g_slist_foreach(rawlog->lines, (GFunc) g_free, NULL);
g_slist_free(rawlog->lines);
if (rawlog->logging) close(rawlog->file);
g_free(rawlog);
}
/* NOTE! str must be dynamically allocated and must not be freed after! */
static void rawlog_add(RAWLOG_REC *rawlog, char *str)
{
if (rawlog->nlines < rawlog_lines || rawlog_lines <= 2)
rawlog->nlines++;
else {
g_free(rawlog->lines->data);
rawlog->lines = g_slist_remove(rawlog->lines, rawlog->lines->data);
}
if (rawlog->logging) {
write(rawlog->file, str, strlen(str));
write(rawlog->file, "\n", 1);
}
rawlog->lines = g_slist_append(rawlog->lines, str);
signal_emit_id(signal_rawlog, 2, rawlog, str);
}
void rawlog_input(RAWLOG_REC *rawlog, const char *str)
{
g_return_if_fail(rawlog != NULL);
g_return_if_fail(str != NULL);
rawlog_add(rawlog, g_strdup_printf(">> %s", str));
}
void rawlog_output(RAWLOG_REC *rawlog, const char *str)
{
g_return_if_fail(rawlog != NULL);
g_return_if_fail(str != NULL);
rawlog_add(rawlog, g_strdup_printf("<< %s", str));
}
void rawlog_redirect(RAWLOG_REC *rawlog, const char *str)
{
g_return_if_fail(rawlog != NULL);
g_return_if_fail(str != NULL);
rawlog_add(rawlog, g_strdup_printf("--> %s", str));
}
static void rawlog_dump(RAWLOG_REC *rawlog, int f)
{
GSList *tmp;
for (tmp = rawlog->lines; tmp != NULL; tmp = tmp->next) {
write(f, tmp->data, strlen((char *) tmp->data));
write(f, "\n", 1);
}
}
void rawlog_open(RAWLOG_REC *rawlog, const char *fname)
{
char *path;
g_return_if_fail(rawlog != NULL);
g_return_if_fail(fname != NULL);
if (rawlog->logging)
return;
path = convert_home(fname);
rawlog->file = open(path, O_WRONLY | O_APPEND | O_CREAT, LOG_FILE_CREATE_MODE);
g_free(path);
rawlog_dump(rawlog, rawlog->file);
rawlog->logging = rawlog->file != -1;
}
void rawlog_close(RAWLOG_REC *rawlog)
{
if (rawlog->logging) {
close(rawlog->file);
rawlog->logging = 0;
}
}
void rawlog_save(RAWLOG_REC *rawlog, const char *fname)
{
char *path;
int f;
path = convert_home(fname);
f = open(path, O_WRONLY | O_APPEND | O_CREAT, LOG_FILE_CREATE_MODE);
g_free(path);
rawlog_dump(rawlog, f);
close(f);
}
void rawlog_set_size(int lines)
{
rawlog_lines = lines;
}
static void read_settings(void)
{
rawlog_set_size(settings_get_int("rawlog_lines"));
}
void rawlog_init(void)
{
signal_rawlog = module_get_uniq_id_str("signals", "rawlog");
settings_add_int("history", "rawlog_lines", 200);
read_settings();
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
void rawlog_deinit(void)
{
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

28
src/core/rawlog.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __RAWLOG_H
#define __RAWLOG_H
typedef struct {
int logging;
int file;
int nlines;
GSList *lines;
} RAWLOG_REC;
RAWLOG_REC *rawlog_create(void);
void rawlog_destroy(RAWLOG_REC *rawlog);
void rawlog_input(RAWLOG_REC *rawlog, const char *str);
void rawlog_output(RAWLOG_REC *rawlog, const char *str);
void rawlog_redirect(RAWLOG_REC *rawlog, const char *str);
void rawlog_set_size(int lines);
void rawlog_open(RAWLOG_REC *rawlog, const char *fname);
void rawlog_close(RAWLOG_REC *rawlog);
void rawlog_save(RAWLOG_REC *rawlog, const char *fname);
void rawlog_init(void);
void rawlog_deinit(void);
#endif

323
src/core/server-redirect.c Normal file
View File

@ -0,0 +1,323 @@
/*
server-redirect.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "misc.h"
#include "server.h"
#include "server-redirect.h"
static int redirect_group;
static void server_eventtable_destroy(char *key, GSList *value)
{
GSList *tmp;
g_free(key);
for (tmp = value; tmp != NULL; tmp = tmp->next) {
REDIRECT_REC *rec = tmp->data;
g_free_not_null(rec->arg);
g_free(rec->name);
g_free(rec);
}
g_slist_free(value);
}
static void server_eventgrouptable_destroy(gpointer key, GSList *value)
{
g_slist_foreach(value, (GFunc) g_free, NULL);
g_slist_free(value);
}
static void server_cmdtable_destroy(char *key, REDIRECT_CMD_REC *value)
{
g_free(key);
g_slist_foreach(value->events, (GFunc) g_free, NULL);
g_slist_free(value->events);
g_free(value);
}
static void sig_disconnected(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
if (server->eventtable != NULL) {
g_hash_table_foreach(server->eventtable, (GHFunc) server_eventtable_destroy, NULL);
g_hash_table_destroy(server->eventtable);
}
g_hash_table_foreach(server->eventgrouptable, (GHFunc) server_eventgrouptable_destroy, NULL);
g_hash_table_destroy(server->eventgrouptable);
if (server->cmdtable != NULL) {
g_hash_table_foreach(server->cmdtable, (GHFunc) server_cmdtable_destroy, NULL);
g_hash_table_destroy(server->cmdtable);
}
}
void server_redirect_initv(SERVER_REC *server, const char *command, int last, GSList *list)
{
REDIRECT_CMD_REC *rec;
g_return_if_fail(server != NULL);
g_return_if_fail(command != NULL);
g_return_if_fail(last > 0);
if (g_hash_table_lookup(server->cmdtable, command) != NULL) {
/* already in hash table. list of events SHOULD be the same... */
g_slist_foreach(list, (GFunc) g_free, NULL);
g_slist_free(list);
return;
}
rec = g_new(REDIRECT_CMD_REC, 1);
rec->last = last;
rec->events = list;
g_hash_table_insert(server->cmdtable, g_strdup(command), rec);
}
void server_redirect_init(SERVER_REC *server, const char *command, int last, ...)
{
va_list args;
GSList *list;
char *event;
va_start(args, last);
list = NULL;
while ((event = va_arg(args, gchar *)) != NULL)
list = g_slist_append(list, g_strdup(event));
va_end(args);
server_redirect_initv(server, command, last, list);
}
int server_redirect_single_event(SERVER_REC *server, const char *arg, int last, int group,
const char *event, const char *signal, int argpos)
{
REDIRECT_REC *rec;
GSList *list, *grouplist;
char *origkey;
g_return_val_if_fail(server != NULL, 0);
g_return_val_if_fail(event != NULL, 0);
g_return_val_if_fail(signal != NULL, 0);
g_return_val_if_fail(arg != NULL || argpos == -1, 0);
if (group == 0) group = ++redirect_group;
rec = g_new0(REDIRECT_REC, 1);
rec->arg = arg == NULL ? NULL : g_strdup(arg);
rec->argpos = argpos;
rec->name = g_strdup(signal);
rec->group = group;
rec->last = last;
if (g_hash_table_lookup_extended(server->eventtable, event, (gpointer *) &origkey, (gpointer *) &list))
g_hash_table_remove(server->eventtable, origkey);
else {
list = NULL;
origkey = g_strdup(event);
}
grouplist = g_hash_table_lookup(server->eventgrouptable, GINT_TO_POINTER(group));
if (grouplist != NULL) g_hash_table_remove(server->eventgrouptable, GINT_TO_POINTER(group));
list = g_slist_append(list, rec);
grouplist = g_slist_append(grouplist, g_strdup(event));
g_hash_table_insert(server->eventtable, origkey, list);
g_hash_table_insert(server->eventgrouptable, GINT_TO_POINTER(group), grouplist);
return group;
}
void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...)
{
va_list args;
char *event, *signal;
int argpos, group;
g_return_if_fail(server != NULL);
va_start(args, last);
group = 0;
while ((event = va_arg(args, gchar *)) != NULL) {
signal = va_arg(args, gchar *);
argpos = va_arg(args, gint);
group = server_redirect_single_event(server, arg, last > 0, group, event, signal, argpos);
last--;
}
va_end(args);
}
void server_redirect_default(SERVER_REC *server, const char *command)
{
REDIRECT_CMD_REC *cmdrec;
REDIRECT_REC *rec;
GSList *events, *list, *grouplist;
char *event, *origkey;
int last;
g_return_if_fail(server != NULL);
g_return_if_fail(command != NULL);
if (server->cmdtable == NULL)
return; /* not connected yet */
cmdrec = g_hash_table_lookup(server->cmdtable, command);
if (cmdrec == NULL) return;
/* add all events used by command to eventtable and eventgrouptable */
redirect_group++; grouplist = NULL; last = cmdrec->last;
for (events = cmdrec->events; events != NULL; events = events->next, last--) {
event = events->data;
if (g_hash_table_lookup_extended(server->eventtable, event, (gpointer *) &origkey, (gpointer *) &list))
g_hash_table_remove(server->eventtable, origkey);
else {
list = NULL;
origkey = g_strdup(event);
}
rec = g_new0(REDIRECT_REC, 1);
rec->argpos = -1;
rec->name = g_strdup(event);
rec->group = redirect_group;
rec->last = last > 0;
grouplist = g_slist_append(grouplist, g_strdup(event));
list = g_slist_append(list, rec);
g_hash_table_insert(server->eventtable, origkey, list);
}
g_hash_table_insert(server->eventgrouptable, GINT_TO_POINTER(redirect_group), grouplist);
}
void server_redirect_remove_next(SERVER_REC *server, const char *event, GSList *item)
{
REDIRECT_REC *rec;
GSList *grouplist, *list, *events, *tmp;
char *origkey;
int group;
g_return_if_fail(server != NULL);
g_return_if_fail(event != NULL);
if (!g_hash_table_lookup_extended(server->eventtable, event, (gpointer *) &origkey, (gpointer *) &list))
return;
rec = item == NULL ? list->data : item->data;
if (!rec->last) {
/* this wasn't last expected event */
return;
}
group = rec->group;
/* get list of events from this group */
grouplist = g_hash_table_lookup(server->eventgrouptable, GINT_TO_POINTER(group));
/* remove all of them */
for (list = grouplist; list != NULL; list = list->next) {
char *event = list->data;
if (!g_hash_table_lookup_extended(server->eventtable, event, (gpointer *) &origkey, (gpointer *) &events)) {
g_warning("server_redirect_remove_next() : event in eventgrouptable but not in eventtable");
continue;
}
/* remove the right group */
for (tmp = events; tmp != NULL; tmp = tmp->next) {
rec = tmp->data;
if (rec->group == group)
break;
}
if (rec == NULL) {
g_warning("server_redirect_remove_next() : event in eventgrouptable but not in eventtable (group)");
continue;
}
g_free(event);
events = g_slist_remove(events, rec);
g_free_not_null(rec->arg);
g_free(rec->name);
g_free(rec);
/* update hash table */
g_hash_table_remove(server->eventtable, origkey);
if (events == NULL)
g_free(origkey);
else
g_hash_table_insert(server->eventtable, origkey, events);
}
g_hash_table_remove(server->eventgrouptable, GINT_TO_POINTER(group));
g_slist_free(grouplist);
}
GSList *server_redirect_getqueue(SERVER_REC *server, const char *event, const char *args)
{
REDIRECT_REC *rec;
GSList *list;
char **arglist;
int found;
list = g_hash_table_lookup(server->eventtable, event);
for (; list != NULL; list = list->next) {
rec = list->data;
if (rec->argpos == -1)
break;
if (rec->arg == NULL)
continue;
/* we need to check that the argument is right.. */
arglist = g_strsplit(args, " ", -1);
found = (strarray_length(arglist) > rec->argpos &&
find_substr(rec->arg, arglist[rec->argpos]));
g_strfreev(arglist);
if (found) break;
}
return list;
}
void servers_redirect_init(void)
{
redirect_group = 0;
signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}
void servers_redirect_deinit(void)
{
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
}

View File

@ -0,0 +1,38 @@
#ifndef __SERVER_REDIRECT_H
#define __SERVER_REDIRECT_H
#include "server.h"
typedef struct {
int last; /* number of "last" events at the start of the events list */
GSList *events; /* char* list of events */
} REDIRECT_CMD_REC;
typedef struct {
char *name; /* event name */
char *arg; /* argument for event we are expecting or NULL */
int argpos; /* argument position */
int group; /* group of events this belongs to */
int last; /* if this event is received, remove all the events in this group */
}
REDIRECT_REC;
void server_redirect_init(SERVER_REC *server, const char *command, int last, ...);
void server_redirect_initv(SERVER_REC *server, const char *command, int last, GSList *list);
/* ... = char *event1, char *event2, ..., NULL */
void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...);
/* ... = char *event, char *callback_signal, int argpos, ..., NULL */
int server_redirect_single_event(SERVER_REC *server, const char *arg, int last, int group,
const char *event, const char *signal, int argpos);
void server_redirect_default(SERVER_REC *server, const char *command);
void server_redirect_remove_next(SERVER_REC *server, const char *event, GSList *item);
GSList *server_redirect_getqueue(SERVER_REC *server, const char *event, const char *args);
void servers_redirect_init(void);
void servers_redirect_deinit(void);
#endif

273
src/core/server.c Normal file
View File

@ -0,0 +1,273 @@
/*
server.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "modules.h"
#include "signals.h"
#include "line-split.h"
#include "net-nonblock.h"
#include "rawlog.h"
#include "misc.h"
#include "server.h"
#include "server-redirect.h"
#include "settings.h"
GSList *servers, *lookup_servers;
/* connection to server failed */
static void server_cant_connect(SERVER_REC *server, const char *msg)
{
g_return_if_fail(server != NULL);
lookup_servers = g_slist_remove(lookup_servers, server);
signal_emit("server connect failed", 2, server, msg);
if (server->connect_tag != -1)
g_source_remove(server->connect_tag);
if (server->connect_pipe[0] != -1) {
close(server->connect_pipe[0]);
close(server->connect_pipe[1]);
}
MODULE_DATA_DEINIT(server);
g_free(server->tag);
g_free(server->nick);
g_free(server);
}
/* generate tag from server's address */
static char *server_create_address_tag(const char *address)
{
const char *start, *end;
/* try to generate a reasonable server tag */
if (g_strncasecmp(address, "irc", 3) == 0 ||
g_strncasecmp(address, "chat", 4) == 0) {
/* irc-2.cs.hut.fi -> hut, chat.bt.net -> bt */
end = strrchr(address, '.');
start = end-1;
while (start > address && *start != '.') start--;
} else {
/* efnet.cs.hut.fi -> efnet */
end = strchr(address, '.');
start = end;
}
if (start == end) start = address; else start++;
if (end == NULL) end = address + strlen(address);
return g_strndup(start, (int) (end-start));
}
/* create unique tag for server. prefer ircnet's name or
generate it from server's address */
static char *server_create_tag(SERVER_CONNECT_REC *conn)
{
GString *str;
char *tag;
int num;
tag = conn->ircnet != NULL ? g_strdup(conn->ircnet) :
server_create_address_tag(conn->address);
/* then just append numbers after tag until unused is found.. */
str = g_string_new(tag);
for (num = 2; server_find_tag(str->str) != NULL; num++)
g_string_sprintf(str, "%s%d", tag, num);
g_free(tag);
tag = str->str;
g_string_free(str, FALSE);
return tag;
}
static void server_connect_callback_init(SERVER_REC *server, int handle)
{
int error;
error = net_geterror(handle);
if (error != 0) {
server->connection_lost = TRUE;
server_cant_connect(server, g_strerror(error));
return;
}
lookup_servers = g_slist_remove(lookup_servers, server);
g_source_remove(server->connect_tag);
server->connect_tag = -1;
server->connect_time = time(NULL);
server->rawlog = rawlog_create();
servers = g_slist_append(servers, server);
signal_emit("server connected", 1, server);
}
static void server_connect_callback_readpipe(SERVER_REC *server, int handle)
{
SERVER_CONNECT_REC *conn;
RESOLVED_IP_REC iprec;
g_source_remove(server->connect_tag);
server->connect_tag = -1;
net_gethostbyname_return(handle, &iprec);
close(server->connect_pipe[0]);
close(server->connect_pipe[1]);
server->connect_pipe[0] = -1;
server->connect_pipe[1] = -1;
conn = server->connrec;
server->handle = iprec.error == -1 ? -1 :
net_connect_ip(&iprec.ip, conn->proxy != NULL ?
conn->proxy_port : conn->port,
conn->own_ip != NULL ? conn->own_ip : NULL);
if (server->handle == -1) {
/* failed */
server->connection_lost = TRUE;
server_cant_connect(server,
iprec.error != -1 ? g_strerror(errno) : /* connect() failed */
(iprec.errorstr != NULL ? iprec.errorstr : "Host lookup failed")); /* gethostbyname() failed */
g_free_not_null(iprec.errorstr);
return;
}
server->connect_tag = g_input_add(server->handle, G_INPUT_WRITE|G_INPUT_READ,
(GInputFunction) server_connect_callback_init, server);
signal_emit("server connecting", 2, server, &iprec.ip);
}
int server_connect(SERVER_REC *server)
{
g_return_val_if_fail(server != NULL, FALSE);
MODULE_DATA_INIT(server);
if (pipe(server->connect_pipe) != 0) {
g_warning("server_connect(): pipe() failed.");
return FALSE;
}
server->tag = server_create_tag(server->connrec);
server->handle = -1;
server->connect_pid =
net_gethostname_nonblock(server->connrec->proxy != NULL ?
server->connrec->proxy : server->connrec->address,
server->connect_pipe[1]);
server->connect_tag =
g_input_add(server->connect_pipe[0], G_INPUT_READ,
(GInputFunction) server_connect_callback_readpipe, server);
lookup_servers = g_slist_append(lookup_servers, server);
signal_emit("server looking", 1, server);
return TRUE;
}
void server_disconnect(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
if (server->connect_tag != -1) {
/* still connecting to server.. */
if (server->connect_pid != -1)
net_disconnect_nonblock(server->connect_pid);
server_cant_connect(server, NULL);
return;
}
servers = g_slist_remove(servers, server);
signal_emit("server disconnected", 1, server);
if (server->handle != -1)
net_disconnect(server->handle);
MODULE_DATA_DEINIT(server);
rawlog_destroy(server->rawlog);
line_split_free(server->buffer);
g_free(server->tag);
g_free(server->nick);
g_free(server);
}
SERVER_REC *server_find_tag(const char *tag)
{
GSList *tmp;
g_return_val_if_fail(tag != NULL, NULL);
if (*tag == '\0') return NULL;
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
SERVER_REC *server = tmp->data;
if (strcmp(server->tag, tag) == 0)
return server;
}
for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) {
SERVER_REC *server = tmp->data;
if (strcmp(server->tag, tag) == 0)
return server;
}
return NULL;
}
SERVER_REC *server_find_ircnet(const char *ircnet)
{
GSList *tmp;
g_return_val_if_fail(ircnet != NULL, NULL);
if (*ircnet == '\0') return NULL;
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
SERVER_REC *server = tmp->data;
if (server->connrec->ircnet != NULL &&
strcmp(server->connrec->ircnet, ircnet) == 0) return server;
}
return NULL;
}
void servers_init(void)
{
lookup_servers = servers = NULL;
servers_redirect_init();
}
void servers_deinit(void)
{
while (servers != NULL)
server_disconnect(servers->data);
while (lookup_servers != NULL)
server_cant_connect(lookup_servers->data, NULL);
servers_redirect_deinit();
}

66
src/core/server.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef __SERVER_H
#define __SERVER_H
#ifndef __NETWORK_H
typedef struct _ipaddr IPADDR;
#endif
/* all strings should be either NULL or dynamically allocated */
/* address and nick are mandatory, rest are optional */
typedef struct {
/* if we're connecting via proxy, or just NULLs */
char *proxy;
int proxy_port;
char *proxy_string;
char *address;
int port;
char *ircnet;
IPADDR *own_ip;
} SERVER_CONNECT_REC;
typedef struct {
int type; /* server type */
SERVER_CONNECT_REC *connrec;
time_t connect_time; /* connection time */
char *tag; /* tag name for addressing server */
char *nick; /* current nick */
int connected:1; /* connected to server */
int connection_lost:1; /* Connection lost unintentionally */
int handle; /* socket handle */
int readtag; /* input tag */
/* for net_connect_nonblock() */
int connect_pipe[2];
int connect_tag;
int connect_pid;
/* For deciding if event should be handled internally */
GHashTable *eventtable; /* "event xxx" : GSList* of REDIRECT_RECs */
GHashTable *eventgrouptable; /* event group : GSList* of REDIRECT_RECs */
GHashTable *cmdtable; /* "command xxx" : REDIRECT_CMD_REC* */
void *rawlog;
void *buffer; /* receive buffer */
GHashTable *module_data;
} SERVER_REC;
extern GSList *servers, *lookup_servers;
/* Connect to server */
int server_connect(SERVER_REC *server);
/* Disconnect from server */
void server_disconnect(SERVER_REC *server);
SERVER_REC *server_find_tag(const char *tag);
SERVER_REC *server_find_ircnet(const char *ircnet);
void servers_init(void);
void servers_deinit(void);
#endif

336
src/core/settings.c Normal file
View File

@ -0,0 +1,336 @@
/*
settings.c : Irssi settings
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "commands.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "default-config.h"
#include <signal.h>
CONFIG_REC *mainconfig;
static GHashTable *settings;
static char *last_error_msg;
static const char *settings_get_default_str(const char *key)
{
SETTINGS_REC *rec;
g_return_val_if_fail(key != NULL, NULL);
rec = g_hash_table_lookup(settings, key);
if (rec == NULL) {
g_warning("settings_get_default_str(%s) : unknown setting", key);
return NULL;
}
return rec->def;
}
static int settings_get_default_int(const char *key)
{
SETTINGS_REC *rec;
g_return_val_if_fail(key != NULL, -1);
rec = g_hash_table_lookup(settings, key);
if (rec == NULL) {
g_warning("settings_get_default_int(%s) : unknown setting", key);
return -1;
}
return GPOINTER_TO_INT(rec->def);
}
const char *settings_get_str(const char *key)
{
return iconfig_get_str("settings", key, settings_get_default_str(key));
}
const int settings_get_int(const char *key)
{
return iconfig_get_int("settings", key, settings_get_default_int(key));
}
const int settings_get_bool(const char *key)
{
return iconfig_get_bool("settings", key, settings_get_default_int(key));
}
void settings_add_str(const char *section, const char *key, const char *def)
{
SETTINGS_REC *rec;
g_return_if_fail(key != NULL);
g_return_if_fail(section != NULL);
rec = g_hash_table_lookup(settings, key);
g_return_if_fail(rec == NULL);
rec = g_new0(SETTINGS_REC, 1);
rec->key = g_strdup(key);
rec->section = g_strdup(section);
rec->def = def == NULL ? NULL : g_strdup(def);
g_hash_table_insert(settings, rec->key, rec);
}
void settings_add_int(const char *section, const char *key, int def)
{
SETTINGS_REC *rec;
g_return_if_fail(key != NULL);
g_return_if_fail(section != NULL);
rec = g_hash_table_lookup(settings, key);
g_return_if_fail(rec == NULL);
rec = g_new0(SETTINGS_REC, 1);
rec->type = SETTING_TYPE_INT;
rec->key = g_strdup(key);
rec->section = g_strdup(section);
rec->def = GINT_TO_POINTER(def);
g_hash_table_insert(settings, rec->key, rec);
}
void settings_add_bool(const char *section, const char *key, int def)
{
SETTINGS_REC *rec;
g_return_if_fail(key != NULL);
g_return_if_fail(section != NULL);
rec = g_hash_table_lookup(settings, key);
g_return_if_fail(rec == NULL);
rec = g_new0(SETTINGS_REC, 1);
rec->type = SETTING_TYPE_BOOLEAN;
rec->key = g_strdup(key);
rec->section = g_strdup(section);
rec->def = GINT_TO_POINTER(def);
g_hash_table_insert(settings, rec->key, rec);
}
static void settings_destroy(SETTINGS_REC *rec)
{
if (rec->type == SETTING_TYPE_STRING)
g_free_not_null(rec->def);
g_free(rec->section);
g_free(rec->key);
g_free(rec);
}
void settings_remove(const char *key)
{
SETTINGS_REC *rec;
g_return_if_fail(key != NULL);
rec = g_hash_table_lookup(settings, key);
if (rec == NULL) return;
g_hash_table_remove(settings, key);
settings_destroy(rec);
}
int settings_get_type(const char *key)
{
SETTINGS_REC *rec;
g_return_val_if_fail(key != NULL, -1);
rec = g_hash_table_lookup(settings, key);
return rec == NULL ? -1 : rec->type;
}
/* Get the record of the setting */
SETTINGS_REC *settings_get_record(const char *key)
{
g_return_val_if_fail(key != NULL, NULL);
return g_hash_table_lookup(settings, key);
}
static int settings_compare(SETTINGS_REC *v1, SETTINGS_REC *v2)
{
return strcmp(v1->section, v2->section);
}
static void settings_hash_get(const char *key, SETTINGS_REC *rec, GSList **list)
{
*list = g_slist_insert_sorted(*list, rec, (GCompareFunc) settings_compare);
}
GSList *settings_get_sorted(void)
{
GSList *list;
list = NULL;
g_hash_table_foreach(settings, (GHFunc) settings_hash_get, &list);
return list;
}
void sig_term(int n)
{
/* if we get SIGTERM after this, just die instead of coming back here. */
signal(SIGTERM, SIG_DFL);
/* quit from all servers too.. */
signal_emit("command quit", 1, "");
/* and die */
raise(SIGTERM);
}
static CONFIG_REC *parse_configfile(const char *fname)
{
CONFIG_REC *config;
char *str;
str = fname != NULL ? g_strdup(fname) :
g_strdup_printf("%s/.irssi/config", g_get_home_dir());
config = config_open(str, -1);
g_free(str);
if (config == NULL && *fname != '\0')
return NULL; /* specified config file not found */
if (config != NULL)
config_parse(config);
else {
/* user configuration file not found, use the default one
from sysconfdir */
config = config_open(SYSCONFDIR"/irssi/config", -1);
if (config != NULL)
config_parse(config);
else {
/* no configuration file in sysconfdir ..
use the build-in configuration */
config = config_open(NULL, -1);
config_parse_data(config, default_config, "internal");
}
config_change_file_name(config, fname, 0660);
}
return config;
}
static void sig_print_config_error(void)
{
signal_emit("gui dialog", 2, "error", last_error_msg);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_print_config_error);
g_free_and_null(last_error_msg);
}
static void init_configfile(void)
{
struct stat statbuf;
char *str;
str = g_strdup_printf("%s/.irssi", g_get_home_dir());
if (stat(str, &statbuf) != 0) {
/* ~/.irssi not found, create it. */
if (mkdir(str, 0700) != 0)
g_error("Couldn't create %s/.irssi directory", g_get_home_dir());
}
g_free(str);
mainconfig = parse_configfile(NULL);
/* any errors? */
if (config_last_error(mainconfig) != NULL) {
last_error_msg = g_strdup_printf("Ignored errors in configuration file:\n%s",
config_last_error(mainconfig));
signal_add("irssi init finished", (SIGNAL_FUNC) sig_print_config_error);
}
signal(SIGTERM, sig_term);
}
static void cmd_rehash(const char *data)
{
CONFIG_REC *tempconfig;
char *str, *fname;
fname = *data != '\0' ? g_strdup(data) :
g_strdup_printf("%s/.irssi/config", g_get_home_dir());
tempconfig = parse_configfile(fname);
g_free(fname);
if (tempconfig == NULL) {
signal_emit("gui dialog", 2, "error", g_strerror(errno));
return;
}
if (config_last_error(tempconfig) != NULL) {
/* error */
str = g_strdup_printf("Errors in configuration file:\n%s",
config_last_error(tempconfig));
signal_emit("gui dialog", 2, "error", str);
g_free(str);
config_close(tempconfig);
return;
}
config_close(mainconfig);
mainconfig = tempconfig;
signal_emit("setup changed", 0);
signal_emit("setup reread", 0);
}
static void cmd_save(const char *data)
{
config_write(mainconfig, *data == '\0' ? NULL : data, 0660);
}
void settings_init(void)
{
settings = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
init_configfile();
command_bind("rehash", NULL, (SIGNAL_FUNC) cmd_rehash);
command_bind("save", NULL, (SIGNAL_FUNC) cmd_save);
}
static void settings_hash_free(const char *key, SETTINGS_REC *rec)
{
settings_destroy(rec);
}
void settings_deinit(void)
{
command_unbind("rehash", (SIGNAL_FUNC) cmd_rehash);
command_unbind("save", (SIGNAL_FUNC) cmd_save);
g_free_not_null(last_error_msg);
g_hash_table_foreach(settings, (GHFunc) settings_hash_free, NULL);
g_hash_table_destroy(settings);
if (mainconfig != NULL) config_close(mainconfig);
}

56
src/core/settings.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef __SETTINGS_H
#define __SETTINGS_H
#ifndef __ICONFIG_H
typedef struct _config_rec CONFIG_REC;
#endif
enum {
SETTING_TYPE_STRING,
SETTING_TYPE_INT,
SETTING_TYPE_BOOLEAN,
};
typedef struct {
int type;
char *key;
char *section;
void *def;
} SETTINGS_REC;
/* macros for handling the default Irssi configuration */
#define iconfig_get_str(a, b, c) config_get_str(mainconfig, a, b,c)
#define iconfig_get_int(a, b, c) config_get_int(mainconfig, a, b,c)
#define iconfig_get_bool(a, b, c) config_get_bool(mainconfig, a, b,c)
#define iconfig_list_find(a, b, c, d) config_list_find(mainconfig, a, b, c, d)
#define iconfig_set_str(a, b, c) config_set_str(mainconfig, a, b,c)
#define iconfig_set_int(a, b, c) config_set_int(mainconfig, a, b,c)
#define iconfig_set_bool(a, b, c) config_set_bool(mainconfig, a, b,c)
#define iconfig_node_traverse(a, b) config_node_traverse(mainconfig, a, b)
extern CONFIG_REC *mainconfig;
/* Functions for handling the "settings" node of Irssi configuration */
const char *settings_get_str(const char *key);
const int settings_get_int(const char *key);
const int settings_get_bool(const char *key);
/* Functions to add/remove settings */
void settings_add_str(const char *section, const char *key, const char *def);
void settings_add_int(const char *section, const char *key, int def);
void settings_add_bool(const char *section, const char *key, int def);
void settings_remove(const char *key);
/* Get the type (SETTING_TYPE_xxx) of `key' */
int settings_get_type(const char *key);
/* Get all settings sorted by section. Free the result with g_slist_free() */
GSList *settings_get_sorted(void);
/* Get the record of the setting */
SETTINGS_REC *settings_get_record(const char *key);
void settings_init(void);
void settings_deinit(void);
#endif

356
src/core/signals.c Normal file
View File

@ -0,0 +1,356 @@
/*
signals.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "../common.h"
#include "signals.h"
#include "modules.h"
#define SIGNAL_LISTS 3
typedef struct {
int emitting; /* signal is being emitted */
int altered; /* some signal functions are marked as NULL */
int stop_emit; /* this signal was stopped */
GPtrArray *modulelist[SIGNAL_LISTS]; /* list of what signals belong
to which module */
GPtrArray *siglist[SIGNAL_LISTS]; /* signal lists */
} SIGNAL_REC;
#define signal_is_emitlist_empty(a) \
(!(a)->siglist[0] && !(a)->siglist[1] && !(a)->siglist[2])
static GMemChunk *signals_chunk;
static GHashTable *signals;
static SIGNAL_REC *first_signal_rec, *last_signal_rec; /* "signal" and "last signal" */
static SIGNAL_REC *current_emitted_signal;
/* bind a signal */
void signal_add_to(const char *module, int pos, const char *signal, SIGNAL_FUNC func)
{
SIGNAL_REC *rec;
int signal_id;
g_return_if_fail(signal != NULL);
g_return_if_fail(func != NULL);
g_return_if_fail(pos >= 0 && pos < SIGNAL_LISTS);
signal_id = module_get_uniq_id_str("signals", signal);
rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id));
if (rec == NULL) {
rec = g_mem_chunk_alloc0(signals_chunk);
g_hash_table_insert(signals, GINT_TO_POINTER(signal_id), rec);
}
if (strcmp(signal, "signal") == 0)
first_signal_rec = rec;
else if (strcmp(signal, "last signal") == 0)
last_signal_rec = rec;
if (rec->siglist[pos] == NULL) {
rec->siglist[pos] = g_ptr_array_new();
rec->modulelist[pos] = g_ptr_array_new();
}
g_ptr_array_add(rec->siglist[pos], (void *) func);
g_ptr_array_add(rec->modulelist[pos], (void *) module);
}
/* Destroy the whole signal */
static void signal_destroy(int signal_id)
{
SIGNAL_REC *rec;
rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id));
if (rec != NULL) {
/* remove whole signal from memory */
g_hash_table_remove(signals, GINT_TO_POINTER(signal_id));
g_free(rec);
}
if (first_signal_rec == rec)
first_signal_rec = NULL;
else if (last_signal_rec == rec)
last_signal_rec = NULL;
}
static int signal_list_find(GPtrArray *array, void *data)
{
int n;
for (n = 0; n < array->len; n++) {
if (g_ptr_array_index(array, n) == data)
return n;
}
return -1;
}
static void signal_remove_from_list(SIGNAL_REC *rec, int signal_id, int list, int index)
{
if (rec->emitting) {
g_ptr_array_index(rec->siglist[list], index) = NULL;
rec->altered = TRUE;
} else {
g_ptr_array_remove_index(rec->siglist[list], index);
g_ptr_array_remove_index(rec->modulelist[list], index);
if (signal_is_emitlist_empty(rec))
signal_destroy(signal_id);
}
}
/* Remove signal from emit lists */
static int signal_remove_from_lists(SIGNAL_REC *rec, int signal_id, SIGNAL_FUNC func)
{
int n, index;
for (n = 0; n < SIGNAL_LISTS; n++) {
if (rec->siglist[n] == NULL)
continue;
index = signal_list_find(rec->siglist[n], (void *) func);
if (index != -1) {
/* remove the function from emit list */
signal_remove_from_list(rec, signal_id, n, index);
return 1;
}
}
return 0;
}
/* unbind signal */
void signal_remove(const char *signal, SIGNAL_FUNC func)
{
SIGNAL_REC *rec;
int signal_id, found;
g_return_if_fail(signal != NULL);
g_return_if_fail(func != NULL);
signal_id = module_get_uniq_id_str("signals", signal);
rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id));
found = rec == NULL ? 0 : signal_remove_from_lists(rec, signal_id, func);
if (!found) g_warning("signal_remove() : signal \"%s\" isn't grabbed for %p", signal, func);
}
/* Remove all NULL functions from signal list */
static void signal_list_clean(SIGNAL_REC *rec)
{
int n, index;
for (n = 0; n < SIGNAL_LISTS; n++) {
if (rec->siglist[n] == NULL)
continue;
for (index = rec->siglist[n]->len-1; index >= 0; index--) {
if (g_ptr_array_index(rec->siglist[n], index) == NULL) {
g_ptr_array_remove_index(rec->siglist[n], index);
g_ptr_array_remove_index(rec->modulelist[n], index);
}
}
}
}
static int signal_emit_real(SIGNAL_REC *rec, gconstpointer *arglist)
{
SIGNAL_REC *prev_emitted_signal;
SIGNAL_FUNC func;
int n, index, stopped;
stopped = FALSE;
rec->emitting++;
for (n = 0; n < SIGNAL_LISTS; n++) {
/* run signals in emit lists */
if (rec->siglist[n] == NULL)
continue;
for (index = rec->siglist[n]->len-1; index >= 0; index--) {
func = (SIGNAL_FUNC) g_ptr_array_index(rec->siglist[n], index);
if (func != NULL) {
prev_emitted_signal = current_emitted_signal;
current_emitted_signal = rec;
func(arglist[0], arglist[1], arglist[2], arglist[3], arglist[4], arglist[5], arglist[6]);
current_emitted_signal = prev_emitted_signal;
}
if (rec->stop_emit) {
stopped = TRUE;
rec->stop_emit--;
n = SIGNAL_LISTS;
break;
}
}
}
rec->emitting--;
if (!rec->emitting && rec->altered) {
signal_list_clean(rec);
rec->altered = FALSE;
}
return stopped;
}
static int signal_emitv_id(int signal_id, int params, va_list va)
{
gconstpointer arglist[8];
SIGNAL_REC *rec;
int n;
g_return_val_if_fail(signal_id >= 0, FALSE);
g_return_val_if_fail(params >= 0 && params <= sizeof(arglist)/sizeof(arglist[0]), FALSE);
arglist[0] = GINT_TO_POINTER(signal_id);
for (n = 1; n < 8; n++)
arglist[n] = n >= params ? NULL : va_arg(va, gconstpointer);
/* send "signal" */
if (first_signal_rec != NULL) {
if (signal_emit_real(first_signal_rec, arglist))
return TRUE;
}
rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id));
if (rec != NULL && signal_emit_real(rec, arglist+1))
return TRUE;
/* send "last signal" */
if (last_signal_rec != NULL) {
if (signal_emit_real(last_signal_rec, arglist))
return TRUE;
}
return rec != NULL;
}
int signal_emit(const char *signal, int params, ...)
{
va_list va;
int signal_id, ret;
/* get arguments */
signal_id = module_get_uniq_id_str("signals", signal);
va_start(va, params);
ret = signal_emitv_id(signal_id, params, va);
va_end(va);
return ret;
}
int signal_emit_id(int signal_id, int params, ...)
{
va_list va;
int ret;
/* get arguments */
va_start(va, params);
ret = signal_emitv_id(signal_id, params, va);
va_end(va);
return ret;
}
/* stop the current ongoing signal emission */
void signal_stop(void)
{
SIGNAL_REC *rec;
rec = current_emitted_signal;
if (rec == NULL || rec->emitting <= rec->stop_emit)
g_warning("signal_stop() : no signals are being emitted currently");
else
rec->stop_emit++;
}
/* stop ongoing signal emission by signal name */
void signal_stop_by_name(const char *signal)
{
SIGNAL_REC *rec;
rec = g_hash_table_lookup(signals, signal);
if (rec == NULL)
g_warning("signal_stop_by_name() : unknown signal \"%s\"", signal);
else if (rec->emitting <= rec->stop_emit)
g_warning("signal_stop_by_name() : signal \"%s\" not being emitted", signal);
else
rec->stop_emit++;
}
static void signal_remove_module(void *signal, SIGNAL_REC *rec, const char *module)
{
int signal_id, list, index;
signal_id = GPOINTER_TO_INT(signal);
for (list = 0; list < SIGNAL_LISTS; list++) {
for (index = 0; index < rec->modulelist[list]->len; index++) {
if (g_strcasecmp(g_ptr_array_index(rec->modulelist[list], index), module) == 0)
signal_remove_from_list(rec, signal_id, list, index);
}
}
}
/* remove all signals that belong to `module' */
void signals_remove_module(const char *module)
{
g_return_if_fail(module != NULL);
g_hash_table_foreach(signals, (GHFunc) signal_remove_module, (void *) module);
}
void signals_init(void)
{
signals_chunk = g_mem_chunk_new("signals", sizeof(SIGNAL_REC),
sizeof(SIGNAL_REC)*200, G_ALLOC_AND_FREE);
signals = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
first_signal_rec = NULL;
last_signal_rec = NULL;
}
static void signal_free(void *key, SIGNAL_REC *rec)
{
int n;
for (n = 0; n < SIGNAL_LISTS; n++) {
if (rec->siglist[n] != NULL) {
g_ptr_array_free(rec->siglist[n], TRUE);
g_ptr_array_free(rec->modulelist[n], TRUE);
}
}
g_mem_chunk_free(signals_chunk, rec);
current_emitted_signal = NULL;
}
void signals_deinit(void)
{
g_hash_table_foreach(signals, (GHFunc) signal_free, NULL);
g_hash_table_destroy(signals);
module_uniq_destroy("signals");
g_mem_chunk_destroy(signals_chunk);
}

30
src/core/signals.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __SIGNAL_H
#define __SIGNAL_H
typedef void (*SIGNAL_FUNC) (gconstpointer, gconstpointer, gconstpointer, gconstpointer, gconstpointer, gconstpointer, gconstpointer);
void signals_init(void);
void signals_deinit(void);
/* bind a signal */
void signal_add_to(const char *module, int pos, const char *signal, SIGNAL_FUNC func);
#define signal_add(a, b) signal_add_to(MODULE_NAME, 1, a, b)
#define signal_add_first(a, b) signal_add_to(MODULE_NAME, 0, a, b)
#define signal_add_last(a, b) signal_add_to(MODULE_NAME, 2, a, b)
/* unbind signal */
void signal_remove(const char *signal, SIGNAL_FUNC func);
/* emit signal */
int signal_emit(const char *signal, int params, ...);
int signal_emit_id(int signal_id, int params, ...);
/* stop the current ongoing signal emission */
void signal_stop(void);
/* stop ongoing signal emission by signal name */
void signal_stop_by_name(const char *signal);
/* remove all signals that belong to `module' */
void signals_remove_module(const char *module);
#endif

635
src/core/special-vars.c Normal file
View File

@ -0,0 +1,635 @@
/*
special-vars.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "special-vars.h"
#include "settings.h"
#include "misc.h"
#include "irssi-version.h"
#include <sys/utsname.h>
#define ALIGN_RIGHT 0x01
#define ALIGN_CUT 0x02
static EXPANDO_FUNC char_expandos[256];
static GHashTable *expandos;
static time_t client_start_time;
static SPECIAL_HISTORY_FUNC history_func;
static char *get_argument(char **cmd, char **arglist)
{
GString *str;
char *ret;
int max, arg, argcount;
arg = 0;
max = -1;
argcount = strarray_length(arglist);
if (**cmd == '*') {
/* get all arguments */
} else if (**cmd == '~') {
/* get last argument */
arg = max = argcount-1;
} else {
if (isdigit(**cmd)) {
/* first argument */
arg = max = (**cmd)-'0';
(*cmd)++;
}
if (**cmd == '-') {
/* get more than one argument */
(*cmd)++;
if (!isdigit(**cmd))
max = -1; /* get all the rest */
else {
max = (**cmd)-'0';
(*cmd)++;
}
}
(*cmd)--;
}
str = g_string_new(NULL);
while (arg < argcount && (arg <= max || max == -1)) {
g_string_append(str, arglist[arg]);
g_string_append_c(str, ' ');
arg++;
}
if (str->len > 0) g_string_truncate(str, str->len-1);
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
static char *get_internal_setting(const char *key, int type, int *free_ret)
{
switch (type) {
case SETTING_TYPE_BOOLEAN:
return settings_get_bool(key) ? "yes" : "no";
case SETTING_TYPE_INT:
*free_ret = TRUE;
return g_strdup_printf("%d", settings_get_int(key));
case SETTING_TYPE_STRING:
return (char *) settings_get_str(key);
}
return NULL;
}
static char *get_long_variable_value(const char *key, void *server, void *item, int *free_ret)
{
EXPANDO_FUNC func;
char *ret;
int type;
*free_ret = FALSE;
/* expando? */
func = g_hash_table_lookup(expandos, key);
if (func != NULL)
return func(server, item, free_ret);
/* internal setting? */
type = settings_get_type(key);
if (type != -1)
return get_internal_setting(key, type, free_ret);
/* environment variable? */
ret = g_getenv(key);
if (ret != NULL) {
*free_ret = TRUE;
return ret;
}
return NULL;
}
static char *get_long_variable(char **cmd, void *server, void *item, int *free_ret)
{
char *start, *var, *ret;
/* get variable name */
start = *cmd;
while (isalnum((*cmd)[1])) (*cmd)++;
var = g_strndup(start, (int) (*cmd-start)+1);
ret = get_long_variable_value(var, server, item, free_ret);
g_free(var);
return ret;
}
/* return the value of the variable found from `cmd' */
static char *get_variable(char **cmd, void *server, void *item, char **arglist, int *free_ret, int *arg_used)
{
if (isdigit(**cmd) || **cmd == '*' || **cmd == '-' || **cmd == '~') {
/* argument */
*free_ret = TRUE;
if (arg_used != NULL) *arg_used = TRUE;
return get_argument(cmd, arglist);
}
if (isalpha(**cmd) && isalnum((*cmd)[1])) {
/* long variable name.. */
return get_long_variable(cmd, server, item, free_ret);
}
/* single character variable. */
*free_ret = FALSE;
return char_expandos[(int) **cmd] == NULL ? NULL :
char_expandos[(int) **cmd](server, item, free_ret);
}
static char *get_history(char **cmd, void *item, int *free_ret)
{
char *start, *text, *ret;
/* get variable name */
start = ++(*cmd);
while (**cmd != '\0' && **cmd != '!') (*cmd)++;
if (history_func == NULL)
ret = NULL;
else {
text = g_strndup(start, (int) (*cmd-start)+1);
ret = history_func(text, item, free_ret);
g_free(text);
}
if (**cmd == '\0') (*cmd)--;
return ret;
}
static char *get_special_value(char **cmd, void *server, void *item, char **arglist, int *free_ret, int *arg_used)
{
char command, *value, *p;
int len;
if (**cmd == '!') {
/* find text from command history */
return get_history(cmd, item, free_ret);
}
command = 0;
if (**cmd == '#' || **cmd == '@') {
command = **cmd;
if ((*cmd)[1] != '\0')
(*cmd)++;
else {
/* default to $* */
char *temp_cmd = "*";
*free_ret = TRUE;
return get_argument(&temp_cmd, arglist);
}
}
value = get_variable(cmd, server, item, arglist, free_ret, arg_used);
if (command == '#') {
/* number of words */
if (value == NULL || *value == '\0') {
if (value != NULL && *free_ret) {
g_free(value);
*free_ret = FALSE;
}
return "0";
}
len = 1;
for (p = value; *p != '\0'; p++) {
if (*p == ' ' && (p[1] != ' ' && p[1] != '\0'))
len++;
}
if (*free_ret) g_free(value);
*free_ret = TRUE;
return g_strdup_printf("%d", len);
}
if (command == '@') {
/* number of characters */
if (value == NULL) return "0";
len = strlen(value);
if (*free_ret) g_free(value);
*free_ret = TRUE;
return g_strdup_printf("%d", len);
}
return value;
}
/* get alignment arguments (inside the []) */
static int get_alignment_args(char **data, int *align, int *flags, char *pad)
{
char *str;
*align = 0;
*flags = ALIGN_CUT;
*pad = ' ';
/* '!' = don't cut, '-' = right padding */
str = *data;
while (*str != '\0' && *str != ']' && !isdigit(*str)) {
if (*str == '!')
*flags &= ~ALIGN_CUT;
else if (*str == '-')
*flags |= ALIGN_RIGHT;
str++;
}
if (!isdigit(*str))
return FALSE; /* expecting number */
/* get the alignment size */
while (isdigit(*str)) {
*align = (*align) * 10 + (*str-'0');
str++;
}
/* get the pad character */
while (*str != '\0' && *str != ']') {
*pad = *str;
str++;
}
if (*str++ != ']') return FALSE;
*data = str;
return TRUE;
}
/* return the aligned text */
static char *get_alignment(const char *text, int align, int flags, char pad)
{
GString *str;
char *ret;
g_return_val_if_fail(text != NULL, NULL);
str = g_string_new(text);
/* cut */
if ((flags & ALIGN_CUT) && align > 0 && str->len > align)
g_string_truncate(str, align);
/* add pad characters */
while (str->len < align) {
if (flags & ALIGN_RIGHT)
g_string_prepend_c(str, pad);
else
g_string_append_c(str, pad);
}
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
/* Parse and expand text after '$' character. return value has to be
g_free()'d if `free_ret' is TRUE. */
char *parse_special(char **cmd, void *server, void *item, char **arglist, int *free_ret, int *arg_used)
{
static char **nested_orig_cmd = NULL; /* FIXME: KLUDGE! */
char command, *value;
char align_pad;
int align, align_flags;
char *nest_value;
int brackets, nest_free;
*free_ret = FALSE;
command = **cmd; (*cmd)++;
switch (command) {
case '[':
/* alignment */
if (!get_alignment_args(cmd, &align, &align_flags, &align_pad) ||
**cmd == '\0') {
(*cmd)--;
return NULL;
}
break;
default:
command = 0;
(*cmd)--;
}
nest_free = FALSE; nest_value = NULL;
if (**cmd == '(') {
/* subvariable */
int toplevel = nested_orig_cmd == NULL;
if (toplevel) nested_orig_cmd = cmd;
(*cmd)++;
if (**cmd != '$') {
/* ... */
nest_value = *cmd;
} else {
(*cmd)++;
nest_value = parse_special(cmd, server, item, arglist, &nest_free, arg_used);
}
while ((*nested_orig_cmd)[1] != '\0') {
(*nested_orig_cmd)++;
if (**nested_orig_cmd == ')') break;
}
cmd = &nest_value;
if (toplevel) nested_orig_cmd = NULL;
}
if (**cmd != '{')
brackets = FALSE;
else {
/* special value is inside {...} (foo${test}bar -> fooXXXbar) */
(*cmd)++;
brackets = TRUE;
}
value = get_special_value(cmd, server, item, arglist, free_ret, arg_used);
if (**cmd == '\0')
g_error("parse_special() : buffer overflow!");
if (brackets) {
while (**cmd != '}' && (*cmd)[1] != '\0')
(*cmd)++;
}
if (nest_free) g_free(nest_value);
if (command == '[') {
/* alignment */
char *p;
if (value == NULL) return "";
p = get_alignment(value, align, align_flags, align_pad);
if (*free_ret) g_free(value);
*free_ret = TRUE;
return p;
}
return value;
}
/* parse the whole string. $ and \ chars are replaced */
char *parse_special_string(const char *cmd, void *server, void *item, const char *data, int *arg_used)
{
char code, **arglist, *ret;
GString *str;
int need_free;
g_return_val_if_fail(cmd != NULL, NULL);
g_return_val_if_fail(data != NULL, NULL);
/* create the argument list */
arglist = g_strsplit(data, " ", -1);
if (arg_used != NULL) *arg_used = FALSE;
code = 0;
str = g_string_new(NULL);
while (*cmd != '\0') {
if (code == '\\'){
g_string_append_c(str, *cmd);
code = 0;
} else if (code == '$') {
char *ret;
ret = parse_special((char **) &cmd, server, item, arglist, &need_free, arg_used);
if (ret != NULL) {
g_string_append(str, ret);
if (need_free) g_free(ret);
}
code = 0;
} else {
if (*cmd == '\\' || *cmd == '$')
code = *cmd;
else
g_string_append_c(str, *cmd);
}
cmd++;
}
g_strfreev(arglist);
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
/* execute the commands in string - commands can be split with ';' */
void eval_special_string(const char *cmd, const char *data, void *server, void *item)
{
const char *cmdchars;
char *orig, *str, *start, *ret;
int arg_used;
cmdchars = settings_get_str("cmdchars");
orig = start = str = g_strdup(cmd);
do {
if (*str == ';' && (start == str || (str[-1] != '\\' && str[-1] != '$')))
*str++ = '\0';
else if (*str != '\0') {
str++;
continue;
}
ret = parse_special_string(start, server, item, data, &arg_used);
if (strchr(cmdchars, *ret) == NULL) {
/* no command char - let's put it there.. */
char *old = ret;
ret = g_strdup_printf("%c%s", *cmdchars, old);
g_free(old);
}
if (!arg_used && *data != '\0') {
/* append the string with all the arguments */
char *old = ret;
ret = g_strconcat(old, " ", data, NULL);
g_free(old);
}
signal_emit("send command", 3, ret, server, item);
g_free(ret);
start = str;
} while (*start != '\0');
g_free(orig);
}
/* Create expando - overrides any existing ones. */
void expando_create(const char *key, EXPANDO_FUNC func)
{
gpointer origkey, origvalue;
g_return_if_fail(key != NULL || *key == '\0');
g_return_if_fail(func != NULL);
if (key[1] == '\0') {
/* single character expando */
char_expandos[(int) *key] = func;
return;
}
if (g_hash_table_lookup_extended(expandos, key, &origkey, &origvalue)) {
g_free(origkey);
g_hash_table_remove(expandos, key);
}
g_hash_table_insert(expandos, g_strdup(key), func);
}
/* Destroy expando */
void expando_destroy(const char *key, EXPANDO_FUNC func)
{
gpointer origkey, origvalue;
g_return_if_fail(key != NULL || *key == '\0');
g_return_if_fail(func != NULL);
if (key[1] == '\0') {
/* single character expando */
if (char_expandos[(int) *key] == func)
char_expandos[(int) *key] = NULL;
return;
}
if (g_hash_table_lookup_extended(expandos, key, &origkey, &origvalue)) {
g_free(origkey);
g_hash_table_remove(expandos, key);
}
}
void special_history_func_set(SPECIAL_HISTORY_FUNC func)
{
history_func = func;
}
/* time client was started, $time() format */
static char *expando_clientstarted(void *server, void *item, int *free_ret)
{
*free_ret = TRUE;
return g_strdup_printf("%ld", (long) client_start_time);
}
/* client version text string */
static char *expando_version(void *server, void *item, int *free_ret)
{
return IRSSI_VERSION;
}
/* current value of CMDCHARS */
static char *expando_cmdchars(void *server, void *item, int *free_ret)
{
return (char *) settings_get_str("cmdchars");
}
/* client release date (numeric version string) */
static char *expando_releasedate(void *server, void *item, int *free_ret)
{
return IRSSI_VERSION_DATE;
}
/* current working directory */
static char *expando_workdir(void *server, void *item, int *free_ret)
{
*free_ret = TRUE;
return g_get_current_dir();
}
/* time of day (hh:mm) */
static char *expando_time(void *server, void *item, int *free_ret)
{
time_t now = time(NULL);
struct tm *tm;
tm = localtime(&now);
*free_ret = TRUE;
return g_strdup_printf("%02d:%02d", tm->tm_hour, tm->tm_min);
}
/* a literal '$' */
static char *expando_dollar(void *server, void *item, int *free_ret)
{
return "$";
}
/* system name */
static char *expando_sysname(void *server, void *item, int *free_ret)
{
struct utsname un;
if (uname(&un) != 0)
return NULL;
*free_ret = TRUE;
return g_strdup(un.sysname);
}
/* system release */
static char *expando_sysrelease(void *server, void *item, int *free_ret)
{
struct utsname un;
if (uname(&un) != 0)
return NULL;
*free_ret = TRUE;
return g_strdup(un.release);
}
void special_vars_init(void)
{
client_start_time = time(NULL);
memset(char_expandos, 0, sizeof(char_expandos));
expandos = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
history_func = NULL;
char_expandos['F'] = expando_clientstarted;
char_expandos['J'] = expando_version;
char_expandos['K'] = expando_cmdchars;
char_expandos['V'] = expando_releasedate;
char_expandos['W'] = expando_workdir;
char_expandos['Z'] = expando_time;
char_expandos['$'] = expando_dollar;
expando_create("sysname", expando_sysname);
expando_create("sysrelease", expando_sysrelease);
}
void special_vars_deinit(void)
{
expando_destroy("sysname", expando_sysname);
expando_destroy("sysrelease", expando_sysrelease);
g_hash_table_destroy(expandos);
}

27
src/core/special-vars.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef __SPECIAL_VARS_H
#define __SPECIAL_VARS_H
typedef char* (*EXPANDO_FUNC) (void *server, void *item, int *free_ret);
typedef char* (*SPECIAL_HISTORY_FUNC) (const char *text, void *item, int *free_ret);
/* Parse and expand text after '$' character. return value has to be
g_free()'d if `free_ret' is TRUE. */
char *parse_special(char **cmd, void *server, void *item, char **arglist, int *free_ret, int *arg_used);
/* parse the whole string. $ and \ chars are replaced */
char *parse_special_string(const char *cmd, void *server, void *item, const char *data, int *arg_used);
/* execute the commands in string - commands can be split with ';' */
void eval_special_string(const char *cmd, const char *data, void *server, void *item);
/* Create expando - overrides any existing ones. */
void expando_create(const char *key, EXPANDO_FUNC func);
/* Destroy expando */
void expando_destroy(const char *key, EXPANDO_FUNC func);
void special_history_func_set(SPECIAL_HISTORY_FUNC func);
void special_vars_init(void);
void special_vars_deinit(void);
#endif

View File

@ -0,0 +1 @@
SUBDIRS = core irc

View File

@ -0,0 +1,38 @@
noinst_LTLIBRARIES = libfe_common_core.la
INCLUDES = \
$(GLIB_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src/core/ \
-DHELPDIR=\""$(datadir)/irssi/help"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\"
libfe_common_core_la_SOURCES = \
autorun.c \
command-history.c \
fe-common-core.c \
fe-core-commands.c \
fe-log.c \
fe-server.c \
fe-settings.c \
hilight-text.c \
keyboard.c \
module-formats.c \
nick-hilight.c \
printtext.c \
themes.c \
translation.c \
window-items.c \
windows.c
noinst_HEADERS = \
command-history.h \
fe-common-core.h \
hilight-text.h \
keyboard.h \
module-formats.h \
module.h \
printtext.h \
themes.h \
translation.h \
window-items.h \
windows.h

View File

@ -0,0 +1,62 @@
/*
autorun.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "line-split.h"
#include "special-vars.h"
#include "windows.h"
static void sig_autorun(void)
{
char tmpbuf[1024], *str, *path;
LINEBUF_REC *buffer = NULL;
int f, ret, recvlen;
/* open ~/.irssi/startup and run all commands in it */
path = g_strdup_printf("%s/.irssi/startup", g_get_home_dir());
f = open(path, O_RDONLY);
g_free(path);
if (f == -1) {
/* file not found */
return;
}
do {
recvlen = read(f, tmpbuf, sizeof(tmpbuf));
ret = line_split(tmpbuf, recvlen, &str, &buffer);
eval_special_string(str, "", active_win->active_server, active_win->active);
} while (ret > 0);
line_split_free(buffer);
close(f);
}
void autorun_init(void)
{
signal_add_last("irssi init finished", (SIGNAL_FUNC) sig_autorun);
}
void autorun_deinit(void)
{
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_autorun);
}

View File

@ -0,0 +1,182 @@
/*
command-history.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "misc.h"
#include "special-vars.h"
#include "settings.h"
#include "windows.h"
#include "window-items.h"
/* command history */
static GList *cmdhist, *histpos;
static int histlines;
static int window_history;
void command_history_add(WINDOW_REC *window, const char *text, int prepend)
{
GList **pcmdhist, *link;
int *phistlines;
g_return_if_fail(text != NULL);
if (window_history) {
/* window specific command history */
pcmdhist = &window->cmdhist;
phistlines = &window->histlines;
} else {
/* global command history */
pcmdhist = &cmdhist;
phistlines = &histlines;
}
if (settings_get_int("max_command_history") < 1 || *phistlines < settings_get_int("max_command_history"))
(*phistlines)++;
else {
link = *pcmdhist;
g_free(link->data);
*pcmdhist = g_list_remove_link(*pcmdhist, link);
g_list_free_1(link);
}
if (prepend)
*pcmdhist = g_list_prepend(*pcmdhist, g_strdup(text));
else
*pcmdhist = g_list_append(*pcmdhist, g_strdup(text));
}
const char *command_history_prev(WINDOW_REC *window, const char *text)
{
GList *pos, **phistpos;
phistpos = window_history ? &window->histpos : &histpos;
pos = *phistpos;
if (*phistpos == NULL)
*phistpos = g_list_last(window_history ? window->cmdhist : cmdhist);
else
*phistpos = (*phistpos)->prev;
if (*text != '\0' &&
(pos == NULL || strcmp(pos->data, text) != 0)) {
/* save the old entry to history */
command_history_add(window, text, FALSE);
}
return *phistpos == NULL ? "" : (*phistpos)->data;
}
const char *command_history_next(WINDOW_REC *window, const char *text)
{
GList *pos, **phistpos;
phistpos = window_history ? &window->histpos : &histpos;
pos = *phistpos;
if (*phistpos == NULL)
*phistpos = window_history ? window->cmdhist : cmdhist;
else
*phistpos = (*phistpos)->next;
if (*text != '\0' &&
(pos == NULL || strcmp(pos->data, text) != 0)) {
/* save the old entry to history */
command_history_add(window, text, TRUE);
}
return *phistpos == NULL ? "" : (*phistpos)->data;
}
void command_history_clear_pos(WINDOW_REC *window)
{
window->histpos = NULL;
histpos = NULL;
}
static void sig_window_created(WINDOW_REC *window)
{
window->histlines = 0;
window->cmdhist = NULL;
window->histpos = NULL;
}
static void sig_window_destroyed(WINDOW_REC *window)
{
g_list_foreach(window->cmdhist, (GFunc) g_free, NULL);
g_list_free(window->cmdhist);
}
static char *special_history_func(const char *text, void *item, int *free_ret)
{
WINDOW_REC *window;
GList *tmp;
char *findtext, *ret;
window = item == NULL ? active_win : window_item_window(item);
findtext = g_strdup_printf("*%s*", text);
ret = NULL;
tmp = window_history ? window->cmdhist : cmdhist;
for (; tmp != NULL; tmp = tmp->next) {
const char *line = tmp->data;
if (match_wildcards(findtext, line)) {
*free_ret = TRUE;
ret = g_strdup(line);
}
}
g_free(findtext);
return ret;
}
static void read_settings(void)
{
window_history = settings_get_bool("toggle_window_history");
}
void command_history_init(void)
{
settings_add_int("history", "max_textwidget_lines", 1000);
settings_add_int("history", "block_remove_lines", 20);
settings_add_int("history", "max_command_history", 100);
settings_add_bool("history", "toggle_window_history", FALSE);
special_history_func_set(special_history_func);
histlines = 0;
cmdhist = NULL; histpos = NULL;
read_settings();
signal_add("window created", (SIGNAL_FUNC) sig_window_created);
signal_add("window destroyed", (SIGNAL_FUNC) sig_window_destroyed);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
void command_history_deinit(void)
{
signal_remove("window created", (SIGNAL_FUNC) sig_window_created);
signal_remove("window destroyed", (SIGNAL_FUNC) sig_window_destroyed);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
g_list_foreach(cmdhist, (GFunc) g_free, NULL);
g_list_free(cmdhist);
}

View File

@ -0,0 +1,16 @@
#ifndef __COMMAND_HISTORY_H
#define __COMMAND_HISTORY_H
#include "windows.h"
void command_history_init(void);
void command_history_deinit(void);
void command_history_add(WINDOW_REC *window, const char *text, int prepend);
const char *command_history_prev(WINDOW_REC *window, const char *text);
const char *command_history_next(WINDOW_REC *window, const char *text);
void command_history_clear_pos(WINDOW_REC *window);
#endif

View File

@ -0,0 +1,132 @@
/*
fe-common-core.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "levels.h"
#include "settings.h"
#include "hilight-text.h"
#include "command-history.h"
#include "keyboard.h"
#include "printtext.h"
#include "themes.h"
#include "translation.h"
#include "windows.h"
#include "window-items.h"
#include <sys/signal.h>
void autorun_init(void);
void autorun_deinit(void);
void fe_core_log_init(void);
void fe_core_log_deinit(void);
void fe_server_init(void);
void fe_server_deinit(void);
void fe_settings_init(void);
void fe_settings_deinit(void);
void nick_hilight_init(void);
void nick_hilight_deinit(void);
void fe_core_commands_init(void);
void fe_core_commands_deinit(void);
void fe_common_core_init(void)
{
settings_add_bool("lookandfeel", "toggle_show_menubar", TRUE);
settings_add_bool("lookandfeel", "toggle_show_toolbar", FALSE);
settings_add_bool("lookandfeel", "toggle_show_statusbar", TRUE);
settings_add_bool("lookandfeel", "toggle_show_nicklist", TRUE);
settings_add_bool("lookandfeel", "toggle_show_timestamps", FALSE);
settings_add_bool("lookandfeel", "toggle_show_msgs_timestamps", FALSE);
settings_add_bool("lookandfeel", "toggle_hide_text_style", FALSE);
settings_add_bool("lookandfeel", "toggle_bell_beeps", FALSE);
settings_add_bool("lookandfeel", "toggle_actlist_moves", FALSE);
settings_add_bool("lookandfeel", "toggle_show_nickmode", TRUE);
settings_add_bool("lookandfeel", "toggle_show_topicbar", TRUE);
settings_add_bool("lookandfeel", "toggle_use_status_window", FALSE);
settings_add_bool("lookandfeel", "toggle_use_msgs_window", TRUE);
settings_add_bool("lookandfeel", "toggle_autoraise_msgs_window", FALSE);
settings_add_bool("lookandfeel", "toggle_autocreate_query", TRUE);
settings_add_bool("lookandfeel", "toggle_notifylist_popups", FALSE);
settings_add_bool("lookandfeel", "toggle_use_tabbed_windows", TRUE);
settings_add_int("lookandfeel", "tab_orientation", 3);
settings_add_str("lookandfeel", "current_theme", "default");
autorun_init();
nick_hilight_init();
hilight_text_init();
command_history_init();
keyboard_init();
printtext_init();
fe_log_init();
fe_server_init();
fe_settings_init();
themes_init();
translation_init();
windows_init();
window_items_init();
fe_core_commands_init();
}
void fe_common_core_deinit(void)
{
autorun_deinit();
nick_hilight_deinit();
hilight_text_deinit();
command_history_deinit();
keyboard_deinit();
printtext_deinit();
fe_log_deinit();
fe_server_deinit();
fe_settings_deinit();
themes_deinit();
translation_deinit();
windows_deinit();
window_items_deinit();
fe_core_commands_deinit();
}
void fe_common_core_finish_init(void)
{
WINDOW_REC *window;
signal(SIGPIPE, SIG_IGN);
if (settings_get_bool("toggle_use_status_window")) {
window = window_create(NULL, TRUE);
window_set_name(window, "(status)");
window_set_level(window, MSGLEVEL_ALL ^ (settings_get_bool("toggle_use_msgs_window") ? (MSGLEVEL_MSGS|MSGLEVEL_ACTIONS) : 0));
}
if (settings_get_bool("toggle_use_msgs_window")) {
window = window_create(NULL, TRUE);
window_set_name(window, "(msgs)");
window_set_level(window, MSGLEVEL_MSGS|MSGLEVEL_ACTIONS);
}
if (windows == NULL) {
/* we have to have at least one window.. */
window = window_create(NULL, TRUE);
}
}

View File

@ -0,0 +1,8 @@
#ifndef __FE_COMMON_CORE_H
#define __FE_COMMON_CORE_H
void fe_common_core_init(void);
void fe_common_core_deinit(void);
void fe_common_core_finish_init(void);
#endif

View File

@ -0,0 +1,266 @@
/*
fe-core-commands.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "levels.h"
#include "line-split.h"
#include "irssi-version.h"
#include "windows.h"
static gchar *ret_texts[] =
{
"Invalid parameter",
"Not enough parameters given",
"Not connected to IRC server yet",
"Not joined to any channels yet",
"Error: getsockname() failed",
"Error: listen() failed",
"Multiple matches found, be more specific",
"Nick not found",
"Not joined to such channel",
"Server not found",
"Channel not fully synchronized yet, try again after a while",
"Doing this is not a good idea. Add -YES if you really mean it",
};
static gint commands_compare(COMMAND_REC *rec, COMMAND_REC *rec2)
{
if (rec->category == NULL && rec2->category != NULL)
return -1;
if (rec2->category == NULL && rec->category != NULL)
return 1;
return strcmp(rec->cmd, rec2->cmd);
}
static void help_category(GSList *cmdlist, gint items, gint max)
{
COMMAND_REC *rec, *last;
GString *str;
GSList *tmp;
gint lines, cols, line, col, skip;
gchar *cmdbuf;
str = g_string_new(NULL);
cols = max > 65 ? 1 : (65 / max);
lines = items <= cols ? 1 : items / cols+1;
last = NULL; cmdbuf = g_malloc(max+1); cmdbuf[max] = '\0';
for (line = 0, col = 0, skip = 1, tmp = cmdlist; line < lines; last = rec, tmp = tmp->next)
{
rec = tmp->data;
if (--skip == 0)
{
skip = lines;
memset(cmdbuf, ' ', max);
memcpy(cmdbuf, rec->cmd, strlen(rec->cmd));
g_string_sprintfa(str, "%s ", cmdbuf);
cols++;
}
if (col == cols || tmp->next == NULL)
{
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, str->str);
g_string_truncate(str, 0);
col = 0; line++;
tmp = g_slist_nth(cmdlist, line-1); skip = 1;
}
}
if (str->len != 0)
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, str->str);
g_string_free(str, TRUE);
g_free(cmdbuf);
}
static int show_help(COMMAND_REC *cmd)
{
char tmpbuf[1024], *str, *path;
LINEBUF_REC *buffer = NULL;
int f, ret, recvlen;
/* helpdir/command or helpdir/category/command */
if (cmd->category == NULL)
path = g_strdup_printf("%s/%s", HELPDIR, cmd->cmd);
else
path = g_strdup_printf("%s/%s/%s", HELPDIR, cmd->category, cmd->cmd);
f = open(path, O_RDONLY);
g_free(path);
if (f == -1)
return FALSE;
/* just print to screen whatever is in the file */
do
{
recvlen = read(f, tmpbuf, sizeof(tmpbuf));
ret = line_split(tmpbuf, recvlen, &str, &buffer);
printtext(NULL, NULL, MSGLEVEL_NEVER, str);
}
while (ret > 0);
line_split_free(buffer);
close(f);
return TRUE;
}
static void cmd_help(gchar *data)
{
COMMAND_REC *rec, *last, *helpitem;
GSList *tmp, *cmdlist;
gint len, max, items, findlen;
gboolean header;
g_return_if_fail(data != NULL);
/* sort the commands list */
commands = g_slist_sort(commands, (GCompareFunc) commands_compare);
/* print command, sort by category */
cmdlist = NULL; last = NULL; header = FALSE; helpitem = NULL;
max = items = 0; findlen = strlen(data);
for (tmp = commands; tmp != NULL; last = rec, tmp = tmp->next)
{
rec = tmp->data;
if (last != NULL && rec->category != NULL &&
(last->category == NULL || strcmp(rec->category, last->category) != 0))
{
/* category changed */
if (items > 0)
{
if (!header)
{
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "Irssi commands:");
header = TRUE;
}
if (last->category != NULL)
{
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "");
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s:", last->category);
}
help_category(cmdlist, items, max);
}
g_slist_free(cmdlist); cmdlist = NULL;
items = 0; max = 0;
}
if (last != NULL && g_strcasecmp(rec->cmd, last->cmd) == 0)
continue; /* don't display same command twice */
if (strlen(rec->cmd) >= findlen && g_strncasecmp(rec->cmd, data, findlen) == 0)
{
if (rec->cmd[findlen] == '\0')
{
helpitem = rec;
break;
}
else if (strchr(rec->cmd+findlen+1, ' ') == NULL)
{
/* not a subcommand (and matches the query) */
len = strlen(rec->cmd);
if (max < len) max = len;
items++;
cmdlist = g_slist_append(cmdlist, rec);
}
}
}
if ((helpitem == NULL && items == 0) || (helpitem != NULL && !show_help(helpitem)))
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "No help for %s", data);
if (items != 0)
{
/* display the last category */
if (!header)
{
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "Irssi commands:");
header = TRUE;
}
if (last->category != NULL)
{
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "");
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s:", last->category);
}
help_category(cmdlist, items, max);
g_slist_free(cmdlist);
}
}
static void cmd_echo(const char *data, void *server, WI_ITEM_REC *item)
{
g_return_if_fail(data != NULL);
printtext(server, item == NULL ? NULL : item->name, MSGLEVEL_CRAP, "%s", data);
}
static void cmd_version(char *data)
{
g_return_if_fail(data != NULL);
if (*data == '\0')
printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, "Client: "PACKAGE" " IRSSI_VERSION);
}
static void cmd_unknown(const char *data, void *server, WI_ITEM_REC *item)
{
char *cmd;
cmd = g_strdup(data); g_strup(cmd);
printtext(server, item == NULL ? NULL : item->name, MSGLEVEL_CRAP, "Unknown command: %s", cmd);
g_free(cmd);
signal_stop();
}
static void event_cmderror(gpointer error)
{
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, ret_texts[GPOINTER_TO_INT(error)]);
}
void fe_core_commands_init(void)
{
command_bind("help", NULL, (SIGNAL_FUNC) cmd_help);
command_bind("echo", NULL, (SIGNAL_FUNC) cmd_echo);
command_bind("version", NULL, (SIGNAL_FUNC) cmd_version);
signal_add("unknown command", (SIGNAL_FUNC) cmd_unknown);
signal_add("default command", (SIGNAL_FUNC) cmd_unknown);
signal_add("error command", (SIGNAL_FUNC) event_cmderror);
}
void fe_core_commands_deinit(void)
{
command_unbind("help", (SIGNAL_FUNC) cmd_help);
command_unbind("echo", (SIGNAL_FUNC) cmd_echo);
command_unbind("version", (SIGNAL_FUNC) cmd_version);
signal_remove("unknown command", (SIGNAL_FUNC) cmd_unknown);
signal_remove("default command", (SIGNAL_FUNC) cmd_unknown);
signal_remove("error command", (SIGNAL_FUNC) event_cmderror);
}

402
src/fe-common/core/fe-log.c Normal file
View File

@ -0,0 +1,402 @@
/*
fe-log.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "server.h"
#include "levels.h"
#include "misc.h"
#include "log.h"
#include "special-vars.h"
#include "settings.h"
#include "windows.h"
#include "window-items.h"
/* close autologs after 5 minutes of inactivity */
#define AUTOLOG_INACTIVITY_CLOSE (60*5)
#define LOG_DIR_CREATE_MODE 0770
static int autolog_level;
static int autoremove_tag;
static const char *autolog_path;
static void cmd_log_open(const char *data)
{
/* /LOG OPEN [-noopen] [-autoopen] [-channels <channels>] [-window]
[-rotate hour|day|week|month] <fname> [<levels>] */
char *params, *args, *itemarg, *rotatearg, *fname, *levels;
char window[MAX_INT_STRLEN];
LOG_REC *log;
int opened, level, rotate;
args = "channels rotate";
params = cmd_get_params(data, 5 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST,
&args, &itemarg, &rotatearg, &fname, &levels);
if (*fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
rotate = LOG_ROTATE_NEVER;
if (stristr(args, "-rotate")) {
rotate = log_str2rotate(rotatearg);
if (rotate < 0) rotate = LOG_ROTATE_NEVER;
}
level = level2bits(levels);
if (level == 0) level = MSGLEVEL_ALL;
if (stristr(args, "-window")) {
/* log by window ref# */
ltoa(window, active_win->refnum);
itemarg = window;
}
log = log_create_rec(fname, level, itemarg);
if (log != NULL && log->handle == -1 && stristr(args, "-noopen") == NULL) {
/* start logging */
opened = log_start_logging(log);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
opened ? IRCTXT_LOG_OPENED :
IRCTXT_LOG_CREATE_FAILED, fname);
if (!opened) log_close(log);
}
if (log != NULL) {
if (stristr(args, "-autoopen"))
log->autoopen = TRUE;
log->rotate = rotate;
log_update(log);
}
g_free(params);
}
static void cmd_log_close(const char *data)
{
LOG_REC *log;
log = log_find(data);
if (log == NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, IRCTXT_LOG_NOT_OPEN, data);
else {
log_close(log);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_LOG_CLOSED, data);
}
}
static void cmd_log_start(const char *data)
{
LOG_REC *log;
log = log_find(data);
if (log != NULL) {
log_start_logging(log);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_LOG_OPENED, data);
}
}
static void cmd_log_stop(const char *data)
{
LOG_REC *log;
log = log_find(data);
if (log == NULL || log->handle == -1)
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, IRCTXT_LOG_NOT_OPEN, data);
else {
log_stop_logging(log);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_LOG_CLOSED, data);
}
}
static void cmd_log_list(void)
{
GSList *tmp;
char *levelstr, *items, *rotate;
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_LOG_LIST_HEADER);
for (tmp = logs; tmp != NULL; tmp = tmp->next) {
LOG_REC *rec = tmp->data;
levelstr = bits2level(rec->level);
items = rec->items == NULL ? NULL :
g_strjoinv(",", rec->items);
rotate = rec->rotate == 0 ? NULL :
g_strdup_printf(" -rotate %s", log_rotate2str(rec->rotate));
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_LOG_LIST,
rec->fname, items != NULL ? items : "",
levelstr, rotate != NULL ? rotate : "",
rec->autoopen ? " -autoopen" : "");
g_free_not_null(rotate);
g_free_not_null(items);
g_free(levelstr);
}
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_LOG_LIST_FOOTER);
}
static void cmd_log(const char *data, SERVER_REC *server, void *item)
{
command_runsub("log", data, server, item);
}
static LOG_REC *log_find_item(const char *item)
{
GSList *tmp;
for (tmp = logs; tmp != NULL; tmp = tmp->next) {
LOG_REC *rec = tmp->data;
if (rec->items != NULL && strarray_find(rec->items, item) != -1)
return rec;
}
return NULL;
}
static void cmd_window_log(const char *data)
{
/* /WINDOW LOG ON|OFF|TOGGLE [<filename>] */
LOG_REC *log;
char *params, *set, *fname, window[MAX_INT_STRLEN];
int open_log, close_log;
params = cmd_get_params(data, 2, &set, &fname);
ltoa(window, active_win->refnum);
log = log_find_item(window);
open_log = close_log = FALSE;
if (g_strcasecmp(set, "ON") == 0)
open_log = TRUE;
else if (g_strcasecmp(set, "OFF") == 0) {
close_log = TRUE;
} else if (g_strcasecmp(set, "TOGGLE") == 0) {
open_log = log == NULL;
close_log = log != NULL;
} else {
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NOT_TOGGLE);
g_free(params);
return;
}
if (open_log && log == NULL) {
/* irc.log.<windowname> or irc.log.Window<ref#> */
fname = *fname != '\0' ? g_strdup(fname) :
g_strdup_printf("~/irc.log.%s%s",
active_win->name != NULL ? active_win->name : "Window",
active_win->name != NULL ? "" : window);
log = log_create_rec(fname, MSGLEVEL_ALL, window);
if (log != NULL) log_update(log);
g_free(fname);
}
if (open_log && log != NULL) {
log_start_logging(log);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_LOG_OPENED, log->fname);
} else if (close_log && log != NULL && log->handle != -1) {
log_stop_logging(log);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_LOG_CLOSED, log->fname);
}
g_free(params);
}
/* Create log file entry to window, but don't start logging */
static void cmd_window_logfile(const char *data)
{
LOG_REC *log;
char window[MAX_INT_STRLEN];
ltoa(window, active_win->refnum);
log = log_find_item(window);
if (log != NULL) {
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLOG_FILE_LOGGING);
return;
}
log = log_create_rec(data, MSGLEVEL_ALL, window);
if (log == NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLOG_FILE, data);
else
log_update(log);
}
static void autologs_close_all(void)
{
GSList *tmp, *next;
for (tmp = logs; tmp != NULL; tmp = next) {
LOG_REC *rec = tmp->data;
next = tmp->next;
if (rec->temp) log_close(rec);
}
}
static void autolog_log(void *server, const char *target)
{
LOG_REC *log;
char *fname, *dir, *str;
log = log_find_item(target);
if (log != NULL) return;
fname = parse_special_string(autolog_path, server, NULL, target, NULL);
if (log_find(fname) == NULL) {
str = convert_home(fname);
dir = g_dirname(str);
g_free(str);
mkdir(dir, LOG_DIR_CREATE_MODE);
g_free(dir);
log = log_create_rec(fname, autolog_level, target);
if (log != NULL) {
log->temp = TRUE;
log_update(log);
log_start_logging(log);
}
}
g_free(fname);
}
/* write to logs created with /WINDOW LOG */
static void sig_printtext_stripped(void *server, const char *target, gpointer levelp, const char *text)
{
char windownum[MAX_INT_STRLEN];
WINDOW_REC *window;
LOG_REC *log;
int level;
level = GPOINTER_TO_INT(levelp);
if ((autolog_level & level) && target != NULL && *target != '\0')
autolog_log(server, target);
window = window_find_closest(server, target, level);
if (window != NULL) {
ltoa(windownum, window->refnum);
log = log_find_item(windownum);
if (log != NULL) log_write_rec(log, text);
}
}
static int sig_autoremove(void)
{
GSList *tmp, *next;
time_t removetime;
removetime = time(NULL)-AUTOLOG_INACTIVITY_CLOSE;
for (tmp = logs; tmp != NULL; tmp = next) {
LOG_REC *rec = tmp->data;
next = tmp->next;
/* FIXME: here is a small kludge - We don't want autolog to
automatically close the logs with channels, only with
private messages. However, this is CORE module and we
don't know how to figure out if item is a channel or not,
so just assume that channels are everything that don't
start with alphanumeric character. */
if (!rec->temp || rec->last > removetime ||
rec->items == NULL || !isalnum(**rec->items))
continue;
log_close(rec);
}
return 1;
}
static void sig_window_item_remove(WINDOW_REC *window, WI_ITEM_REC *item)
{
GSList *tmp;
for (tmp = logs; tmp != NULL; tmp = tmp->next) {
LOG_REC *rec = tmp->data;
if (rec->temp && g_strcasecmp(rec->items[0], item->name) == 0) {
log_close(rec);
break;
}
}
}
static void sig_log_locked(LOG_REC *log)
{
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_LOG_LOCKED, log->fname);
}
static void read_settings(void)
{
int old_autolog = autolog_level;
autolog_path = settings_get_str("autolog_path");
autolog_level = !settings_get_bool("autolog") ? 0 :
level2bits(settings_get_str("autolog_level"));
if (old_autolog && !autolog_level)
autologs_close_all();
}
void fe_log_init(void)
{
autoremove_tag = g_timeout_add(60000, (GSourceFunc) sig_autoremove, NULL);
settings_add_str("log", "autolog_path", "~/irclogs/$tag/$0.log");
settings_add_str("log", "autolog_level", "all");
settings_add_bool("log", "autolog", FALSE);
autolog_level = 0;
read_settings();
command_bind("log", NULL, (SIGNAL_FUNC) cmd_log);
command_bind("log open", NULL, (SIGNAL_FUNC) cmd_log_open);
command_bind("log close", NULL, (SIGNAL_FUNC) cmd_log_close);
command_bind("log start", NULL, (SIGNAL_FUNC) cmd_log_start);
command_bind("log stop", NULL, (SIGNAL_FUNC) cmd_log_stop);
command_bind("log ", NULL, (SIGNAL_FUNC) cmd_log_list);
command_bind("window log", NULL, (SIGNAL_FUNC) cmd_window_log);
command_bind("window logfile", NULL, (SIGNAL_FUNC) cmd_window_logfile);
signal_add_first("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped);
signal_add("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
signal_add("log locked", (SIGNAL_FUNC) sig_log_locked);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
void fe_log_deinit(void)
{
g_source_remove(autoremove_tag);
command_unbind("log", (SIGNAL_FUNC) cmd_log);
command_unbind("log open", (SIGNAL_FUNC) cmd_log_open);
command_unbind("log close", (SIGNAL_FUNC) cmd_log_close);
command_unbind("log start", (SIGNAL_FUNC) cmd_log_start);
command_unbind("log stop", (SIGNAL_FUNC) cmd_log_stop);
command_unbind("log ", (SIGNAL_FUNC) cmd_log_list);
command_unbind("window log", (SIGNAL_FUNC) cmd_window_log);
command_unbind("window logfile", (SIGNAL_FUNC) cmd_window_logfile);
signal_remove("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped);
signal_remove("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
signal_remove("log locked", (SIGNAL_FUNC) sig_log_locked);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

View File

@ -0,0 +1,96 @@
/*
fe-server.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "settings.h"
#include "network.h"
#include "levels.h"
#include "server.h"
static void sig_server_looking(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_LOOKING_UP, server->connrec->address);
}
static void sig_server_connecting(SERVER_REC *server, IPADDR *ip)
{
char ipaddr[MAX_IP_LEN];
g_return_if_fail(server != NULL);
g_return_if_fail(ip != NULL);
net_ip2host(ip, ipaddr);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CONNECTING,
server->connrec->address, ipaddr, server->connrec->port);
}
static void sig_server_connected(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_CONNECTION_ESTABLISHED, server->connrec->address);
}
static void sig_connect_failed(SERVER_REC *server, gchar *msg)
{
g_return_if_fail(server != NULL);
if (msg == NULL) {
/* no message so this wasn't unexpected fail - send
connection_lost message instead */
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_CONNECTION_LOST, server->connrec->address);
} else {
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
IRCTXT_CANT_CONNECT, server->connrec->address, server->connrec->port, msg);
}
}
static void sig_server_disconnected(SERVER_REC *server)
{
g_return_if_fail(server != NULL);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_CONNECTION_LOST, server->connrec->address);
}
void fe_server_init(void)
{
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting);
signal_add("server connected", (SIGNAL_FUNC) sig_server_connected);
signal_add("server connect failed", (SIGNAL_FUNC) sig_connect_failed);
signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
}
void fe_server_deinit(void)
{
signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_remove("server connecting", (SIGNAL_FUNC) sig_server_connecting);
signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected);
signal_remove("server connect failed", (SIGNAL_FUNC) sig_connect_failed);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
}

View File

@ -0,0 +1,215 @@
/*
fe-settings.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "server.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "levels.h"
static void set_print(SETTINGS_REC *rec)
{
const char *value;
char value_int[MAX_INT_STRLEN];
switch (rec->type) {
case SETTING_TYPE_BOOLEAN:
value = settings_get_bool(rec->key) ? "ON" : "OFF";
break;
case SETTING_TYPE_INT:
g_snprintf(value_int, sizeof(value_int), "%d", settings_get_int(rec->key));
value = value_int;
break;
case SETTING_TYPE_STRING:
value = settings_get_str(rec->key);
break;
default:
value = "";
}
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s = %s", rec->key, value);
}
static void set_boolean(const char *key, const char *value)
{
if (g_strcasecmp(value, "ON") == 0)
iconfig_set_bool("settings", key, TRUE);
else if (g_strcasecmp(value, "OFF") == 0)
iconfig_set_bool("settings", key, FALSE);
else if (g_strcasecmp(value, "TOGGLE") == 0)
iconfig_set_bool("settings", key, !settings_get_bool(key));
else
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NOT_TOGGLE);
}
static void cmd_set(char *data)
{
GSList *sets, *tmp;
char *params, *key, *value, *last_section;
int keylen, found;
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &key, &value);
keylen = strlen(key);
last_section = ""; found = 0;
sets = settings_get_sorted();
for (tmp = sets; tmp != NULL; tmp = tmp->next) {
SETTINGS_REC *rec = tmp->data;
if ((*value != '\0' && g_strcasecmp(rec->key, key) != 0) ||
(*value == '\0' && keylen != 0 && g_strncasecmp(rec->key, key, keylen) != 0))
continue;
if (strcmp(last_section, rec->section) != 0) {
/* print section */
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%_[ %s ]", rec->section);
last_section = rec->section;
}
if (*value != '\0') {
/* change the setting */
switch (rec->type) {
case SETTING_TYPE_BOOLEAN:
set_boolean(key, value);
break;
case SETTING_TYPE_INT:
iconfig_set_int("settings", key, atoi(value));
break;
case SETTING_TYPE_STRING:
iconfig_set_str("settings", key, value);
break;
}
signal_emit("setup changed", 0);
}
set_print(rec);
found = TRUE;
}
g_slist_free(sets);
if (!found)
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown setting %s", key);
g_free(params);
}
static void cmd_toggle(const char *data)
{
char *params, *key, *value;
int type;
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &key, &value);
type = settings_get_type(key);
if (type == -1)
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown setting %_%s", key);
else if (type != SETTING_TYPE_BOOLEAN)
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Setting %_%s%_ isn't boolean, use /SET", key);
else {
set_boolean(key, *value != '\0' ? value : "TOGGLE");
set_print(settings_get_record(key));
}
g_free(params);
}
static void show_aliases(const char *alias)
{
CONFIG_NODE *node;
GSList *tmp;
int aliaslen;
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_HEADER);
node = iconfig_node_traverse("aliases", FALSE);
tmp = node == NULL ? NULL : node->value;
aliaslen = strlen(alias);
for (; tmp != NULL; tmp = tmp->next) {
CONFIG_NODE *node = tmp->data;
if (node->type != NODE_TYPE_KEY)
continue;
if (aliaslen != 0 && g_strncasecmp(node->key, alias, aliaslen) != 0)
continue;
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_LINE,
node->key, node->value);
}
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_FOOTER);
}
static void alias_remove(const char *alias)
{
if (iconfig_get_str("aliases", alias, NULL) == NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIAS_NOT_FOUND, alias);
else {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIAS_REMOVED, alias);
iconfig_set_str("aliases", alias, NULL);
}
}
static void cmd_alias(const char *data)
{
char *params, *alias, *value;
g_return_if_fail(data != NULL);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &alias, &value);
if (*alias == '-') {
if (alias[1] != '\0') alias_remove(alias+1);
} else if (*alias == '\0' || *value == '\0')
show_aliases(alias);
else {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIAS_ADDED, alias);
iconfig_set_str("aliases", alias, value);
}
g_free(params);
}
static void cmd_unalias(const char *data)
{
g_return_if_fail(data != NULL);
if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
alias_remove(data);
}
void fe_settings_init(void)
{
command_bind("set", NULL, (SIGNAL_FUNC) cmd_set);
command_bind("toggle", NULL, (SIGNAL_FUNC) cmd_toggle);
command_bind("alias", NULL, (SIGNAL_FUNC) cmd_alias);
command_bind("unalias", NULL, (SIGNAL_FUNC) cmd_unalias);
}
void fe_settings_deinit(void)
{
command_unbind("set", (SIGNAL_FUNC) cmd_set);
command_unbind("toggle", (SIGNAL_FUNC) cmd_toggle);
command_unbind("alias", (SIGNAL_FUNC) cmd_alias);
command_unbind("unalias", (SIGNAL_FUNC) cmd_unalias);
}

View File

@ -0,0 +1,354 @@
/*
hilight-text.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "levels.h"
#include "server.h"
#include "hilight-text.h"
#define DEFAULT_HILIGHT_CHECK_LEVEL \
(MSGLEVEL_PUBLIC | MSGLEVEL_MSGS | MSGLEVEL_NOTICES | MSGLEVEL_ACTIONS)
static int hilight_next;
GSList *hilights;
static void hilight_add_config(HILIGHT_REC *rec)
{
CONFIG_NODE *node;
node = iconfig_node_traverse("(hilights", TRUE);
node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
config_node_set_str(node, "text", rec->text);
if (rec->level > 0) config_node_set_int(node, "level", rec->level);
if (rec->color) config_node_set_str(node, "color", rec->color);
if (rec->nickmask) config_node_set_bool(node, "nickmask", TRUE);
if (rec->fullword) config_node_set_bool(node, "fullword", TRUE);
if (rec->regexp) config_node_set_bool(node, "regexp", TRUE);
if (rec->channels != NULL && *rec->channels != NULL) {
node = config_node_section(node, "channels", NODE_TYPE_LIST);
config_node_add_list(node, rec->channels);
}
}
static void hilight_remove_config(HILIGHT_REC *rec)
{
CONFIG_NODE *node;
node = iconfig_node_traverse("hilights", FALSE);
if (node != NULL) config_node_list_remove(node, g_slist_index(hilights, rec));
}
static void hilight_destroy(HILIGHT_REC *rec)
{
g_free(rec->text);
g_free_not_null(rec->color);
g_free(rec);
}
static void hilights_destroy_all(void)
{
g_slist_foreach(hilights, (GFunc) hilight_destroy, NULL);
g_slist_free(hilights);
hilights = NULL;
}
static void hilight_remove(HILIGHT_REC *rec)
{
hilight_remove_config(rec);
hilights = g_slist_remove(hilights, rec);
hilight_destroy(rec);
}
static HILIGHT_REC *hilight_find(const char *text, char **channels)
{
GSList *tmp;
char **chan;
g_return_val_if_fail(text != NULL, NULL);
for (tmp = hilights; tmp != NULL; tmp = tmp->next) {
HILIGHT_REC *rec = tmp->data;
if (g_strcasecmp(rec->text, text) != 0)
continue;
if ((channels == NULL && rec->channels == NULL))
return rec; /* no channels - ok */
if (channels != NULL && strcmp(*channels, "*") == 0)
return rec; /* ignore channels */
if (channels == NULL || rec->channels == NULL)
continue; /* other doesn't have channels */
if (strarray_length(channels) != strarray_length(rec->channels))
continue; /* different amount of channels */
/* check that channels match */
for (chan = channels; *chan != NULL; chan++) {
if (strarray_find(rec->channels, *chan) == -1)
break;
}
if (*chan == NULL)
return rec; /* channels ok */
}
return NULL;
}
static void sig_print_text(SERVER_REC *server, const char *channel, gpointer level, const char *str)
{
if (hilight_next) {
hilight_next = FALSE;
signal_stop();
}
}
static void sig_print_text_stripped(SERVER_REC *server, const char *channel, gpointer plevel, const char *str)
{
GSList *tmp;
char *color, *newstr;
int len, level, best_match;
g_return_if_fail(str != NULL);
level = GPOINTER_TO_INT(plevel);
if (level & (MSGLEVEL_NOHILIGHT|MSGLEVEL_HILIGHT)) return;
color = NULL; best_match = 0;
for (tmp = hilights; tmp != NULL; tmp = tmp->next) {
HILIGHT_REC *rec = tmp->data;
if (rec->nickmask)
continue;
if ((level & (rec->level > 0 ? rec->level : DEFAULT_HILIGHT_CHECK_LEVEL)) == 0)
continue;
if (rec->channels != NULL && !strarray_find(rec->channels, channel))
continue;
if (rec->regexp) {
if (!regexp_match(str, rec->text))
continue;
} else if (rec->fullword) {
if (stristr_full(str, rec->text) == NULL)
continue;
} else {
if (stristr(str, rec->text) == NULL)
continue;
}
len = strlen(rec->text);
if (best_match < len) {
best_match = len;
color = rec->color;
}
}
if (best_match > 0) {
hilight_next = FALSE;
if (color == NULL) color = "\00316";
newstr = g_strconcat(isdigit(*color) ? "\003" : "", color, str, NULL);
signal_emit("print text", 4, server, channel, GINT_TO_POINTER(level | MSGLEVEL_HILIGHT), newstr);
g_free(newstr);
hilight_next = TRUE;
}
}
static void read_hilight_config(void)
{
CONFIG_NODE *node;
HILIGHT_REC *rec;
GSList *tmp;
char *text, *color;
hilights_destroy_all();
node = iconfig_node_traverse("hilights", FALSE);
if (node == NULL) return;
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
node = tmp->data;
if (node->type != NODE_TYPE_BLOCK)
continue;
text = config_node_get_str(node, "text", NULL);
if (text == NULL || *text == '\0')
continue;
rec = g_new0(HILIGHT_REC, 1);
hilights = g_slist_append(hilights, rec);
color = config_node_get_str(node, "color", NULL);
rec->text = g_strdup(text);
rec->color = color == NULL || *color == '\0' ? NULL :
g_strdup(color);
rec->level = config_node_get_int(node, "level", 0);
rec->nickmask = config_node_get_bool(node, "nickmask", FALSE);
rec->fullword = config_node_get_bool(node, "fullword", FALSE);
rec->regexp = config_node_get_bool(node, "regexp", FALSE);
node = config_node_section(node, "channels", -1);
if (node != NULL) rec->channels = config_node_get_list(node);
}
}
static void hilight_print(int index, HILIGHT_REC *rec)
{
char *chans, *levelstr;
chans = rec->channels == NULL ? NULL :
g_strjoinv(",", rec->channels);
levelstr = rec->level == 0 ? NULL :
bits2level(rec->level);
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
IRCTXT_HILIGHT_LINE, index, rec->text,
chans != NULL ? chans : "",
levelstr != NULL ? levelstr : "",
rec->nickmask ? " -nick" : "",
rec->fullword ? " -word" : "",
rec->regexp ? " -regexp" : "");
g_free_not_null(chans);
g_free_not_null(levelstr);
}
static void cmd_hilight_show(void)
{
GSList *tmp;
int index;
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_HILIGHT_HEADER);
index = 1;
for (tmp = hilights; tmp != NULL; tmp = tmp->next, index++) {
HILIGHT_REC *rec = tmp->data;
hilight_print(index, rec);
}
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_HILIGHT_FOOTER);
}
static void cmd_hilight(const char *data)
{
/* /HILIGHT [-nick | -regexp | -word] [-color <color>] [-level <level>] [-channels <channels>] <text> */
char *params, *args, *colorarg, *levelarg, *chanarg, *text;
char **channels;
HILIGHT_REC *rec;
g_return_if_fail(data != NULL);
if (*data == '\0') {
cmd_hilight_show();
return;
}
args = "color level channels";
params = cmd_get_params(data, 5 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST,
&args, &colorarg, &levelarg, &chanarg, &text);
if (*text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
channels = *chanarg == '\0' ? NULL :
g_strsplit(replace_chars(chanarg, ',', ' '), " ", -1);
rec = hilight_find(text, channels);
if (rec == NULL) {
rec = g_new0(HILIGHT_REC, 1);
rec->text = g_strdup(text);
rec->channels = channels;
} else {
g_free_and_null(rec->color);
g_strfreev(channels);
hilight_remove_config(rec);
hilights = g_slist_remove(hilights, rec);
}
hilights = g_slist_append(hilights, rec);
rec->nickmask = stristr(args, "-nick") != NULL;
rec->fullword = stristr(args, "-word") != NULL;
rec->regexp = stristr(args, "-regexp") != NULL;
rec->level = level2bits(replace_chars(levelarg, ',', ' '));
if (*colorarg != '\0') rec->color = g_strdup(colorarg);
hilight_print(g_slist_index(hilights, rec)+1, rec);
hilight_add_config(rec);
g_free(params);
}
static void cmd_dehilight(const char *data)
{
HILIGHT_REC *rec;
GSList *tmp;
if (is_numeric(data, ' ')) {
/* with index number */
tmp = g_slist_nth(hilights, atol(data)-1);
rec = tmp == NULL ? NULL : tmp->data;
} else {
/* with mask */
char *chans[2] = { "*", NULL };
rec = hilight_find(data, chans);
}
if (rec == NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_HILIGHT_NOT_FOUND, data);
else
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_HILIGHT_REMOVED, rec->text);
hilight_remove(rec);
}
void hilight_text_init(void)
{
hilight_next = FALSE;
read_hilight_config();
signal_add_first("print text", (SIGNAL_FUNC) sig_print_text);
signal_add_first("print text stripped", (SIGNAL_FUNC) sig_print_text_stripped);
signal_add("setup reread", (SIGNAL_FUNC) read_hilight_config);
command_bind("hilight", NULL, (SIGNAL_FUNC) cmd_hilight);
command_bind("dehilight", NULL, (SIGNAL_FUNC) cmd_dehilight);
}
void hilight_text_deinit(void)
{
hilights_destroy_all();
signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
signal_remove("print text stripped", (SIGNAL_FUNC) sig_print_text_stripped);
signal_remove("setup reread", (SIGNAL_FUNC) read_hilight_config);
command_unbind("hilight", (SIGNAL_FUNC) cmd_hilight);
command_unbind("dehilight", (SIGNAL_FUNC) cmd_dehilight);
}

View File

@ -0,0 +1,22 @@
#ifndef __HILIGHT_TEXT_H
#define __HILIGHT_TEXT_H
typedef struct {
char *text;
char **channels; /* if non-NULL, check the text only from these channels */
int level; /* match only messages with this level, 0=default */
char *color; /* if starts with number, \003 is automatically
inserted before it. */
int nickmask:1; /* `text 'is a nick mask - colorify the nick */
int fullword:1; /* match `text' only for full words */
int regexp:1; /* `text' is a regular expression */
} HILIGHT_REC;
extern GSList *hilights;
void hilight_text_init(void);
void hilight_text_deinit(void);
#endif

View File

@ -0,0 +1,297 @@
/*
keyboard.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "keyboard.h"
#include "windows.h"
GSList *keyinfos;
static GHashTable *keys;
KEYINFO_REC *key_info_find(gchar *id)
{
GSList *tmp;
for (tmp = keyinfos; tmp != NULL; tmp = tmp->next)
{
KEYINFO_REC *rec = tmp->data;
if (g_strcasecmp(rec->id, id) == 0)
return rec;
}
return NULL;
}
/* Bind a key for function */
void key_bind(gchar *id, gchar *data, gchar *description, gchar *key_default, SIGNAL_FUNC func)
{
KEYINFO_REC *info;
KEY_REC *rec;
g_return_if_fail(id != NULL);
g_return_if_fail(func != NULL);
/* create key info record */
info = key_info_find(id);
if (info == NULL)
{
g_return_if_fail(description != NULL);
info = g_new0(KEYINFO_REC, 1);
info->id = g_strdup(id);
info->description = g_strdup(description);
keyinfos = g_slist_append(keyinfos, info);
/* add the signal */
id = g_strconcat("key ", id, NULL);
signal_add(id, func);
g_free(id);
signal_emit("keyinfo created", 1, info);
}
if (key_default == NULL || *key_default == '\0')
{
/* just create a possible key command, don't bind it to any key yet */
return;
}
/* create/replace key record */
rec = g_hash_table_lookup(keys, key_default);
if (rec != NULL)
{
if (rec->data != NULL)
g_free(rec->data);
}
else
{
rec = g_new0(KEY_REC, 1);
info->keys = g_slist_append(info->keys, rec);
rec->key = g_strdup(key_default);
g_hash_table_insert(keys, rec->key, rec);
}
rec->info = info;
rec->data = data == NULL ? NULL : g_strdup(data);
}
static void keyinfo_remove(KEYINFO_REC *info)
{
GSList *tmp;
g_return_if_fail(info != NULL);
keyinfos = g_slist_remove(keyinfos, info);
signal_emit("keyinfo destroyed", 1, info);
/* destroy all keys */
for (tmp = info->keys; tmp != NULL; tmp = tmp->next)
{
KEY_REC *rec = tmp->data;
g_hash_table_remove(keys, rec->key);
if (rec->data != NULL) g_free(rec->data);
g_free(rec->key);
g_free(rec);
}
/* destroy key info */
g_slist_free(info->keys);
g_free(info->description);
g_free(info->id);
g_free(info);
}
/* Unbind key */
void key_unbind(gchar *id, SIGNAL_FUNC func)
{
KEYINFO_REC *info;
g_return_if_fail(id != NULL);
g_return_if_fail(func != NULL);
/* remove keys */
info = key_info_find(id);
if (info != NULL)
keyinfo_remove(info);
/* remove signal */
id = g_strconcat("key ", id, NULL);
signal_remove(id, func);
g_free(id);
}
/* Configure new key */
void key_configure_add(gchar *id, gchar *data, gchar *key)
{
KEYINFO_REC *info;
KEY_REC *rec;
g_return_if_fail(id != NULL);
g_return_if_fail(key != NULL && *key != '\0');
info = key_info_find(id);
if (info == NULL)
return;
rec = g_new0(KEY_REC, 1);
info->keys = g_slist_append(info->keys, rec);
rec->info = info;
rec->data = data == NULL ? NULL : g_strdup(data);
rec->key = g_strdup(key);
g_hash_table_insert(keys, rec->key, rec);
}
/* Remove key */
void key_configure_remove(gchar *key)
{
KEY_REC *rec;
g_return_if_fail(key != NULL);
rec = g_hash_table_lookup(keys, key);
if (rec == NULL) return;
rec->info->keys = g_slist_remove(rec->info->keys, rec);
g_hash_table_remove(keys, key);
if (rec->data != NULL) g_free(rec->data);
g_free(rec->key);
g_free(rec);
}
gboolean key_pressed(gchar *key, gpointer data)
{
KEY_REC *rec;
gboolean ret;
gchar *str;
g_return_val_if_fail(key != NULL, FALSE);
rec = g_hash_table_lookup(keys, key);
if (rec == NULL) return FALSE;
str = g_strconcat("key ", rec->info->id, NULL);
ret = signal_emit(str, 3, rec->data, data, rec->info);
g_free(str);
return ret;
}
void keyboard_save(void)
{
CONFIG_NODE *keyboard, *node, *listnode;
GSList *tmp, *tmp2;
/* remove old keyboard settings */
config_node_set_str(NULL, "(keyboard", NULL);
keyboard = iconfig_node_traverse("(keyboard", TRUE);
for (tmp = keyinfos; tmp != NULL; tmp = tmp->next) {
KEYINFO_REC *info = tmp->data;
node = config_node_section(keyboard, info->id, TRUE);
for (tmp2 = info->keys; tmp2 != NULL; tmp2 = tmp2->next) {
KEY_REC *key = tmp2->data;
listnode = config_node_section(node, NULL, NODE_TYPE_BLOCK);
if (key->data != NULL)
config_node_set_str(listnode, "data", key->data);
config_node_set_str(listnode, "key", key->key);
}
}
}
static void sig_command(gchar *data)
{
signal_emit("send command", 3, data, active_win->active_server, active_win->active);
}
void read_keyinfo(KEYINFO_REC *info, CONFIG_NODE *node)
{
GSList *tmp;
char *data, *key;
g_return_if_fail(info != NULL);
g_return_if_fail(node != NULL);
g_return_if_fail(is_node_list(node));
/* remove all old keys */
while (info->keys != NULL)
key_configure_remove(((KEY_REC *) info->keys->data)->key);
/* add the new keys */
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
node = tmp->data;
data = config_node_get_str(node->value, "data", NULL);
key = config_node_get_str(node->value, "key", NULL);
if (key != NULL) key_configure_add(info->id, data, key);
}
}
static void read_keyboard_config(void)
{
KEYINFO_REC *info;
CONFIG_NODE *node;
GSList *tmp;
while (keyinfos != NULL)
keyinfo_remove(keyinfos->data);
if (keys != NULL) g_hash_table_destroy(keys);
keys = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal);
node = iconfig_node_traverse("keyboard", FALSE);
if (node == NULL) return;
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
node = tmp->data;
if (node->key == NULL || node->value == NULL)
continue;
info = key_info_find(node->key);
if (info != NULL) read_keyinfo(info, node->value);
}
}
void keyboard_init(void)
{
keyinfos = NULL; keys = NULL;
key_bind("command", NULL, "Run any IRC command", NULL, (SIGNAL_FUNC) sig_command);
read_keyboard_config();
signal_add("setup reread", (SIGNAL_FUNC) read_keyboard_config);
}
void keyboard_deinit(void)
{
while (keyinfos != NULL)
keyinfo_remove(keyinfos->data);
g_hash_table_destroy(keys);
signal_remove("setup reread", (SIGNAL_FUNC) read_keyboard_config);
}

View File

@ -0,0 +1,40 @@
#ifndef __KEYBOARD_H
#define __KEYBOARD_H
#include "signals.h"
typedef struct
{
char *id;
char *description;
GSList *keys;
}
KEYINFO_REC;
typedef struct
{
KEYINFO_REC *info;
char *key;
void *data;
}
KEY_REC;
extern GSList *keyinfos;
void key_bind(gchar *id, gchar *data, gchar *description, gchar *key_default, SIGNAL_FUNC func);
void key_unbind(gchar *id, SIGNAL_FUNC func);
void key_configure_add(gchar *id, gchar *data, gchar *key);
void key_configure_remove(gchar *key);
KEYINFO_REC *key_info_find(gchar *id);
gboolean key_pressed(gchar *key, gpointer data);
void keyboard_save(void);
void keyboard_init(void);
void keyboard_deinit(void);
#endif

View File

@ -0,0 +1,87 @@
/*
module-formats.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "printtext.h"
FORMAT_REC fecommon_core_formats[] =
{
{ MODULE_NAME, N_("Core"), 0 },
/* ---- */
{ NULL, N_("Windows"), 0 },
{ "line_start", N_("%B-%W!%B-%n "), 0 },
{ "line_start_irssi", N_("%B-%W!%B- %WIrssi:%n "), 0 },
{ "timestamp", N_("[$[-2.0]3:$[-2.0]4] "), 6, { 1, 1, 1, 1, 1, 1 } },
{ "daychange", N_("Day changed to $[-2.0]1-$[-2.0]0 $2"), 3, { 1, 1, 1 } },
{ "talking_with", N_("You are now talking with %_$0%_"), 1, { 0 } },
/* ---- */
{ NULL, N_("Server"), 0 },
{ "looking_up", N_("Looking up %_$0%_"), 1, { 0 } },
{ "connecting", N_("Connecting to %_$0%_ %K[%n$1%K]%n port %_$2%_"), 3, { 0, 0, 1 } },
{ "connection_established", N_("Connection to %_$0%_ established"), 1, { 0 } },
{ "cant_connect", N_("Unable to connect server %_$0%_ port %_$1%_ %K[%n$2%K]"), 3, { 0, 1, 0 } },
{ "connection_lost", N_("Connection lost to %_$0%_"), 1, { 0 } },
{ "server_changed", N_("Changed to %_$2%_ server %_$1%_"), 3, { 0, 0, 0 } },
{ "unknown_server_tag", N_("Unknown server tag %_$0%_"), 1, { 0 } },
/* ---- */
{ NULL, N_("Highlighting"), 0 },
{ "hilight_header", N_("Highlights:"), 0 },
{ "hilight_line", N_("$[-4]0 $1 $2 $3$3$4$5"), 7, { 1, 0, 0, 0, 0, 0, 0 } },
{ "hilight_footer", "", 0 },
{ "hilight_not_found", N_("Highlight not found: $0"), 1, { 0 } },
{ "hilight_removed", N_("Highlight removed: $0"), 1, { 0 } },
/* ---- */
{ NULL, N_("Aliases"), 0 },
{ "alias_added", N_("Alias $0 added"), 1, { 0 } },
{ "alias_removed", N_("Alias $0 removed"), 1, { 0 } },
{ "alias_not_found", N_("No such alias: $0"), 1, { 0 } },
{ "aliaslist_header", N_("Aliases:"), 0 },
{ "aliaslist_line", N_("$[10]0 $1"), 2, { 0, 0 } },
{ "aliaslist_footer", "", 0 },
/* ---- */
{ NULL, N_("Logging"), 0 },
{ "log_opened", N_("Log file %W$0%n opened"), 1, { 0 } },
{ "log_closed", N_("Log file %W$0%n closed"), 1, { 0 } },
{ "log_create_failed", N_("Couldn't create log file %W$0"), 1, { 0 } },
{ "log_locked", N_("Log file %W$0%n is locked, probably by another running Irssi"), 1, { 0 } },
{ "log_not_open", N_("Log file %W$0%n not open"), 1, { 0 } },
{ "log_started", N_("Started logging to file %W$0"), 1, { 0 } },
{ "log_stopped", N_("Stopped logging to file %W$0"), 1, { 0 } },
{ "log_list_header", N_("Logs:"), 0 },
{ "log_list", N_("$0: $1 $2$3$4"), 5, { 0, 0, 0, 0, 0 } },
{ "log_list_footer", N_(""), 0 },
{ "windowlog_file", N_("Window LOGFILE set to $0"), 1, { 0 } },
{ "windowlog_file_logging", N_("Can't change window's logfile while log is on"), 0 },
/* ---- */
{ NULL, N_("Misc"), 0 },
{ "not_toggle", N_("Value must be either ON, OFF or TOGGLE"), 0 }
};

View File

@ -0,0 +1,62 @@
#include "printtext.h"
enum {
IRCTXT_MODULE_NAME,
IRCTXT_FILL_1,
IRCTXT_LINE_START,
IRCTXT_LINE_START_IRSSI,
IRCTXT_TIMESTAMP,
IRCTXT_DAYCHANGE,
IRCTXT_TALKING_WITH,
IRCTXT_FILL_2,
IRCTXT_LOOKING_UP,
IRCTXT_CONNECTING,
IRCTXT_CONNECTION_ESTABLISHED,
IRCTXT_CANT_CONNECT,
IRCTXT_CONNECTION_LOST,
IRCTXT_SERVER_CHANGED,
IRCTXT_UNKNOWN_SERVER_TAG,
IRCTXT_FILL_3,
IRCTXT_HILIGHT_HEADER,
IRCTXT_HILIGHT_LINE,
IRCTXT_HILIGHT_FOOTER,
IRCTXT_HILIGHT_NOT_FOUND,
IRCTXT_HILIGHT_REMOVED,
IRCTXT_FILL_4,
IRCTXT_ALIAS_ADDED,
IRCTXT_ALIAS_REMOVED,
IRCTXT_ALIAS_NOT_FOUND,
IRCTXT_ALIASLIST_HEADER,
IRCTXT_ALIASLIST_LINE,
IRCTXT_ALIASLIST_FOOTER,
IRCTXT_FILL_5,
IRCTXT_LOG_OPENED,
IRCTXT_LOG_CLOSED,
IRCTXT_LOG_CREATE_FAILED,
IRCTXT_LOG_LOCKED,
IRCTXT_LOG_NOT_OPEN,
IRCTXT_LOG_STARTED,
IRCTXT_LOG_STOPPED,
IRCTXT_LOG_LIST_HEADER,
IRCTXT_LOG_LIST,
IRCTXT_LOG_LIST_FOOTER,
IRCTXT_WINDOWLOG_FILE,
IRCTXT_WINDOWLOG_FILE_LOGGING,
IRCTXT_FILL_6,
IRCTXT_NOT_TOGGLE
};
extern FORMAT_REC fecommon_core_formats[];
#define MODULE_FORMATS fecommon_core_formats

View File

@ -0,0 +1,3 @@
#include "common.h"
#define MODULE_NAME "fe-common/core"

View File

@ -0,0 +1,115 @@
/*
nick-hilight.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "levels.h"
#include "server.h"
#include "windows.h"
#include "window-items.h"
static void sig_hilight_text(SERVER_REC *server, const char *channel, gpointer levelptr, const char *msg)
{
WINDOW_REC *window;
int level, oldlevel;
level = GPOINTER_TO_INT(levelptr);
window = window_find_closest(server, channel, level);
if (window == active_win || (level & (MSGLEVEL_NEVER|MSGLEVEL_NO_ACT|MSGLEVEL_MSGS)))
return;
oldlevel = window->new_data;
if (window->new_data < NEWDATA_TEXT) {
window->new_data = NEWDATA_TEXT;
signal_emit("window hilight", 1, window);
}
signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel));
}
static void sig_dehilight(WINDOW_REC *window, WI_ITEM_REC *item)
{
g_return_if_fail(window != NULL);
if (item != NULL && item->new_data != 0) {
item->new_data = 0;
signal_emit("window item hilight", 1, item);
}
}
static void sig_dehilight_window(WINDOW_REC *window)
{
int oldlevel;
g_return_if_fail(window != NULL);
if (window->new_data == 0)
return;
if (window->new_data != 0) {
oldlevel = window->new_data;
window->new_data = 0;
signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel));
}
signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel));
g_slist_foreach(window->items, (GFunc) sig_dehilight, NULL);
}
static void sig_hilight_window_item(WI_ITEM_REC *item)
{
WINDOW_REC *window;
GSList *tmp;
int level, oldlevel;
window = window_item_window(item); level = 0;
for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
item = tmp->data;
if (item->new_data > level)
level = item->new_data;
}
oldlevel = window->new_data;
if (window->new_data < level || level == 0) {
window->new_data = level;
signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel));
}
signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel));
}
void nick_hilight_init(void)
{
signal_add("print text", (SIGNAL_FUNC) sig_hilight_text);
signal_add("window item changed", (SIGNAL_FUNC) sig_dehilight);
signal_add("window changed", (SIGNAL_FUNC) sig_dehilight_window);
signal_add("window dehilight", (SIGNAL_FUNC) sig_dehilight_window);
signal_add("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item);
}
void nick_hilight_deinit(void)
{
signal_remove("print text", (SIGNAL_FUNC) sig_hilight_text);
signal_remove("window item changed", (SIGNAL_FUNC) sig_dehilight);
signal_remove("window changed", (SIGNAL_FUNC) sig_dehilight_window);
signal_remove("window dehilight", (SIGNAL_FUNC) sig_dehilight_window);
signal_remove("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item);
}

View File

@ -0,0 +1,858 @@
/*
printtext.c : irssi
Copyright (C) 1999 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "special-vars.h"
#include "settings.h"
#include "levels.h"
#include "server.h"
#include "translation.h"
#include "themes.h"
#include "windows.h"
static gboolean toggle_show_timestamps, toggle_show_msgs_timestamps, toggle_hide_text_style;
static gint printtag;
static gchar ansitab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
static gint signal_gui_print_text;
static gint signal_print_text_stripped;
static gint signal_print_text;
static gint signal_print_text_finished;
void printbeep(void)
{
signal_emit_id(signal_gui_print_text, 6, active_win, NULL, NULL,
GINT_TO_POINTER(PRINTFLAG_BEEP), "", MSGLEVEL_NEVER);
}
/* parse ANSI color string */
static char *convert_ansi(char *str, int *fgcolor, int *bgcolor, int *flags)
{
gchar *start;
gint fg, bg, fl, num;
if (*str != '[') return str;
start = str;
fg = *fgcolor < 0 ? current_theme->default_color : *fgcolor;
bg = *bgcolor < 0 ? -1 : *bgcolor;
fl = *flags;
str++; num = 0;
for (;; str++)
{
if (*str == '\0') return start;
if (isdigit((gint) *str))
{
num = num*10 + (*str-'0');
continue;
}
if (*str != ';' && *str != 'm') return start;
switch (num)
{
case 0:
/* reset colors back to default */
fg = current_theme->default_color;
bg = -1;
break;
case 1:
/* hilight */
fg |= 8;
break;
case 5:
/* blink */
bg = bg == -1 ? 8 : bg | 8;
break;
case 7:
/* reverse */
fl |= PRINTFLAG_REVERSE;
break;
default:
if (num >= 30 && num <= 37)
fg = (fg & 0xf8) + ansitab[num-30];
if (num >= 40 && num <= 47)
{
if (bg == -1) bg = 0;
bg = (bg & 0xf8) + ansitab[num-40];
}
break;
}
num = 0;
if (*str == 'm')
{
if (!toggle_hide_text_style)
{
*fgcolor = fg;
*bgcolor = bg == -1 ? -1 : bg;
*flags = fl;
}
str++;
break;
}
}
return str;
}
#define IN_COLOR_CODE 2
#define IN_SECOND_CODE 4
char *strip_codes(const char *input)
{
const char *p;
gchar *str, *out;
gint loop_state;
loop_state = 0;
out = str = g_strdup(input);
for (p = input; *p != '\0'; p++) /* Going through the string till the end k? */
{
if (*p == '\003')
{
if (p[1] < 17 && p[1] > 0)
{
p++;
if (p[1] < 17 && p[1] > 0) p++;
continue;
}
loop_state = IN_COLOR_CODE;
continue;
}
if (loop_state & IN_COLOR_CODE)
{
if (isdigit( (gint) *p )) continue;
if (*p != ',' || (loop_state & IN_SECOND_CODE))
{
/* we're no longer in a color code */
*out++ = *p;
loop_state &= ~IN_COLOR_CODE|IN_SECOND_CODE;
continue;
}
/* we're in the second code */
loop_state |= IN_SECOND_CODE;
continue;
}
/* we're not in a color code that means we should add the character */
if (*p == 4 && p[1] != '\0' && p[2] != '\0')
{
p += 2;
continue;
}
if (*p == 2 || *p == 22 || *p == 27 || *p == 31 || *p == 15)
continue;
*out++ = *p;
}
*out = '\0';
return str;
}
static gboolean expand_styles(GString *out, char format, void *server, const char *channel, int level)
{
static const char *backs = "01234567";
static const char *fores = "krgybmcw";
static const char *boldfores = "KRGYBMCW";
gchar *p;
/* p/P -> m/M */
if (format == 'p')
format = 'm';
else if (format == 'P')
format = 'M';
switch (format)
{
case 'U':
/* Underline on/off */
g_string_append_c(out, 4);
g_string_append_c(out, -1);
g_string_append_c(out, 2);
break;
case '9':
case '_':
/* bold on/off */
g_string_append_c(out, 4);
g_string_append_c(out, -1);
g_string_append_c(out, 1);
break;
case '8':
/* reverse */
g_string_append_c(out, 4);
g_string_append_c(out, -1);
g_string_append_c(out, 3);
break;
case '%':
g_string_append_c(out, '%');
break;
case ':':
/* Newline */
printtext(server, channel, level, out->str);
g_string_truncate(out, 0);
break;
case '|':
/* Indent here mark */
g_string_append_c(out, 4);
g_string_append_c(out, -1);
g_string_append_c(out, 4);
break;
case 'F':
/* flashing - ignore */
break;
case 'N':
/* don't put clear-color tag at the end of the output - ignore */
break;
case 'n':
/* default color */
g_string_append_c(out, 4);
g_string_append_c(out, -1);
g_string_append_c(out, -1);
break;
default:
/* check if it's a background color */
p = strchr(backs, format);
if (p != NULL)
{
g_string_append_c(out, 4);
g_string_append_c(out, -2);
g_string_append_c(out, ansitab[(gint) (p-backs)]+1);
break;
}
/* check if it's a foreground color */
p = strchr(fores, format);
if (p != NULL)
{
g_string_append_c(out, 4);
g_string_append_c(out, ansitab[(gint) (p-fores)]+1);
g_string_append_c(out, -2);
break;
}
/* check if it's a bold foreground color */
p = strchr(boldfores, format);
if (p != NULL)
{
g_string_append_c(out, 4);
g_string_append_c(out, 8+ansitab[(gint) (p-boldfores)]+1);
g_string_append_c(out, -2);
break;
}
return FALSE;
}
return TRUE;
}
static void read_arglist(va_list va, FORMAT_REC *format,
char **arglist, int arglist_size,
char *buffer, int buffer_size)
{
int num, len, bufpos;
bufpos = 0;
for (num = 0; num < format->params && num < arglist_size; num++) {
switch (format->paramtypes[num]) {
case FORMAT_STRING:
arglist[num] = (char *) va_arg(va, char *);
if (arglist[num] == NULL) {
g_warning("output_format_text_args() : parameter %d is NULL", num);
arglist[num] = "";
}
break;
case FORMAT_INT: {
int d = (int) va_arg(va, int);
if (bufpos >= buffer_size) {
arglist[num] = "";
break;
}
arglist[num] = buffer+bufpos;
len = g_snprintf(buffer+bufpos, buffer_size-bufpos,
"%d", d);
bufpos += len+1;
break;
}
case FORMAT_LONG: {
long l = (long) va_arg(va, long);
if (bufpos >= buffer_size) {
arglist[num] = "";
break;
}
arglist[num] = buffer+bufpos;
len = g_snprintf(buffer+bufpos, buffer_size-bufpos,
"%ld", l);
bufpos += len+1;
break;
}
case FORMAT_FLOAT: {
double f = (double) va_arg(va, double);
if (bufpos >= buffer_size) {
arglist[num] = "";
break;
}
arglist[num] = buffer+bufpos;
len = g_snprintf(buffer+bufpos, buffer_size-bufpos,
"%0.2f", f);
bufpos += len+1;
break;
}
}
}
}
static void output_format_text_args(GString *out, void *server, const char *channel, int level, FORMAT_REC *format, const char *text, va_list args)
{
char *arglist[10];
char buffer[200]; /* should be enough? (won't overflow even if it isn't) */
const char *str;
char code;
int need_free;
str = current_theme != NULL && text != NULL ? text : format->def;
/* read all optional arguments to arglist[] list
so they can be used in any order.. */
read_arglist(args, format,
arglist, sizeof(arglist)/sizeof(void*),
buffer, sizeof(buffer));
code = 0;
while (*str != '\0') {
if (code == '%') {
/* color code */
if (!expand_styles(out, *str, server, channel, level)) {
g_string_append_c(out, '%');
g_string_append_c(out, '%');
g_string_append_c(out, *str);
}
code = 0;
} else if (code == '$') {
/* argument */
char *ret;
ret = parse_special((char **) &str, active_win->active_server, active_win->active, arglist, &need_free, NULL);
if (ret != NULL) {
g_string_append(out, ret);
if (need_free) g_free(ret);
}
code = 0;
} else {
if (*str == '%' || *str == '$')
code = *str;
else
g_string_append_c(out, *str);
}
str++;
}
}
static void output_format_text(GString *out, void *server, const char *channel, int level, int formatnum, ...)
{
MODULE_THEME_REC *theme;
va_list args;
theme = g_hash_table_lookup(current_theme->modules, MODULE_FORMATS->tag);
va_start(args, formatnum);
output_format_text_args(out, server, channel, level,
&MODULE_FORMATS[formatnum],
theme == NULL ? NULL : theme->format[formatnum], args);
va_end(args);
}
static void add_timestamp(WINDOW_REC *window, GString *out, void *server, const char *channel, int level)
{
time_t t;
struct tm *tm;
GString *tmp;
if (!(level != MSGLEVEL_NEVER && (toggle_show_timestamps || (toggle_show_msgs_timestamps && (level & MSGLEVEL_MSGS) != 0))))
return;
t = time(NULL);
if ((t - window->last_timestamp) < settings_get_int("timestamp_timeout")) {
window->last_timestamp = t;
return;
}
window->last_timestamp = t;
tmp = g_string_new(NULL);
tm = localtime(&t);
output_format_text(tmp, server, channel, level, IRCTXT_TIMESTAMP,
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
/* insert the timestamp right after \n */
g_string_prepend(out, tmp->str);
g_string_free(tmp, TRUE);
}
static void new_line_stuff(GString *out, void *server, const char *channel, int level)
{
if ((level & (MSGLEVEL_CLIENTERROR|MSGLEVEL_CLIENTNOTICE)) != 0)
output_format_text(out, server, channel, level, IRCTXT_LINE_START_IRSSI);
else if ((level & (MSGLEVEL_MSGS|MSGLEVEL_PUBLIC|MSGLEVEL_NOTICES|MSGLEVEL_SNOTES|MSGLEVEL_CTCPS|MSGLEVEL_ACTIONS|MSGLEVEL_DCC|MSGLEVEL_CLIENTCRAP)) == 0 && level != MSGLEVEL_NEVER)
output_format_text(out, server, channel, level, IRCTXT_LINE_START);
}
/* Write text to channel - convert color codes */
void printtext(void *server, const char *channel, int level, const char *str, ...)
{
va_list args;
GString *out;
gchar *tmpstr;
gint pros;
g_return_if_fail(str != NULL);
va_start(args, str);
pros = 0;
out = g_string_new(NULL);
new_line_stuff(out, server, channel, level);
for (; *str != '\0'; str++)
{
if (*str != '%')
{
g_string_append_c(out, *str);
continue;
}
if (*++str == '\0') break;
switch (*str)
{
/* standard parameters */
case 's':
{
gchar *s = (gchar *) va_arg(args, gchar *);
if (s && *s) g_string_append(out, s);
break;
}
case 'd':
{
gint d = (gint) va_arg(args, gint);
g_string_sprintfa(out, "%d", d);
break;
}
case 'f':
{
gdouble f = (gdouble) va_arg(args, gdouble);
g_string_sprintfa(out, "%0.2f", f);
break;
}
case 'u':
{
guint d = (guint) va_arg(args, guint);
g_string_sprintfa(out, "%u", d);
break;
}
case 'l':
{
gulong d = (gulong) va_arg(args, gulong);
if (*++str != 'd' && *str != 'u')
{
g_string_sprintfa(out, "%ld", d);
str--;
}
else
{
if (*str == 'd')
g_string_sprintfa(out, "%ld", d);
else
g_string_sprintfa(out, "%lu", d);
}
break;
}
default:
if (!expand_styles(out, *str, server, channel, level))
{
g_string_append_c(out, '%');
g_string_append_c(out, *str);
}
break;
}
}
va_end(args);
/* send the plain text version for logging.. */
tmpstr = strip_codes(out->str);
signal_emit_id(signal_print_text_stripped, 4, server, channel, GINT_TO_POINTER(level), tmpstr);
g_free(tmpstr);
signal_emit_id(signal_print_text, 4, server, channel, GINT_TO_POINTER(level), out->str);
g_string_free(out, TRUE);
}
void printformat_format(FORMAT_REC *formats, void *server, const char *channel, int level, int formatnum, ...)
{
MODULE_THEME_REC *theme;
GString *out;
va_list args;
va_start(args, formatnum);
out = g_string_new(NULL);
theme = g_hash_table_lookup(current_theme->modules, formats->tag);
output_format_text_args(out, server, channel, level,
&formats[formatnum],
theme == NULL ? NULL : theme->format[formatnum], args);
if (out->len > 0) printtext(server, channel, level, "%s", out->str);
g_string_free(out, TRUE);
va_end(args);
}
static void newline(WINDOW_REC *window)
{
window->lines++;
if (window->lines != 1) {
signal_emit_id(signal_gui_print_text, 6, window,
GINT_TO_POINTER(-1), GINT_TO_POINTER(-1),
GINT_TO_POINTER(0), "\n", GINT_TO_POINTER(-1));
}
}
static void sig_print_text(void *server, const char *target, gpointer level, const char *text)
{
WINDOW_REC *window;
GString *out;
gchar *dup, *ptr, type, *str;
gint fgcolor, bgcolor;
gint flags;
g_return_if_fail(text != NULL);
window = window_find_closest(server, target, GPOINTER_TO_INT(level));
g_return_if_fail(window != NULL);
flags = 0; fgcolor = -1; bgcolor = -1; type = '\0';
newline(window);
out = g_string_new(text);
if (server != NULL && servers != NULL && servers->next != NULL &&
(window->active == NULL || window->active->server != server))
{
/* connected to more than one server and active server isn't the
same where the message came or we're in status/msgs/empty window -
prefix with a [server tag] */
gchar *str;
str = g_strdup_printf("[%s] ", ((SERVER_REC *) server)->tag);
g_string_prepend(out, str);
g_free(str);
}
add_timestamp(window, out, server, target, GPOINTER_TO_INT(level));
dup = str = out->str;
g_string_free(out, FALSE);
while (*str != '\0')
{
for (ptr = str; *ptr != '\0'; ptr++)
{
if (*ptr == 2 || *ptr == 3 || *ptr == 4 || *ptr == 6 || *ptr == 7 || *ptr == 15 || *ptr == 22 || *ptr == 27 || *ptr == 31)
{
type = *ptr;
*ptr++ = '\0';
break;
}
*ptr = (gchar) translation_in[(gint) (guchar) *ptr];
}
if (type == 7)
{
/* bell */
if (settings_get_bool("toggle_bell_beeps"))
flags |= PRINTFLAG_BEEP;
}
if (*str != '\0' || flags & PRINTFLAG_BEEP)
{
signal_emit_id(signal_gui_print_text, 6, window,
GINT_TO_POINTER(fgcolor), GINT_TO_POINTER(bgcolor),
GINT_TO_POINTER(flags), str, level);
flags &= ~(PRINTFLAG_BEEP|PRINTFLAG_INDENT);
}
if (*ptr == '\0') break;
switch (type)
{
case 2:
/* bold */
if (!toggle_hide_text_style)
flags ^= PRINTFLAG_BOLD;
break;
case 6:
/* blink */
if (!toggle_hide_text_style)
flags ^= PRINTFLAG_BLINK;
break;
case 15:
/* remove all styling */
flags &= PRINTFLAG_BEEP;
fgcolor = bgcolor = -1;
break;
case 22:
/* reverse */
if (!toggle_hide_text_style)
flags ^= PRINTFLAG_REVERSE;
break;
case 31:
/* underline */
if (!toggle_hide_text_style)
flags ^= PRINTFLAG_UNDERLINE;
case 27:
/* ansi color code */
ptr = convert_ansi(ptr, &fgcolor, &bgcolor, &flags);
break;
case 4:
/* user specific colors */
flags &= ~PRINTFLAG_MIRC_COLOR;
if ((signed char) *ptr == -1)
{
ptr++;
if ((signed char) *ptr == -1)
{
fgcolor = bgcolor = -1;
flags &= PRINTFLAG_INDENT;
}
else if (*ptr == 1)
flags ^= PRINTFLAG_BOLD;
else if (*ptr == 2)
flags ^= PRINTFLAG_UNDERLINE;
else if (*ptr == 3)
flags ^= PRINTFLAG_REVERSE;
else if (*ptr == 4)
flags |= PRINTFLAG_INDENT;
}
else
{
if ((signed char) *ptr != -2)
{
fgcolor = (guchar) *ptr-1;
if (fgcolor <= 7)
flags &= ~PRINTFLAG_BOLD;
else
{
/* bold */
if (fgcolor != 8) fgcolor -= 8;
flags |= PRINTFLAG_BOLD;
}
}
ptr++;
if ((signed char) *ptr != -2)
bgcolor = (signed char) *ptr == -1 ? -1 : *ptr-1;
}
ptr++;
break;
case 3:
if (*ptr < 17)
{
/* mostly just for irssi's internal use.. */
fgcolor = (*ptr++)-1;
if (*ptr == 0 || *ptr >= 17)
bgcolor = -1;
else
bgcolor = (*ptr++)-1;
if (fgcolor & 8)
flags |= PRINTFLAG_BOLD;
else
flags &= ~PRINTFLAG_BOLD;
break;
}
/* MIRC color */
if (toggle_hide_text_style)
{
/* don't show them. */
if (isdigit((gint) *ptr))
{
ptr++;
if (isdigit((gint) *ptr)) ptr++;
if (*ptr == ',')
{
ptr++;
if (isdigit((gint) *ptr))
{
ptr++;
if (isdigit((gint) *ptr)) ptr++;
}
}
}
break;
}
flags |= PRINTFLAG_MIRC_COLOR;
if (!isdigit((gint) *ptr) && *ptr != ',')
{
fgcolor = -1;
bgcolor = -1;
}
else
{
/* foreground color */
if (*ptr != ',')
{
fgcolor = *ptr++-'0';
if (isdigit((gint) *ptr))
fgcolor = fgcolor*10 + (*ptr++-'0');
}
if (*ptr == ',')
{
/* back color */
bgcolor = 0;
if (!isdigit((gint) *++ptr))
bgcolor = -1;
else
{
bgcolor = *ptr++-'0';
if (isdigit((gint) *ptr))
bgcolor = bgcolor*10 + (*ptr++-'0');
}
}
}
break;
}
str = ptr;
}
g_free(dup);
signal_emit_id(signal_print_text_finished, 1, window);
}
static int sig_check_daychange(void)
{
static gint lastday = -1;
GSList *tmp;
time_t t;
struct tm *tm;
if (!toggle_show_timestamps)
{
/* display day change notice only when using timestamps */
return TRUE;
}
t = time(NULL);
tm = localtime(&t);
if (lastday == -1)
{
/* First check, don't display. */
lastday = tm->tm_mday;
return TRUE;
}
if (tm->tm_mday == lastday)
return TRUE;
/* day changed, print notice about it to every window */
for (tmp = windows; tmp != NULL; tmp = tmp->next)
{
WINDOW_REC *win = tmp->data;
printformat(win->active->server, win->active->name, MSGLEVEL_NEVER,
IRCTXT_DAYCHANGE, tm->tm_mday, tm->tm_mon+1, 1900+tm->tm_year);
}
lastday = tm->tm_mday;
return TRUE;
}
static void sig_gui_dialog(const char *type, const char *text)
{
char **lines, **tmp;
if (g_strcasecmp(type, "warning") == 0)
type = _("%_Warning:%_ %s");
else if (g_strcasecmp(type, "error") == 0)
type = _("%_Error:%_ %s");
else
type = "%s";
lines = g_strsplit(text, "\n", -1);
for (tmp = lines; *tmp != NULL; tmp++)
printtext(NULL, NULL, MSGLEVEL_NEVER, type, *tmp);
g_strfreev(lines);
}
static void read_settings(void)
{
toggle_show_timestamps = settings_get_bool("toggle_show_timestamps");
toggle_show_msgs_timestamps = settings_get_bool("toggle_show_msgs_timestamps");
toggle_hide_text_style = settings_get_bool("toggle_hide_text_style");
}
void printtext_init(void)
{
settings_add_int("misc", "timestamp_timeout", 0);
signal_gui_print_text = module_get_uniq_id_str("signals", "gui print text");
signal_print_text_stripped = module_get_uniq_id_str("signals", "print text stripped");
signal_print_text = module_get_uniq_id_str("signals", "print text");
signal_print_text_finished = module_get_uniq_id_str("signals", "print text finished");
read_settings();
printtag = g_timeout_add(30000, (GSourceFunc) sig_check_daychange, NULL);
signal_add("print text", (SIGNAL_FUNC) sig_print_text);
signal_add("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
command_bind("beep", NULL, (SIGNAL_FUNC) printbeep);
}
void printtext_deinit(void)
{
g_source_remove(printtag);
signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
signal_remove("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
command_unbind("beep", (SIGNAL_FUNC) printbeep);
}

View File

@ -0,0 +1,61 @@
#ifndef __PRINTTEXT_H
#define __PRINTTEXT_H
enum {
FORMAT_STRING,
FORMAT_INT,
FORMAT_LONG,
FORMAT_FLOAT
};
typedef struct {
char *tag;
char *def;
int params;
int paramtypes[10];
} FORMAT_REC;
#define PRINTFLAG_BOLD 0x01
#define PRINTFLAG_REVERSE 0x02
#define PRINTFLAG_UNDERLINE 0x04
#define PRINTFLAG_BEEP 0x08
#define PRINTFLAG_BLINK 0x10
#define PRINTFLAG_MIRC_COLOR 0x20
#define PRINTFLAG_INDENT 0x40
/* printformat(...) = printformat_format(module_formats, ...)
Could this be any harder? :) With GNU C compiler and C99 compilers,
use #define. With others use either inline functions if they are
supported or static functions if they are not..
*/
#ifdef __GNUC__
/* GCC */
# define printformat(server, channel, level, formatnum...) \
printformat_format(MODULE_FORMATS, server, channel, level, ##formatnum)
#elif defined (_ISOC99_SOURCE)
/* C99 */
# define printformat(server, channel, level, formatnum, ...) \
printformat_format(MODULE_FORMATS, server, channel, level, formatnum, __VA_ARGS__)
#else
/* inline/static */
#ifdef G_CAN_INLINE
inline
#else
static
#endif
void printformat(void *server, const char *channel, int level, int formatnum, ...)
{
printformat_format(MODULE_FORMATS, server, channel, level, ##formatnum);
}
#endif
void printformat_format(FORMAT_REC *formats, void *server, const char *channel, int level, int formatnum, ...);
void printtext(void *server, const char *channel, int level, const char *str, ...);
void printbeep(void);
void printtext_init(void);
void printtext_deinit(void);
#endif

278
src/fe-common/core/themes.c Normal file
View File

@ -0,0 +1,278 @@
/*
themes.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "printtext.h"
#include "themes.h"
GSList *themes;
THEME_REC *current_theme;
THEME_REC *theme_create(const char *path, const char *name)
{
THEME_REC *rec;
g_return_val_if_fail(path != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL);
rec = g_new0(THEME_REC, 1);
rec->path = g_strdup(path);
rec->name = g_strdup(name);
rec->modules = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
signal_emit("theme created", 1, rec);
return rec;
}
static void theme_destroy_hash(const char *key, MODULE_THEME_REC *rec)
{
int n, max;
max = strarray_length(rec->formatlist);
for (n = 0; n < max; n++)
if (rec->format[n] != NULL)
g_free(rec->format[n]);
g_free(rec->format);
g_strfreev(rec->formatlist);
g_free(rec->name);
g_free(rec);
}
void theme_destroy(THEME_REC *rec)
{
signal_emit("theme destroyed", 1, rec);
g_hash_table_foreach(rec->modules, (GHFunc) theme_destroy_hash, NULL);
g_hash_table_destroy(rec->modules);
if (rec->bg_pixmap != NULL) g_free(rec->bg_pixmap);
if (rec->font != NULL) g_free(rec->font);
g_free(rec->path);
g_free(rec->name);
g_free(rec);
}
static THEME_REC *theme_find(const char *name)
{
GSList *tmp;
for (tmp = themes; tmp != NULL; tmp = tmp->next) {
THEME_REC *rec = tmp->data;
if (g_strcasecmp(rec->name, name) == 0)
return rec;
}
return NULL;
}
/* Add all *.theme files from directory to themes */
static void find_themes(gchar *path)
{
DIR *dirp;
struct dirent *dp;
char *fname, *name;
int len;
dirp = opendir(path);
if (dirp == NULL) return;
while ((dp = readdir(dirp)) != NULL) {
len = strlen(dp->d_name);
if (len <= 6 || strcmp(dp->d_name+len-6, ".theme") != 0)
continue;
name = g_strndup(dp->d_name, strlen(dp->d_name)-6);
if (!theme_find(name)) {
fname = g_strdup_printf("%s/%s", path, dp->d_name);
themes = g_slist_append(themes, theme_create(fname, name));
g_free(fname);
}
g_free(name);
}
closedir(dirp);
}
/* Read module texts into theme */
static void theme_read_module_texts(const char *hashkey, MODULE_THEME_REC *rec, CONFIG_REC *config)
{
CONFIG_NODE *formats;
GSList *tmp;
char **flist;
int n;
formats = config_node_traverse(config, "moduleformats", FALSE);
if (formats == NULL) return;
for (tmp = formats->value; tmp != NULL; tmp = tmp->next) {
CONFIG_NODE *node = tmp->data;
if (node->key == NULL || node->value == NULL)
continue;
for (n = 0, flist = rec->formatlist; *flist != NULL; flist++, n++) {
if (g_strcasecmp(*flist, node->key) == 0) {
rec->format[n] = g_strdup(node->value);
break;
}
}
}
}
static int theme_read(THEME_REC *theme, const char *path)
{
MODULE_THEME_REC *mrec;
CONFIG_REC *config;
CONFIG_NODE *formats;
GSList *tmp;
char *value;
int errors;
config = config_open(path, -1);
if (config == NULL) {
/* didn't exist or no access? */
theme->default_color = 15;
return FALSE;
}
errors = config_parse(config) == -1;
/* default color */
theme->default_color = config_get_int(config, NULL, "default_color", 15);
/* get font */
value = config_get_str(config, NULL, "font", NULL);
theme->font = (value == NULL || *value == '\0') ? NULL : g_strdup(value);
/* get background pixmap */
value = config_get_str(config, NULL, "bg_pixmap", NULL);
theme->bg_pixmap = (value == NULL || *value == '\0') ? NULL : g_strdup(value);
/* get background pixmap properties */
if (config_get_bool(config, NULL, "bg_scrollable", FALSE))
theme->flags |= THEME_FLAG_BG_SCROLLABLE;
if (config_get_bool(config, NULL, "bg_scaled", TRUE))
theme->flags |= THEME_FLAG_BG_SCALED;
if (config_get_bool(config, NULL, "bg_shaded", FALSE))
theme->flags |= THEME_FLAG_BG_SHADED;
/* Read modules that are defined in this theme. */
formats = config_node_traverse(config, "modules", FALSE);
if (formats != NULL) {
for (tmp = formats->value; tmp != NULL; tmp = tmp->next) {
CONFIG_NODE *node = tmp->data;
if (node->key == NULL || node->value == NULL)
continue;
mrec = g_new0(MODULE_THEME_REC, 1);
mrec->name = g_strdup(node->key);
mrec->formatlist = g_strsplit(node->value, " ", -1);
mrec->format = g_new0(char*, strarray_length(mrec->formatlist));
g_hash_table_insert(theme->modules, mrec->name, mrec);
}
}
/* Read the texts inside the plugin */
g_hash_table_foreach(theme->modules, (GHFunc) theme_read_module_texts, config);
if (errors) {
/* errors fixed - save the theme */
if (config_write(config, NULL, 0660) == -1) {
/* we probably tried to save to global directory
where we didn't have access.. try saving it to
home dir instead. */
char *str;
/* check that we really didn't try to save
it to home dir.. */
str = g_strdup_printf("%s/.irssi/", g_get_home_dir());
if (strncmp(path, str, strlen(str)) != 0) {
g_free(str);
str = g_strdup_printf("%s/.irssi/%s", g_get_home_dir(), g_basename(path));
config_write(config, str, 0660);
}
g_free(str);
}
}
config_close(config);
return errors;
}
static void sig_formats_error(void)
{
signal_emit("gui dialog", 2, "warning",
"Your theme(s) had some old format strings, "
"these have been changed back to their default values.");
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_formats_error);
}
void themes_init(void)
{
THEME_REC *rec;
GSList *tmp;
const char *value;
char *str;
int errors;
/* first there's default theme.. */
str = g_strdup_printf("%s/.irssi/default.theme", g_get_home_dir());
current_theme = theme_create(str, "default");
current_theme->default_color = 15;
themes = g_slist_append(NULL, current_theme);
g_free(str);
/* read list of themes */
str = g_strdup_printf("%s/.irssi", g_get_home_dir());
find_themes(str);
g_free(str);
find_themes(SYSCONFDIR"/irssi");
/* read formats for all themes */
errors = FALSE;
for (tmp = themes; tmp != NULL; tmp = tmp->next) {
rec = tmp->data;
if (theme_read(rec, rec->path))
errors = TRUE;
}
if (errors)
signal_add("irssi init finished", (SIGNAL_FUNC) sig_formats_error);
/* find the current theme to use */
value = settings_get_str("current_theme");
rec = theme_find(value);
if (rec != NULL) current_theme = rec;
}
void themes_deinit(void)
{
/* free memory used by themes */
g_slist_foreach(themes, (GFunc) theme_destroy, NULL);
g_slist_free(themes);
themes = NULL;
}

View File

@ -0,0 +1,40 @@
#ifndef __THEMES_H
#define __THEMES_H
#define THEME_FLAG_BG_SCROLLABLE 0x0001
#define THEME_FLAG_BG_SCALED 0x0002
#define THEME_FLAG_BG_SHADED 0x0004
typedef struct
{
char *name;
char **formatlist;
char **format;
}
MODULE_THEME_REC;
typedef struct {
char *path;
char *name;
int default_color;
char *bg_pixmap;
char *font;
int flags;
GHashTable *modules;
gpointer gui_data;
} THEME_REC;
extern GSList *themes;
extern THEME_REC *current_theme;
THEME_REC *theme_create(const char *path, const char *name);
void theme_destroy(THEME_REC *rec);
void themes_init(void);
void themes_deinit(void);
#endif

View File

@ -0,0 +1,122 @@
/*
translation.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "line-split.h"
#include "misc.h"
#include "settings.h"
unsigned char translation_in[256], translation_out[256];
void translation_reset(void)
{
int n;
for (n = 0; n < 256; n++)
translation_in[n] = (unsigned char) n;
for (n = 0; n < 256; n++)
translation_out[n] = (unsigned char) n;
}
void translate_output(char *text)
{
while (*text != '\0') {
*text = (char) translation_out[(int) (unsigned char) *text];
text++;
}
}
#define gethex(a) \
(isdigit(a) ? ((a)-'0') : (toupper(a)-'A'+10))
void translation_parse_line(const char *str, int *pos)
{
const char *ptr;
int value;
for (ptr = str; *ptr != '\0'; ptr++) {
if (ptr[0] != '0' || ptr[1] != 'x')
break;
ptr += 2;
value = (gethex(ptr[0]) << 4) + gethex(ptr[1]);
if (*pos < 256)
translation_in[*pos] = (unsigned char) value;
else
translation_out[*pos-256] = (unsigned char) value;
(*pos)++;
ptr += 2;
if (*ptr != ',') break;
}
}
int translation_read(const char *file)
{
char tmpbuf[1024], *str, *path;
LINEBUF_REC *buffer;
int f, pos, ret, recvlen;
g_return_val_if_fail(file != NULL, FALSE);
path = convert_home(file);
f = open(file, O_RDONLY);
g_free(path);
if (f == -1) return FALSE;
pos = 0; buffer = NULL;
while (pos < 512) {
recvlen = read(f, tmpbuf, sizeof(tmpbuf));
ret = line_split(tmpbuf, recvlen, &str, &buffer);
if (ret <= 0) break;
translation_parse_line(str, &pos);
}
line_split_free(buffer);
close(f);
if (pos != 512)
translation_reset();
return pos == 512;
}
static void read_settings(void)
{
translation_read(settings_get_str("translation"));
}
void translation_init(void)
{
translation_reset();
settings_add_str("misc", "translation", "");
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
read_settings();
}
void translation_deinit(void)
{
read_settings();
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

View File

@ -0,0 +1,12 @@
#ifndef __TRANSLATION_H
#define __TRANSLATION_H
extern unsigned char translation_in[256], translation_out[256];
int translation_read(const char *file);
void translate_output(char *text);
void translation_init(void);
void translation_deinit(void);
#endif

View File

@ -0,0 +1,224 @@
/*
window-items.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "modules.h"
#include "signals.h"
#include "server.h"
#include "settings.h"
#include "levels.h"
#include "printtext.h"
#include "windows.h"
#include "window-items.h"
void window_add_item(WINDOW_REC *window, WI_ITEM_REC *item, int automatic)
{
g_return_if_fail(window != NULL);
g_return_if_fail(item != NULL);
MODULE_DATA_SET(item, window);
if (window->items == NULL) {
window->active = item;
window->active_server = item->server;
}
signal_emit("gui window item init", 1, item);
if (!automatic || settings_get_bool("window_auto_change")) {
if (automatic)
signal_emit("window changed automatic", 1, window);
window_set_active(window);
}
window->items = g_slist_append(window->items, item);
signal_emit("window item new", 2, window, item);
if (!automatic || g_slist_length(window->items) == 1) {
window->active = NULL;
window_item_set_active(window, item);
}
}
void window_remove_item(WINDOW_REC *window, WI_ITEM_REC *item)
{
g_return_if_fail(window != NULL);
g_return_if_fail(item != NULL);
if (g_slist_find(window->items, item) == NULL)
return;
MODULE_DATA_SET(item, NULL);
window->items = g_slist_remove(window->items, item);
if (window->active == item) {
window->active = window->items == NULL ? NULL :
window->items->data;
}
signal_emit("window item remove", 2, window, item);
}
WINDOW_REC *window_item_window(WI_ITEM_REC *item)
{
g_return_val_if_fail(item != NULL, NULL);
return MODULE_DATA(item);
}
void window_item_set_active(WINDOW_REC *window, WI_ITEM_REC *item)
{
g_return_if_fail(window != NULL);
if (window->active != item) {
window->active = item;
if (item != NULL) window_change_server(window, window->active_server);
signal_emit("window item changed", 2, window, item);
}
}
void window_item_change_server(WI_ITEM_REC *item, void *server)
{
WINDOW_REC *window;
g_return_if_fail(item != NULL);
window = MODULE_DATA(item);
item->server = server;
signal_emit("window item server changed", 2, window, item);
if (window->active == item) window_change_server(window, item->server);
}
static WI_ITEM_REC *window_item_find_window(WINDOW_REC *window, void *server, const char *name)
{
GSList *tmp;
for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
WI_ITEM_REC *rec = tmp->data;
if ((server == NULL || rec->server == server) &&
g_strcasecmp(name, rec->name) == 0) return rec;
}
return NULL;
}
/* Find wanted window item by name. `server' can be NULL. */
WI_ITEM_REC *window_item_find(void *server, const char *name)
{
WI_ITEM_REC *item;
GSList *tmp;
g_return_val_if_fail(name != NULL, NULL);
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
WINDOW_REC *rec = tmp->data;
item = window_item_find_window(rec, server, name);
if (item != NULL) return item;
}
return NULL;
}
static int waiting_channels_get(WINDOW_REC *window, const char *tag)
{
GSList *tmp;
g_return_val_if_fail(window != NULL, FALSE);
g_return_val_if_fail(tag != NULL, FALSE);
for (tmp = window->waiting_channels; tmp != NULL; tmp = tmp->next) {
if (g_strcasecmp(tmp->data, tag) == 0) {
g_free(tmp->data);
window->waiting_channels = g_slist_remove(window->waiting_channels, tmp->data);
return TRUE;
}
}
return FALSE;
}
void window_item_create(WI_ITEM_REC *item, int automatic)
{
WINDOW_REC *window;
GSList *tmp;
char *str;
g_return_if_fail(item != NULL);
str = item->server == NULL ? NULL :
g_strdup_printf("%s %s", ((SERVER_REC *) item->server)->tag, item->name);
window = NULL;
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
WINDOW_REC *rec = tmp->data;
if (rec->items == NULL && rec->level == 0 &&
(window == NULL || rec == active_win)) {
/* no items in this window, we should probably use it.. */
window = rec;
}
if (rec->waiting_channels != NULL && str != NULL) {
/* right name/server tag combination in
some waiting list? */
if (waiting_channels_get(rec, str)) {
window = rec;
break;
}
}
}
g_free_not_null(str);
if (window == NULL) {
/* create new window to use */
window = window_create(item, automatic);
} else {
/* use existing window */
window_add_item(window, item, automatic);
}
}
static void signal_window_item_changed(WINDOW_REC *window, WI_ITEM_REC *item)
{
g_return_if_fail(window != NULL);
if (g_slist_length(window->items) > 1) {
/* default to printing "talking with ...",
you can override it it you wish */
printformat(item->server, item->name, MSGLEVEL_CLIENTNOTICE,
IRCTXT_TALKING_WITH, item->name);
}
}
void window_items_init(void)
{
signal_add_last("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
}
void window_items_deinit(void)
{
signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
}

View File

@ -0,0 +1,22 @@
#ifndef __WINDOW_ITEMS_H
#define __WINDOW_ITEMS_H
#include "windows.h"
/* Add/remove window item from `window' */
void window_add_item(WINDOW_REC *window, WI_ITEM_REC *item, int automatic);
void window_remove_item(WINDOW_REC *window, WI_ITEM_REC *item);
/* Find a window for `item' and call window_add_item(). */
void window_item_create(WI_ITEM_REC *item, int automatic);
WINDOW_REC *window_item_window(WI_ITEM_REC *item);
void window_item_set_active(WINDOW_REC *window, WI_ITEM_REC *item);
void window_item_change_server(WI_ITEM_REC *item, void *server);
/* Find wanted window item by name. `server' can be NULL. */
WI_ITEM_REC *window_item_find(void *server, const char *name);
void window_items_init(void);
void window_items_deinit(void);
#endif

View File

@ -0,0 +1,466 @@
/*
windows.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "server.h"
#include "settings.h"
#include "levels.h"
#include "printtext.h"
#include "windows.h"
#include "window-items.h"
GSList *windows;
WINDOW_REC *active_win;
static int window_get_new_refnum(void)
{
WINDOW_REC *win;
GSList *tmp;
int refnum;
refnum = 1;
tmp = windows;
while (tmp != NULL) {
win = tmp->data;
if (refnum != win->refnum) {
tmp = tmp->next;
continue;
}
refnum++;
tmp = windows;
}
return refnum;
}
WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic)
{
WINDOW_REC *rec;
rec = g_new0(WINDOW_REC, 1);
rec->refnum = window_get_new_refnum();
windows = g_slist_append(windows, rec);
signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic));
if (item != NULL) window_add_item(rec, item, automatic);
if (windows->next == NULL || !automatic || settings_get_bool("window_auto_change")) {
if (automatic && windows->next != NULL)
signal_emit("window changed automatic", 1, rec);
window_set_active(rec);
}
return rec;
}
void window_destroy(WINDOW_REC *window)
{
g_return_if_fail(window != NULL);
if (window->destroying) return;
window->destroying = TRUE;
while (window->items != NULL)
window_remove_item(window, window->items->data);
windows = g_slist_remove(windows, window);
signal_emit("window destroyed", 1, window);
g_slist_foreach(window->waiting_channels, (GFunc) g_free, NULL);
g_slist_free(window->waiting_channels);
g_free_not_null(window->name);
g_free(window);
}
void window_set_active_num(int number)
{
GSList *win;
win = g_slist_nth(windows, number);
if (win == NULL) return;
active_win = win->data;
signal_emit("window changed", 1, active_win);
}
void window_set_active(WINDOW_REC *window)
{
int number;
number = g_slist_index(windows, window);
if (number == -1) return;
active_win = window;
signal_emit("window changed", 1, active_win);
}
void window_change_server(WINDOW_REC *window, void *server)
{
window->active_server = server;
signal_emit("window server changed", 2, window, server);
}
void window_set_name(WINDOW_REC *window, const char *name)
{
g_free_not_null(window->name);
window->name = g_strdup(name);
signal_emit("window name changed", 1, window);
}
void window_set_level(WINDOW_REC *window, int level)
{
g_return_if_fail(window != NULL);
window->level = level;
signal_emit("window level changed", 1, window);
}
WINDOW_REC *window_find_level(void *server, int level)
{
WINDOW_REC *match;
GSList *tmp;
match = NULL;
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
WINDOW_REC *rec = tmp->data;
if ((server == NULL || rec->active_server == server) &&
(rec->level & level)) {
if (server == NULL || rec->active_server == server)
return rec;
match = rec;
}
}
return match;
}
WINDOW_REC *window_find_closest(void *server, const char *name, int level)
{
WINDOW_REC *window;
WI_ITEM_REC *item;
/* match by name */
item = name == NULL ? NULL :
window_item_find(server, name);
if (item != NULL)
return window_item_window(item);
/* match by level */
if (level != MSGLEVEL_HILIGHT)
level &= ~(MSGLEVEL_HILIGHT | MSGLEVEL_NOHILIGHT);
window = window_find_level(server, level);
if (window != NULL) return window;
/* fallback to active */
return active_win;
}
static void cmd_window(const char *data, void *server, WI_ITEM_REC *item)
{
command_runsub("window", data, server, item);
}
static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item)
{
WINDOW_REC *window;
int type;
g_return_if_fail(data != NULL);
type = (g_strcasecmp(data, "hide") == 0 || g_strcasecmp(data, "tab") == 0) ? 1 :
(g_strcasecmp(data, "split") == 0 ? 2 : 0);
signal_emit("gui window create override", 1, GINT_TO_POINTER(type));
window = window_create(NULL, FALSE);
window_change_server(window, server);
}
static void cmd_window_close(const char *data)
{
/* destroy window unless it's the last one */
if (windows->next != NULL)
window_destroy(active_win);
}
/* return the first window number with the highest activity */
static int window_highest_activity(WINDOW_REC *window)
{
WINDOW_REC *rec;
GSList *tmp;
int max_num, max_act, through;
max_num = 0; max_act = 0; through = FALSE;
tmp = g_slist_find(windows, window);
for (;; tmp = tmp->next) {
if (tmp == NULL) {
tmp = windows;
through = TRUE;
}
if (through && tmp->data == window)
break;
rec = tmp->data;
if (rec->new_data && max_act < rec->new_data) {
max_act = rec->new_data;
max_num = g_slist_index(windows, rec)+1;
}
}
return max_num;
}
/* channel name - first try channel from same server */
static int window_find_name(WINDOW_REC *window, const char *name)
{
WI_ITEM_REC *item;
int num;
item = window_item_find(window->active_server, name);
if (item == NULL && window->active_server != NULL) {
/* not found from the active server - any server? */
item = window_item_find(NULL, name);
}
if (item == NULL) {
char *chan;
/* still nothing? maybe user just left the # in front of
channel, try again with it.. */
chan = g_strdup_printf("#%s", name);
item = window_item_find(window->active_server, chan);
if (item == NULL) item = window_item_find(NULL, chan);
g_free(chan);
}
if (item == NULL)
return 0;
/* get the window number */
window = MODULE_DATA(item);
if (window == NULL) return 0;
num = g_slist_index(windows, window);
return num < 0 ? 0 : num+1;
}
static void cmd_window_goto(const char *data)
{
int num;
g_return_if_fail(data != NULL);
num = 0;
if (g_strcasecmp(data, "active") == 0)
num = window_highest_activity(active_win);
else if (isdigit(*data))
num = atol(data);
else
num = window_find_name(active_win, data);
if (num > 0)
window_set_active_num(num-1);
}
static void cmd_window_next(const char *data)
{
int num;
num = g_slist_index(windows, active_win)+1;
if (num >= g_slist_length(windows)) num = 0;
window_set_active_num(num);
}
static void cmd_window_prev(const char *data)
{
int num;
num = g_slist_index(windows, active_win)-1;
if (num < 0) num = g_slist_length(windows)-1;
window_set_active_num(num);
}
static void cmd_window_level(const char *data)
{
g_return_if_fail(data != NULL);
window_set_level(active_win, combine_level(active_win->level, data));
printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, "Window level is now %s",
bits2level(active_win->level));
}
static void cmd_window_server(const char *data)
{
SERVER_REC *server;
g_return_if_fail(data != NULL);
server = server_find_tag(data);
if (server == NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_UNKNOWN_SERVER_TAG, data);
else if (active_win->active == NULL) {
window_change_server(active_win, server);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SERVER_CHANGED, server->tag, server->connrec->address,
server->connrec->ircnet == NULL ? "" : server->connrec->ircnet);
}
}
static void cmd_window_item_prev(const char *data, void *server, WI_ITEM_REC *item)
{
WINDOW_REC *window;
WI_ITEM_REC *last;
GSList *tmp;
window = item == NULL ? NULL : MODULE_DATA(item);
if (window == NULL) return;
last = NULL;
for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
WI_ITEM_REC *rec = tmp->data;
if (rec != item)
last = rec;
else {
/* current channel. did we find anything?
if not, go to the last channel */
if (last != NULL) break;
}
}
if (last != NULL)
window_item_set_active(window, last);
}
static void cmd_window_item_next(const char *data, void *server, WI_ITEM_REC *item)
{
WINDOW_REC *window;
WI_ITEM_REC *next;
GSList *tmp;
int gone;
window = item == NULL ? NULL : MODULE_DATA(item);
if (window == NULL) return;
next = NULL; gone = FALSE;
for (tmp = window->items; tmp != NULL; tmp = tmp->next) {
WI_ITEM_REC *rec = tmp->data;
if (rec == item)
gone = TRUE;
else {
if (gone) {
/* found the next channel */
next = rec;
break;
}
if (next == NULL)
next = rec; /* fallback to first channel */
}
}
if (next != NULL)
window_item_set_active(window, next);
}
static void cmd_window_name(const char *data)
{
window_set_name(active_win, data);
}
static void sig_server_looking(void *server)
{
GSList *tmp;
g_return_if_fail(server != NULL);
/* try to keep some server assigned to windows.. */
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
WINDOW_REC *rec = tmp->data;
if (rec->active_server == NULL)
window_change_server(rec, server);
}
}
static void sig_server_disconnected(void *server)
{
GSList *tmp;
g_return_if_fail(server != NULL);
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
WINDOW_REC *rec = tmp->data;
if (rec->active_server == server)
window_change_server(rec, NULL);
}
}
void windows_init(void)
{
active_win = NULL;
settings_add_bool("lookandfeel", "window_auto_change", FALSE);
command_bind("window", NULL, (SIGNAL_FUNC) cmd_window);
command_bind("window new", NULL, (SIGNAL_FUNC) cmd_window_new);
command_bind("window close", NULL, (SIGNAL_FUNC) cmd_window_close);
command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server);
command_bind("window goto", NULL, (SIGNAL_FUNC) cmd_window_goto);
command_bind("window prev", NULL, (SIGNAL_FUNC) cmd_window_prev);
command_bind("window next", NULL, (SIGNAL_FUNC) cmd_window_next);
command_bind("window level", NULL, (SIGNAL_FUNC) cmd_window_level);
command_bind("window item prev", NULL, (SIGNAL_FUNC) cmd_window_item_prev);
command_bind("window item next", NULL, (SIGNAL_FUNC) cmd_window_item_next);
command_bind("window name", NULL, (SIGNAL_FUNC) cmd_window_name);
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
signal_add("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
}
void windows_deinit(void)
{
command_unbind("window", (SIGNAL_FUNC) cmd_window);
command_unbind("window new", (SIGNAL_FUNC) cmd_window_new);
command_unbind("window close", (SIGNAL_FUNC) cmd_window_close);
command_unbind("window server", (SIGNAL_FUNC) cmd_window_server);
command_unbind("window goto", (SIGNAL_FUNC) cmd_window_goto);
command_unbind("window prev", (SIGNAL_FUNC) cmd_window_prev);
command_unbind("window next", (SIGNAL_FUNC) cmd_window_next);
command_unbind("window level", (SIGNAL_FUNC) cmd_window_level);
command_unbind("window item prev", (SIGNAL_FUNC) cmd_window_item_prev);
command_unbind("window item next", (SIGNAL_FUNC) cmd_window_item_next);
command_unbind("window name", (SIGNAL_FUNC) cmd_window_name);
signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
signal_remove("server connect failed", (SIGNAL_FUNC) sig_server_disconnected);
}

View File

@ -0,0 +1,67 @@
#ifndef __WINDOWS_H
#define __WINDOWS_H
enum {
NEWDATA_TEXT = 1,
NEWDATA_MSG,
NEWDATA_MSG_FORYOU,
NEWDATA_CUSTOM
};
/* All window items *MUST* have these variables in same order
at the start of the structure - the server's type can of course be
replaced with the preferred record type. */
typedef struct {
int type;
GHashTable *module_data;
void *server;
char *name;
int new_data;
} WI_ITEM_REC;
typedef struct {
int refnum;
char *name;
GSList *items;
WI_ITEM_REC *active;
void *active_server;
GSList *waiting_channels; /* list of "<server tag> <channel>" */
int lines;
int destroying:1;
/* window-specific command line history */
GList *cmdhist, *histpos;
int histlines;
int level;
int new_data;
time_t last_timestamp; /* When was last timestamp printed */
gpointer gui_data;
} WINDOW_REC;
extern GSList *windows;
extern WINDOW_REC *active_win;
WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic);
void window_destroy(WINDOW_REC *window);
void window_set_active_num(int number);
void window_set_active(WINDOW_REC *window);
void window_change_server(WINDOW_REC *window, void *server);
void window_set_name(WINDOW_REC *window, const char *name);
void window_set_level(WINDOW_REC *window, int level);
WINDOW_REC *window_find_level(void *server, int level);
WINDOW_REC *window_find_closest(void *server, const char *name, int level);
void windows_init(void);
void windows_deinit(void);
#endif

View File

@ -0,0 +1,32 @@
SUBDIRS = dcc flood notifylist
noinst_LTLIBRARIES = libfe_common_irc.la
INCLUDES = \
$(GLIB_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core/ \
-I$(top_srcdir)/src/irc/core/ \
-I$(top_srcdir)/src/fe-common/core/ \
-DHELPDIR=\""$(datadir)/irssi/help"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\"
libfe_common_irc_la_SOURCES = \
completion.c \
fe-channels.c \
fe-irc-commands.c \
fe-ctcp.c \
fe-events.c \
fe-events-numeric.c \
fe-ignore.c \
fe-query.c \
fe-common-irc.c \
irc-nick-hilight.c \
irc-hilight-text.c \
module-formats.c
noinst_HEADERS = \
completion.h \
fe-common-irc.h \
irc-hilight-text.h \
module-formats.h

View File

@ -0,0 +1,628 @@
/*
completion.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "commands.h"
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "irc.h"
#include "server.h"
#include "channels.h"
#include "nicklist.h"
#include "completion.h"
#include "window-items.h"
typedef struct {
time_t time;
char *nick;
} COMPLETION_REC;
#define replace_find(replace) \
iconfig_list_find("replaces", "text", replace, "replace")
#define completion_find(completion) \
iconfig_list_find("completions", "short", completion, "long")
static gint comptag;
static GList *complist;
static COMPLETION_REC *nick_completion_find(GSList *list, gchar *nick)
{
GSList *tmp;
for (tmp = list; tmp != NULL; tmp = tmp->next)
{
COMPLETION_REC *rec = tmp->data;
if (g_strcasecmp(rec->nick, nick) == 0) return rec;
}
return NULL;
}
static void completion_destroy(GSList **list, COMPLETION_REC *rec)
{
*list = g_slist_remove(*list, rec);
g_free(rec->nick);
g_free(rec);
}
static COMPLETION_REC *nick_completion_create(GSList **list, time_t time, gchar *nick)
{
COMPLETION_REC *rec;
rec = nick_completion_find(*list, nick);
if (rec != NULL)
{
/* remove the old one */
completion_destroy(list, rec);
}
rec = g_new(COMPLETION_REC, 1);
*list = g_slist_prepend(*list, rec);
rec->time = time;
rec->nick = g_strdup(nick);
return rec;
}
static void completion_checklist(GSList **list, gint timeout, time_t t)
{
GSList *tmp, *next;
for (tmp = *list; tmp != NULL; tmp = next)
{
COMPLETION_REC *rec = tmp->data;
next = tmp->next;
if (t-rec->time > timeout)
completion_destroy(list, rec);
}
}
static gint completion_timeout(void)
{
GSList *tmp, *link;
time_t t;
gint len;
t = time(NULL);
for (tmp = servers; tmp != NULL; tmp = tmp->next)
{
IRC_SERVER_REC *rec = tmp->data;
len = g_slist_length(rec->lastmsgs);
if (len > 0 && len >= settings_get_int("completion_keep_privates"))
{
link = g_slist_last(rec->lastmsgs);
g_free(link->data);
rec->lastmsgs = g_slist_remove_link(rec->lastmsgs, link);
g_slist_free_1(link);
}
}
for (tmp = channels; tmp != NULL; tmp = tmp->next)
{
CHANNEL_REC *rec = tmp->data;
completion_checklist(&rec->lastownmsgs, settings_get_int("completion_keep_ownpublics"), t);
completion_checklist(&rec->lastmsgs, settings_get_int("completion_keep_publics"), t);
}
return 1;
}
static void add_private_msg(IRC_SERVER_REC *server, gchar *nick)
{
GSList *link;
link = gslist_find_icase_string(server->lastmsgs, nick);
if (link != NULL)
{
g_free(link->data);
server->lastmsgs = g_slist_remove_link(server->lastmsgs, link);
g_slist_free_1(link);
}
server->lastmsgs = g_slist_prepend(server->lastmsgs, g_strdup(nick));
}
static void event_privmsg(gchar *data, IRC_SERVER_REC *server, gchar *nick)
{
gchar *params, *target, *msg;
GSList **list;
g_return_if_fail(server != NULL);
if (nick == NULL) return; /* from server */
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (*msg == 1)
{
/* ignore ctcp messages */
g_free(params);
return;
}
if (ischannel(*target))
{
/* channel message */
CHANNEL_REC *channel;
channel = channel_find(server, target);
if (channel == NULL)
{
g_free(params);
return;
}
list = completion_msgtoyou((SERVER_REC *) server, msg) ?
&channel->lastownmsgs :
&channel->lastmsgs;
nick_completion_create(list, time(NULL), nick);
}
else
{
/* private message */
add_private_msg(server, nick);
}
g_free(params);
}
static void cmd_msg(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *target, *msg;
g_return_if_fail(data != NULL);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (*target != '\0' && *msg != '\0')
{
if (!ischannel(*target) && *target != '=' && server != NULL)
add_private_msg(server, target);
}
g_free(params);
}
int completion_msgtoyou(SERVER_REC *server, const char *msg)
{
gchar *stripped, *nick;
gboolean ret;
gint len;
g_return_val_if_fail(msg != NULL, FALSE);
if (g_strncasecmp(msg, server->nick, strlen(server->nick)) == 0 &&
!isalnum((gint) msg[strlen(server->nick)])) return TRUE;
stripped = nick_strip(server->nick);
nick = nick_strip(msg);
len = strlen(stripped);
ret = *stripped != '\0' &&
g_strncasecmp(nick, stripped, len) == 0 &&
!isalnum((gint) nick[len]) &&
(guchar) nick[len] < 128;
g_free(nick);
g_free(stripped);
return ret;
}
static void complete_list(GList **outlist, GSList *list, gchar *nick)
{
GSList *tmp;
gint len;
len = strlen(nick);
for (tmp = list; tmp != NULL; tmp = tmp->next)
{
COMPLETION_REC *rec = tmp->data;
if (g_strncasecmp(rec->nick, nick, len) == 0 &&
glist_find_icase_string(*outlist, rec->nick) == NULL)
*outlist = g_list_append(*outlist, g_strdup(rec->nick));
}
}
static GList *completion_getlist(CHANNEL_REC *channel, gchar *nick)
{
GSList *nicks, *tmp;
GList *list;
gint len;
g_return_val_if_fail(channel != NULL, NULL);
g_return_val_if_fail(nick != NULL, NULL);
if (*nick == '\0') return NULL;
list = NULL;
complete_list(&list, channel->lastownmsgs, nick);
complete_list(&list, channel->lastmsgs, nick);
len = strlen(nick);
nicks = nicklist_getnicks(channel);
for (tmp = nicks; tmp != NULL; tmp = tmp->next)
{
NICK_REC *rec = tmp->data;
if (g_strncasecmp(rec->nick, nick, len) == 0 &&
glist_find_icase_string(list, rec->nick) == NULL &&
g_strcasecmp(rec->nick, channel->server->nick) != 0)
list = g_list_append(list, g_strdup(rec->nick));
}
g_slist_free(nicks);
return list;
}
static GList *completion_getmsglist(IRC_SERVER_REC *server, gchar *nick)
{
GSList *tmp;
GList *list;
gint len;
list = NULL; len = strlen(nick);
for (tmp = server->lastmsgs; tmp != NULL; tmp = tmp->next)
{
if (len == 0 || g_strncasecmp(tmp->data, nick, len) == 0)
list = g_list_append(list, g_strdup(tmp->data));
}
return list;
}
static void event_command(gchar *line, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
CHANNEL_REC *channel;
GList *comp;
gchar *str, *ptr;
g_return_if_fail(line != NULL);
if (!irc_item_check(item))
return;
if (strchr(settings_get_str("cmdchars"), *line) != NULL)
return;
line = g_strdup(line);
/* check for nick completion */
if (settings_get_bool("completion_disable_auto") || *settings_get_str("completion_char") == '\0')
{
ptr = NULL;
comp = NULL;
}
else
{
ptr = strchr(line, *settings_get_str("completion_char"));
if (ptr != NULL) *ptr++ = '\0';
channel = irc_item_channel(item);
comp = ptr == NULL || channel == NULL ||
nicklist_find(channel, line) != NULL ? NULL :
completion_getlist(channel, line);
}
/* message to channel */
if (ptr == NULL)
str = g_strdup_printf("%s %s", item->name, line);
else
{
str = g_strdup_printf("%s %s%s%s", item->name,
comp != NULL ? (gchar *) comp->data : line,
settings_get_str("completion_char"), ptr);
}
signal_emit("command msg", 3, str, server, item);
g_free(str);
g_free(line);
if (comp != NULL)
{
g_list_foreach(comp, (GFunc) g_free, NULL);
g_list_free(comp);
}
signal_stop();
}
static GList *completion_joinlist(GList *list1, GList *list2)
{
while (list2 != NULL)
{
if (!glist_find_icase_string(list1, list2->data))
list1 = g_list_append(list1, list2->data);
else
g_free(list2->data);
list2 = list2->next;
}
g_list_free(list2);
return list1;
}
char *auto_completion(const char *line, int *pos)
{
const char *replace;
gchar *word, *ret;
gint spos, epos, n, wordpos;
GString *result;
g_return_val_if_fail(line != NULL, NULL);
g_return_val_if_fail(pos != NULL, NULL);
spos = *pos;
/* get the word we are completing.. */
while (spos > 0 && isspace((gint) line[spos-1])) spos--;
epos = spos;
while (spos > 0 && !isspace((gint) line[spos-1])) spos--;
while (line[epos] != '\0' && !isspace((gint) line[epos])) epos++;
word = g_strdup(line+spos);
word[epos-spos] = '\0';
/* word position in line */
wordpos = 0;
for (n = 0; n < spos; )
{
while (n < spos && isspace((gint) line[n])) n++;
while (n < spos && !isspace((gint) line[n])) n++;
if (n < spos) wordpos++;
}
result = g_string_new(line);
g_string_erase(result, spos, epos-spos);
/* check for words in autocompletion list */
replace = replace_find(word); g_free(word);
if (replace != NULL)
{
*pos = spos+strlen(replace);
g_string_insert(result, spos, replace);
ret = result->str;
g_string_free(result, FALSE);
return ret;
}
g_string_free(result, TRUE);
return NULL;
}
#define issplit(a) ((a) == ',' || (a) == ' ')
char *completion_line(WINDOW_REC *window, const char *line, int *pos)
{
static gboolean msgcomp = FALSE;
const char *completion;
CHANNEL_REC *channel;
SERVER_REC *server;
gchar *word, *ret;
gint spos, epos, len, n, wordpos;
gboolean msgcompletion;
GString *result;
g_return_val_if_fail(window != NULL, NULL);
g_return_val_if_fail(line != NULL, NULL);
g_return_val_if_fail(pos != NULL, NULL);
spos = *pos;
/* get the word we are completing.. */
while (spos > 0 && issplit((gint) line[spos-1])) spos--;
epos = spos;
if (line[epos] == ',') epos++;
while (spos > 0 && !issplit((gint) line[spos-1])) spos--;
while (line[epos] != '\0' && !issplit((gint) line[epos])) epos++;
word = g_strdup(line+spos);
word[epos-spos] = '\0';
/* word position in line */
wordpos = 0;
for (n = 0; n < spos; )
{
while (n < spos && issplit((gint) line[n])) n++;
while (n < spos && !issplit((gint) line[n])) n++;
if (n < spos) wordpos++;
}
server = window->active == NULL ? window->active_server : window->active->server;
msgcompletion = server != NULL &&
(*line == '\0' || ((wordpos == 0 || wordpos == 1) && g_strncasecmp(line, "/msg ", 5) == 0));
if (msgcompletion && wordpos == 0 && issplit((gint) line[epos]))
{
/* /msg <tab> */
*word = '\0'; epos++; spos = epos; wordpos = 1;
}
/* are we completing the same nick as last time?
if not, forget the old completion.. */
len = strlen(word)-(msgcomp == FALSE && word[strlen(word)-1] == *settings_get_str("completion_char"));
if (complist != NULL && (strlen(complist->data) != len || g_strncasecmp(complist->data, word, len) != 0))
{
g_list_foreach(complist, (GFunc) g_free, NULL);
g_list_free(complist);
complist = NULL;
}
result = g_string_new(line);
g_string_erase(result, spos, epos-spos);
/* check for words in completion list */
completion = completion_find(word);
if (completion != NULL)
{
g_free(word);
*pos = spos+strlen(completion);
g_string_insert(result, spos, completion);
ret = result->str;
g_string_free(result, FALSE);
return ret;
}
channel = irc_item_channel(window->active);
if (complist == NULL && !msgcompletion && channel == NULL)
{
/* don't try nick completion */
g_free(word);
g_string_free(result, TRUE);
return NULL;
}
if (complist == NULL)
{
/* start new nick completion */
complist = channel == NULL ? NULL : completion_getlist(channel, word);
if (!msgcompletion)
{
/* nick completion in channel */
msgcomp = FALSE;
}
else
{
GList *tmpcomp;
/* /msg completion */
msgcomp = TRUE;
/* first get the list of msg nicks and then nicks from current
channel. */
tmpcomp = complist;
complist = completion_getmsglist((IRC_SERVER_REC *) server, word);
complist = completion_joinlist(complist, tmpcomp);
if (*line == '\0')
{
/* completion in empty line -> /msg <nick> */
g_free(word);
g_string_free(result, TRUE);
if (complist == NULL)
ret = g_strdup("/msg ");
else
ret = g_strdup_printf("/msg %s ", (gchar *) complist->data);
*pos = strlen(ret);
return ret;
}
}
if (complist == NULL)
{
g_free(word);
g_string_free(result, TRUE);
return NULL;
}
}
else
{
/* continue the last completion */
complist = complist->next == NULL ? g_list_first(complist) : complist->next;
}
g_free(word);
/* insert the nick.. */
g_string_insert(result, spos, complist->data);
*pos = spos+strlen(complist->data);
if (!msgcomp && wordpos == 0)
{
/* insert completion character */
g_string_insert(result, *pos, settings_get_str("completion_char"));
*pos += strlen(settings_get_str("completion_char"));
}
if (msgcomp || wordpos == 0)
{
if (!issplit((gint) result->str[*pos]))
{
/* insert space */
g_string_insert(result, *pos, " ");
}
(*pos)++;
}
ret = result->str;
g_string_free(result, FALSE);
return ret;
}
static void completion_deinit_server(IRC_SERVER_REC *server)
{
g_return_if_fail(server != NULL);
g_slist_foreach(server->lastmsgs, (GFunc) g_free, NULL);
g_slist_free(server->lastmsgs);
}
static void completion_deinit_channel(CHANNEL_REC *channel)
{
g_return_if_fail(channel != NULL);
while (channel->lastmsgs != NULL)
completion_destroy(&channel->lastmsgs, channel->lastmsgs->data);
while (channel->lastownmsgs != NULL)
completion_destroy(&channel->lastownmsgs, channel->lastownmsgs->data);
g_slist_free(channel->lastmsgs);
g_slist_free(channel->lastownmsgs);
}
void completion_init(void)
{
settings_add_str("completion", "completion_char", ":");
settings_add_bool("completion", "completion_disable_auto", FALSE);
settings_add_int("completion", "completion_keep_publics", 180);
settings_add_int("completion", "completion_keep_ownpublics", 360);
settings_add_int("completion", "completion_keep_privates", 10);
signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
signal_add("send command", (SIGNAL_FUNC) event_command);
signal_add("server disconnected", (SIGNAL_FUNC) completion_deinit_server);
signal_add("channel destroyed", (SIGNAL_FUNC) completion_deinit_channel);
command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
comptag = g_timeout_add(1000, (GSourceFunc) completion_timeout, NULL);
complist = NULL;
}
void completion_deinit(void)
{
g_list_foreach(complist, (GFunc) g_free, NULL);
g_list_free(complist);
g_source_remove(comptag);
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
signal_remove("send command", (SIGNAL_FUNC) event_command);
signal_remove("server disconnected", (SIGNAL_FUNC) completion_deinit_server);
signal_remove("channel destroyed", (SIGNAL_FUNC) completion_deinit_channel);
command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
}

View File

@ -0,0 +1,13 @@
#ifndef __COMPLETION_H
#define __COMPLETION_H
#include "window-items.h"
int completion_msgtoyou(SERVER_REC *server, const char *msg);
char *completion_line(WINDOW_REC *window, const char *line, int *pos);
char *auto_completion(const char *line, int *pos);
void completion_init(void);
void completion_deinit(void);
#endif

View File

@ -0,0 +1,17 @@
noinst_LTLIBRARIES = libfe_common_irc_dcc.la
INCLUDES = \
$(GLIB_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core/ \
-I$(top_srcdir)/src/irc/core/ \
-I$(top_srcdir)/src/fe-common/core/ \
-DHELPDIR=\""$(datadir)/irssi/help"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\"
libfe_common_irc_dcc_la_SOURCES = \
fe-dcc.c \
module-formats.c
noinst_HEADERS = \
module-formats.h

View File

@ -0,0 +1,457 @@
/*
fe-dcc.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "network.h"
#include "levels.h"
#include "irc.h"
#include "channels.h"
#include "irc/dcc/dcc.h"
#include "windows.h"
static void dcc_connected(DCC_REC *dcc)
{
gchar *str;
g_return_if_fail(dcc != NULL);
switch (dcc->dcc_type)
{
case DCC_TYPE_CHAT:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT_CONNECTED,
dcc->nick, dcc->addrstr, dcc->port);
str = g_strconcat("=", dcc->nick, NULL);
/*FIXME: dcc_chat_create(dcc->server, str, FALSE);*/
g_free(str);
break;
case DCC_TYPE_SEND:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_CONNECTED,
dcc->arg, dcc->nick, dcc->addrstr, dcc->port);
break;
case DCC_TYPE_GET:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_CONNECTED,
dcc->arg, dcc->nick, dcc->addrstr, dcc->port);
break;
}
}
static void dcc_rejected(DCC_REC *dcc)
{
g_return_if_fail(dcc != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CLOSE,
dcc_type2str(dcc->dcc_type), dcc->nick, dcc->arg);
}
static void dcc_closed(DCC_REC *dcc)
{
time_t secs;
gdouble kbs;
g_return_if_fail(dcc != NULL);
secs = dcc->starttime == 0 ? -1 : time(NULL)-dcc->starttime;
kbs = (gdouble) (dcc->transfd-dcc->skipped) / (secs == 0 ? 1 : secs) / 1024.0;
switch (dcc->dcc_type)
{
case DCC_TYPE_CHAT:
{
/* nice kludge :) if connection was lost, close the channel.
after closed channel (can be done with /unquery too)
prints the disconnected-text.. */
CHANNEL_REC *channel;
gchar *str;
str = g_strdup_printf("=%s", dcc->nick);
printformat(dcc->server, str, MSGLEVEL_DCC,
IRCTXT_DCC_CHAT_DISCONNECTED, dcc->nick);
channel = channel_find(dcc->server, str);
if (channel != NULL)
channel_destroy(channel);
g_free(str);
}
break;
case DCC_TYPE_SEND:
if (secs == -1)
{
/* aborted */
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_ABORTED,
dcc->arg, dcc->nick);
}
else
{
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_COMPLETE,
dcc->arg, dcc->transfd/1024, dcc->nick, (glong) secs, kbs);
}
break;
case DCC_TYPE_GET:
if (secs == -1)
{
/* aborted */
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_ABORTED,
dcc->arg, dcc->nick);
}
else
{
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_COMPLETE,
dcc->arg, dcc->transfd/1024, dcc->nick, (glong) secs, kbs);
}
break;
}
}
static void dcc_chat_in_action(gchar *msg, DCC_REC *dcc)
{
gchar *sender;
g_return_if_fail(dcc != NULL);
g_return_if_fail(msg != NULL);
sender = g_strconcat("=", dcc->nick, NULL);
printformat(NULL, sender, MSGLEVEL_DCC,
IRCTXT_ACTION_DCC, dcc->nick, msg);
g_free(sender);
}
static void dcc_chat_ctcp(gchar *msg, DCC_REC *dcc)
{
gchar *sender;
g_return_if_fail(dcc != NULL);
g_return_if_fail(msg != NULL);
sender = g_strconcat("=", dcc->nick, NULL);
printformat(NULL, sender, MSGLEVEL_DCC, IRCTXT_DCC_CTCP, dcc->nick, msg);
g_free(sender);
}
static void dcc_chat_msg(DCC_REC *dcc, gchar *msg)
{
gchar *nick;
g_return_if_fail(dcc != NULL);
g_return_if_fail(msg != NULL);
nick = g_strconcat("=", dcc->nick, NULL);
printformat(NULL, nick, MSGLEVEL_DCC, IRCTXT_DCC_MSG, dcc->nick, msg);
g_free(nick);
}
static void dcc_request(DCC_REC *dcc)
{
g_return_if_fail(dcc != NULL);
switch (dcc->dcc_type)
{
case DCC_TYPE_CHAT:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT,
dcc->nick, dcc->addrstr, dcc->port);
break;
case DCC_TYPE_GET:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND,
dcc->nick, dcc->addrstr, dcc->port, dcc->arg, dcc->size);
break;
}
}
static void dcc_error_connect(DCC_REC *dcc)
{
g_return_if_fail(dcc != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CONNECT_ERROR, dcc->addrstr, dcc->port);
}
static void dcc_error_file_create(DCC_REC *dcc, gchar *fname)
{
g_return_if_fail(dcc != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CANT_CREATE, fname);
}
static void dcc_error_file_not_found(gchar *nick, gchar *fname)
{
g_return_if_fail(nick != NULL);
g_return_if_fail(fname != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_FILE_NOT_FOUND, fname);
}
static void dcc_error_get_not_found(gchar *nick)
{
g_return_if_fail(nick != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick);
}
static void dcc_error_send_exists(gchar *nick, gchar *fname)
{
g_return_if_fail(nick != NULL);
g_return_if_fail(fname != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_EXISTS, fname, nick);
}
static void dcc_error_unknown_type(gchar *type)
{
g_return_if_fail(type != NULL);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_TYPE, type);
}
static void dcc_error_close_not_found(gchar *type, gchar *nick, gchar *fname)
{
g_return_if_fail(type != NULL);
g_return_if_fail(nick != NULL);
g_return_if_fail(fname != NULL);
if (fname == '\0') fname = "(ANY)";
switch (dcc_str2type(type))
{
case DCC_TYPE_CHAT:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CHAT_NOT_FOUND, nick);
break;
case DCC_TYPE_SEND:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_SEND_NOT_FOUND, nick, fname);
break;
case DCC_TYPE_GET:
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick, fname);
break;
}
}
static void dcc_unknown_ctcp(gchar *data, gchar *sender)
{
gchar *params, *type, *args;
g_return_if_fail(data != NULL);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &type, &args);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_CTCP, type, sender, args);
g_free(params);
}
static void dcc_unknown_reply(gchar *data, gchar *sender)
{
gchar *params, *type, *args;
g_return_if_fail(data != NULL);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &type, &args);
printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_REPLY, type, sender, args);
g_free(params);
}
static void dcc_chat_write(gchar *data)
{
DCC_REC *dcc;
gchar *params, *text, *target;
g_return_if_fail(data != NULL);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &text);
if (*target == '=')
{
/* dcc msg */
dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL);
if (dcc == NULL)
{
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
IRCTXT_DCC_CHAT_NOT_FOUND, target+1);
return;
}
printformat(NULL, target, MSGLEVEL_DCC, IRCTXT_OWN_DCC, target+1, text);
}
g_free(params);
}
static void dcc_chat_out_me(gchar *data, SERVER_REC *server, WI_IRC_REC *item)
{
DCC_REC *dcc;
g_return_if_fail(data != NULL);
dcc = irc_item_dcc_chat(item);
if (dcc == NULL) return;
printformat(NULL, item->name, MSGLEVEL_DCC,
IRCTXT_OWN_ME, dcc->mynick, data);
}
static void dcc_chat_out_action(const char *data, SERVER_REC *server, WI_IRC_REC *item)
{
char *params, *target, *text;
DCC_REC *dcc;
g_return_if_fail(data != NULL);
if (*data != '=') {
/* handle only DCC actions */
return;
}
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &text);
if (*target == '\0' || *text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL);
if (dcc == NULL){
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
IRCTXT_DCC_CHAT_NOT_FOUND, target+1);
} else {
printformat(NULL, item->name, MSGLEVEL_DCC,
IRCTXT_OWN_ME, dcc->mynick, text);
}
g_free(params);
}
static void dcc_chat_out_ctcp(gchar *data, SERVER_REC *server)
{
char *params, *target, *ctcpcmd, *ctcpdata;
DCC_REC *dcc;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata);
if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (*target != '=') {
/* handle only DCC CTCPs */
g_free(params);
return;
}
dcc = dcc_find_item(DCC_TYPE_CHAT, target+1, NULL);
if (dcc == NULL) {
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
IRCTXT_DCC_CHAT_NOT_FOUND, target+1);
} else {
g_strup(ctcpcmd);
printformat(server, target, MSGLEVEL_DCC, IRCTXT_OWN_CTCP,
target, ctcpcmd, ctcpdata);
}
g_free(params);
}
static void cmd_dcc_list(gchar *data)
{
GSList *tmp;
time_t going;
g_return_if_fail(data != NULL);
printtext(NULL, NULL, MSGLEVEL_DCC, "%gDCC connections");
for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
{
DCC_REC *dcc = tmp->data;
going = time(NULL) - dcc->starttime;
if (going == 0) going = 1; /* no division by zeros :) */
if (dcc->dcc_type == DCC_TYPE_CHAT)
printtext(NULL, NULL, MSGLEVEL_DCC, "%g %s %s", dcc->nick, dcc_type2str(dcc->dcc_type));
else
printtext(NULL, NULL, MSGLEVEL_DCC, "%g %s %s: %luk of %luk (%d%%) - %fkB/s - %s",
dcc->nick, dcc_type2str(dcc->dcc_type), dcc->transfd/1024, dcc->size/1024,
dcc->size == 0 ? 0 : (100*dcc->transfd/dcc->size),
(gdouble) (dcc->transfd-dcc->skipped)/going/1024, dcc->arg);
}
}
static void dcc_chat_closed(WINDOW_REC *window, WI_IRC_REC *item)
{
DCC_REC *dcc;
dcc = irc_item_dcc_chat(item);
if (dcc == NULL) return;
/* check that we haven't got here from dcc_destroy() so we won't try to
close the dcc again.. */
if (!dcc->destroyed) {
/* DCC query window closed, close the dcc chat too. */
dcc_destroy(dcc);
}
}
void fe_dcc_init(void)
{
signal_add("dcc connected", (SIGNAL_FUNC) dcc_connected);
signal_add("dcc rejected", (SIGNAL_FUNC) dcc_rejected);
signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
signal_add("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg);
signal_add("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_in_action);
signal_add("default dcc ctcp", (SIGNAL_FUNC) dcc_chat_ctcp);
signal_add("dcc request", (SIGNAL_FUNC) dcc_request);
signal_add("dcc error connect", (SIGNAL_FUNC) dcc_error_connect);
signal_add("dcc error file create", (SIGNAL_FUNC) dcc_error_file_create);
signal_add("dcc error file not found", (SIGNAL_FUNC) dcc_error_file_not_found);
signal_add("dcc error get not found", (SIGNAL_FUNC) dcc_error_get_not_found);
signal_add("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists);
signal_add("dcc error unknown type", (SIGNAL_FUNC) dcc_error_unknown_type);
signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
signal_add("dcc unknown ctcp", (SIGNAL_FUNC) dcc_unknown_ctcp);
signal_add("dcc unknown reply", (SIGNAL_FUNC) dcc_unknown_reply);
command_bind("msg", NULL, (SIGNAL_FUNC) dcc_chat_write);
command_bind("me", NULL, (SIGNAL_FUNC) dcc_chat_out_me);
command_bind("action", NULL, (SIGNAL_FUNC) dcc_chat_out_action);
command_bind("ctcp", NULL, (SIGNAL_FUNC) dcc_chat_out_ctcp);
command_bind("dcc ", NULL, (SIGNAL_FUNC) cmd_dcc_list);
command_bind("dcc list", NULL, (SIGNAL_FUNC) cmd_dcc_list);
signal_add("window item remove", (SIGNAL_FUNC) dcc_chat_closed);
}
void fe_dcc_deinit(void)
{
signal_remove("dcc connected", (SIGNAL_FUNC) dcc_connected);
signal_remove("dcc rejected", (SIGNAL_FUNC) dcc_rejected);
signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed);
signal_remove("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg);
signal_remove("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_in_action);
signal_remove("default dcc ctcp", (SIGNAL_FUNC) dcc_chat_ctcp);
signal_remove("dcc request", (SIGNAL_FUNC) dcc_request);
signal_remove("dcc error connect", (SIGNAL_FUNC) dcc_error_connect);
signal_remove("dcc error file create", (SIGNAL_FUNC) dcc_error_file_create);
signal_remove("dcc error file not found", (SIGNAL_FUNC) dcc_error_file_not_found);
signal_remove("dcc error get not found", (SIGNAL_FUNC) dcc_error_get_not_found);
signal_remove("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists);
signal_remove("dcc error unknown type", (SIGNAL_FUNC) dcc_error_unknown_type);
signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
signal_remove("dcc unknown ctcp", (SIGNAL_FUNC) dcc_unknown_ctcp);
signal_remove("dcc unknown reply", (SIGNAL_FUNC) dcc_unknown_reply);
command_unbind("msg", (SIGNAL_FUNC) dcc_chat_write);
command_unbind("me", (SIGNAL_FUNC) dcc_chat_out_me);
command_unbind("action", (SIGNAL_FUNC) dcc_chat_out_action);
command_unbind("ctcp", (SIGNAL_FUNC) dcc_chat_out_ctcp);
command_unbind("dcc ", (SIGNAL_FUNC) cmd_dcc_list);
command_unbind("dcc list", (SIGNAL_FUNC) cmd_dcc_list);
signal_remove("window item remove", (SIGNAL_FUNC) dcc_chat_closed);
}

View File

@ -0,0 +1,57 @@
/*
module-formats.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "printtext.h"
FORMAT_REC fecommon_irc_dcc_formats[] =
{
{ MODULE_NAME, N_("IRC"), 0 },
/* ---- */
{ NULL, N_("DCC"), 0 },
{ "own_dcc", N_("%K[%rdcc%K(%R$0%K)]%n $1"), 2, { 0, 0 } },
{ "dcc_msg", N_("%K[%G$0%K(%gdcc%K)]%n $1"), 2, { 0, 0 } },
{ "action_dcc", N_("%W (*dcc*) $0%n $1"), 2, { 0, 0 } },
{ "dcc_ctcp", N_("%g>>> DCC CTCP received from %_$0%_%K: %g$1"), 2, { 0, 0 } },
{ "dcc_chat", N_("%gDCC CHAT from %_$0%_ %K[%g$1 port $2%K]"), 3, { 0, 0, 1 } },
{ "dcc_chat_not_found", N_("%gNo DCC CHAT connection open to %_$0"), 1, { 0 } },
{ "dcc_chat_connected", N_("%gDCC %_CHAT%_ connection with %_$0%_ %K%K[%g$1 port $2%K]%g established"), 3, { 0, 0, 1 } },
{ "dcc_chat_disconnected", N_("%gDCC lost chat to %_$0"), 1, { 0 } },
{ "dcc_send", N_("%gDCC SEND from %_$0%_ %K[%g$1 port $2%K]: %g$3 %K[%g$4 bytes%K]"), 5, { 0, 0, 1, 0, 2 } },
{ "dcc_send_exists", N_("%gDCC already sending file %G$0%g for %_$1%_"), 2, { 0, 0 } },
{ "dcc_send_not_found", N_("%gDCC not sending file %G$1%g to %_$0"), 2, { 0, 0 } },
{ "dcc_send_file_not_found", N_("%gDCC file not found: %G$0%g"), 1, { 0 } },
{ "dcc_send_connected", N_("%gDCC sending file %G$0%g for %_$1%_ %K[%g$2 port $3%K]"), 4, { 0, 0, 0, 1 } },
{ "dcc_send_complete", N_("%gDCC sent file $0 %K[%g%_$1%_kb%K]%g for %_$2%_ in %_$3%_ secs %K[%g%_$4kb/s%_%K]"), 5, { 0, 2, 0, 2, 3 } },
{ "dcc_send_aborted", N_("%gDCC aborted sending file $0 for %_$1%_"), 2, { 0, 0 } },
{ "dcc_get_not_found", N_("%gDCC no file offered by %_$0"), 1, { 0 } },
{ "dcc_get_connected", N_("%gDCC receiving file %G$0%g from %_$1%_ %K[%g$2 port $3%K]"), 4, { 0, 0, 0, 1 } },
{ "dcc_get_complete", N_("%gDCC received file %G$0%g %K[%g$1kb%K]%g from %_$2%_ in %_$3%_ secs %K[%g$4kb/s%K]"), 5, { 0, 2, 0, 2, 3 } },
{ "dcc_get_aborted", N_("%gDCC aborted receiving file $0 from %_$1%_"), 2, { 0, 0 } },
{ "dcc_unknown_ctcp", N_("%gDCC unknown ctcp %G$0%g from %_$1%_ %K[%g$2%K]"), 3, { 0, 0, 0 } },
{ "dcc_unknown_reply", N_("%gDCC unknown reply %G$0%g from %_$1%_ %K[%g$2%K]"), 3, { 0, 0, 0 } },
{ "dcc_unknown_type", N_("%gDCC unknown type %_$0"), 1, { 0 } },
{ "dcc_connect_error", N_("%gDCC can't connect to %_$0%_ port %_$1"), 2, { 0, 1 } },
{ "dcc_cant_create", N_("%gDCC can't create file %G$0%g"), 1, { 0 } },
{ "dcc_rejected", N_("%gDCC %G$0%g was rejected by %_$1%_ %K[%G$2%K]"), 3, { 0, 0, 0 } },
{ "dcc_close", N_("%gDCC %G$0%g close for %_$1%_ %K[%G$2%K]"), 3, { 0, 0, 0 } }
};

View File

@ -0,0 +1,37 @@
#include "printtext.h"
enum {
IRCTXT_MODULE_NAME,
IRCTXT_FILL_1,
IRCTXT_OWN_DCC,
IRCTXT_DCC_MSG,
IRCTXT_ACTION_DCC,
IRCTXT_DCC_CTCP,
IRCTXT_DCC_CHAT,
IRCTXT_DCC_CHAT_NOT_FOUND,
IRCTXT_DCC_CHAT_CONNECTED,
IRCTXT_DCC_CHAT_DISCONNECTED,
IRCTXT_DCC_SEND,
IRCTXT_DCC_SEND_EXISTS,
IRCTXT_DCC_SEND_NOT_FOUND,
IRCTXT_DCC_SEND_FILE_NOT_FOUND,
IRCTXT_DCC_SEND_CONNECTED,
IRCTXT_DCC_SEND_COMPLETE,
IRCTXT_DCC_SEND_ABORTED,
IRCTXT_DCC_GET_NOT_FOUND,
IRCTXT_DCC_GET_CONNECTED,
IRCTXT_DCC_GET_COMPLETE,
IRCTXT_DCC_GET_ABORTED,
IRCTXT_DCC_UNKNOWN_CTCP,
IRCTXT_DCC_UNKNOWN_REPLY,
IRCTXT_DCC_UNKNOWN_TYPE,
IRCTXT_DCC_CONNECT_ERROR,
IRCTXT_DCC_CANT_CREATE,
IRCTXT_DCC_REJECTED,
IRCTXT_DCC_CLOSE,
};
extern FORMAT_REC fecommon_irc_dcc_formats[];
#define MODULE_FORMATS fecommon_irc_dcc_formats

View File

@ -0,0 +1,123 @@
/*
fe-channels.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "levels.h"
#include "irc.h"
#include "channels.h"
#include "windows.h"
#include "window-items.h"
static void signal_channel_created(CHANNEL_REC *channel, gpointer automatic)
{
window_item_create((WI_ITEM_REC *) channel, GPOINTER_TO_INT(automatic));
}
static void signal_channel_created_curwin(CHANNEL_REC *channel)
{
g_return_if_fail(channel != NULL);
window_add_item(active_win, (WI_ITEM_REC *) channel, FALSE);
signal_stop();
}
static void signal_channel_destroyed(CHANNEL_REC *channel)
{
WINDOW_REC *window;
g_return_if_fail(channel != NULL);
window = window_item_window((WI_ITEM_REC *) channel);
if (window != NULL) window_remove_item(window, (WI_ITEM_REC *) channel);
}
static void signal_window_item_removed(WINDOW_REC *window, WI_ITEM_REC *item)
{
CHANNEL_REC *channel;
g_return_if_fail(window != NULL);
channel = irc_item_channel(item);
if (channel != NULL) channel_destroy(channel);
}
static void sig_disconnected(IRC_SERVER_REC *server)
{
WINDOW_REC *window;
GSList *tmp;
g_return_if_fail(server != NULL);
if (!irc_server_check(server))
return;
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *channel = tmp->data;
window = window_item_window((WI_ITEM_REC *) channel);
window->waiting_channels =
g_slist_append(window->waiting_channels, g_strdup_printf("%s %s", server->tag, channel->name));
}
}
static void signal_window_item_changed(WINDOW_REC *window, WI_ITEM_REC *item)
{
g_return_if_fail(item != NULL);
if (g_slist_length(window->items) > 1 && irc_item_channel(item)) {
printformat(item->server, item->name, MSGLEVEL_CLIENTNOTICE,
IRCTXT_TALKING_IN, item->name);
signal_stop();
}
}
static void cmd_wjoin(const char *data, void *server, WI_ITEM_REC *item)
{
signal_add("channel created", (SIGNAL_FUNC) signal_channel_created_curwin);
signal_emit("command join", 3, data, server, item);
signal_remove("channel created", (SIGNAL_FUNC) signal_channel_created_curwin);
}
void fe_channels_init(void)
{
signal_add("channel created", (SIGNAL_FUNC) signal_channel_created);
signal_add("channel destroyed", (SIGNAL_FUNC) signal_channel_destroyed);
signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_removed);
signal_add_last("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected);
command_bind("wjoin", NULL, (SIGNAL_FUNC) cmd_wjoin);
}
void fe_channels_deinit(void)
{
signal_remove("channel created", (SIGNAL_FUNC) signal_channel_created);
signal_remove("channel destroyed", (SIGNAL_FUNC) signal_channel_destroyed);
signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_removed);
signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_changed);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
command_unbind("wjoin", (SIGNAL_FUNC) cmd_wjoin);
}

View File

@ -0,0 +1,172 @@
/*
fe-common-irc.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "args.h"
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "server-setup.h"
#include "completion.h"
void fe_channels_init(void);
void fe_channels_deinit(void);
void fe_irc_commands_init(void);
void fe_irc_commands_deinit(void);
void fe_ctcp_init(void);
void fe_ctcp_deinit(void);
void fe_dcc_init(void);
void fe_dcc_deinit(void);
void fe_events_init(void);
void fe_events_deinit(void);
void fe_events_numeric_init(void);
void fe_events_numeric_deinit(void);
void fe_ignore_init(void);
void fe_ignore_deinit(void);
void fe_query_init(void);
void fe_query_deinit(void);
void irc_nick_hilight_init(void);
void irc_nick_hilight_deinit(void);
void fe_notifylist_init(void);
void fe_notifylist_deinit(void);
void fe_flood_init(void);
void fe_flood_deinit(void);
static char *autocon_server;
static char *autocon_password;
static int autocon_port;
static int no_autoconnect;
static char *cmdline_nick;
static char *cmdline_hostname;
void fe_common_irc_init(void)
{
static struct poptOption options[] = {
{ "connect", 'c', POPT_ARG_STRING, &autocon_server, 0, N_("Automatically connect to server/ircnet"), N_("SERVER") },
{ "password", 'w', POPT_ARG_STRING, &autocon_password, 0, N_("Autoconnect password"), N_("SERVER") },
{ "port", 'p', POPT_ARG_INT, &autocon_port, 0, N_("Autoconnect port"), N_("PORT") },
{ "noconnect", '!', POPT_ARG_NONE, &no_autoconnect, 0, N_("Disable autoconnecting"), NULL },
{ "nick", 'n', POPT_ARG_STRING, &cmdline_nick, 0, N_("Specify nick to use"), NULL },
{ "hostname", 'h', POPT_ARG_STRING, &cmdline_hostname, 0, N_("Specify host name to use"), NULL },
{ NULL, '\0', 0, NULL }
};
autocon_server = NULL;
autocon_password = NULL;
autocon_port = 6667;
no_autoconnect = FALSE;
cmdline_nick = NULL;
cmdline_hostname = NULL;
args_register(options);
settings_add_str("lookandfeel", "beep_on_msg", "");
settings_add_bool("lookandfeel", "beep_when_away", TRUE);
settings_add_bool("lookandfeel", "show_away_once", TRUE);
settings_add_bool("lookandfeel", "show_quit_once", FALSE);
fe_channels_init();
fe_irc_commands_init();
fe_ctcp_init();
fe_dcc_init();
fe_events_init();
fe_events_numeric_init();
fe_ignore_init();
fe_notifylist_init();
fe_flood_init();
fe_query_init();
completion_init();
irc_nick_hilight_init();
}
void fe_common_irc_deinit(void)
{
fe_channels_deinit();
fe_irc_commands_deinit();
fe_ctcp_deinit();
fe_dcc_deinit();
fe_events_deinit();
fe_events_numeric_deinit();
fe_ignore_deinit();
fe_notifylist_deinit();
fe_flood_deinit();
fe_query_deinit();
completion_deinit();
irc_nick_hilight_deinit();
}
void fe_common_irc_finish_init(void)
{
GSList *tmp, *ircnets;
char *str;
if (cmdline_nick != NULL) {
/* override nick found from setup */
iconfig_set_str("settings", "default_nick", cmdline_nick);
}
if (cmdline_hostname != NULL) {
/* override host name found from setup */
iconfig_set_str("settings", "hostname", cmdline_hostname);
}
if (autocon_server != NULL) {
/* connect to specified server */
str = g_strdup_printf(autocon_password == NULL ? "%s %d" : "%s %d %s",
autocon_server, autocon_port, autocon_password);
signal_emit("command connect", 1, str);
g_free(str);
return;
}
if (no_autoconnect) {
/* don't autoconnect */
return;
}
/* connect to autoconnect servers */
ircnets = NULL;
for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
SETUP_SERVER_REC *rec = tmp->data;
if (rec->autoconnect && (*rec->ircnet == '\0' || gslist_find_icase_string(ircnets, rec->ircnet) == NULL)) {
if (*rec->ircnet != '\0')
ircnets = g_slist_append(ircnets, rec->ircnet);
str = g_strdup_printf("%s %d", rec->server, rec->port);
signal_emit("command connect", 1, str);
g_free(str);
}
}
g_slist_free(ircnets);
}

View File

@ -0,0 +1,8 @@
#ifndef __FE_COMMON_IRC_H
#define __FE_COMMON_IRC_H
void fe_common_irc_init(void);
void fe_common_irc_deinit(void);
void fe_common_irc_finish_init(void);
#endif

110
src/fe-common/irc/fe-ctcp.c Normal file
View File

@ -0,0 +1,110 @@
/*
fe-ctcp.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "misc.h"
#include "settings.h"
#include "irc.h"
#include "levels.h"
#include "server.h"
#include "channels.h"
#include "query.h"
#include "ignore.h"
#include "windows.h"
#include "window-items.h"
static void ctcp_print(const char *pre, const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
{
char *str;
g_return_if_fail(data != NULL);
str = g_strconcat(pre, " ", data, NULL);
printformat(server, ischannel(*target) ? target : nick, MSGLEVEL_CTCPS,
IRCTXT_CTCP_REQUESTED, nick, addr, str, target);
g_free(str);
}
static void ctcp_default_msg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
{
return ctcp_print("unknown CTCP", data, server, nick, addr, target);
}
static void ctcp_ping_msg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
{
return ctcp_print("CTCP PING", data, server, nick, addr, target);
}
static void ctcp_version_msg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
{
return ctcp_print("CTCP VERSION", data, server, nick, addr, target);
}
static void ctcp_default_reply(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
{
char *ptr, *str;
g_return_if_fail(data != NULL);
str = g_strdup(data);
ptr = strchr(str, ' ');
if (ptr != NULL) *ptr++ = '\0'; else ptr = "";
printformat(server, ischannel(*target) ? target : nick, MSGLEVEL_CTCPS,
IRCTXT_CTCP_REPLY, str, nick, ptr);
g_free(str);
}
static void ctcp_ping_reply(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr, const char *target)
{
GTimeVal tv, tv2;
long usecs;
g_return_if_fail(data != NULL);
if (sscanf(data, "%ld %ld", &tv2.tv_sec, &tv2.tv_usec) != 2)
return;
g_get_current_time(&tv);
usecs = get_timeval_diff(&tv, &tv2);
printformat(server, ischannel(*target) ? target : nick, MSGLEVEL_CTCPS,
IRCTXT_CTCP_PING_REPLY, nick, usecs/1000, usecs%1000);
}
void fe_ctcp_init(void)
{
signal_add("default ctcp msg", (SIGNAL_FUNC) ctcp_default_msg);
signal_add("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping_msg);
signal_add("ctcp msg version", (SIGNAL_FUNC) ctcp_version_msg);
signal_add("default ctcp reply", (SIGNAL_FUNC) ctcp_default_reply);
signal_add("ctcp reply ping", (SIGNAL_FUNC) ctcp_ping_reply);
}
void fe_ctcp_deinit(void)
{
signal_remove("default ctcp msg", (SIGNAL_FUNC) ctcp_default_msg);
signal_remove("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping_msg);
signal_remove("ctcp msg version", (SIGNAL_FUNC) ctcp_version_msg);
signal_remove("default ctcp reply", (SIGNAL_FUNC) ctcp_default_reply);
signal_remove("ctcp reply ping", (SIGNAL_FUNC) ctcp_ping_reply);
}

View File

@ -0,0 +1,707 @@
/*
fe-events-numeric.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "settings.h"
#include "irc.h"
#include "levels.h"
#include "server.h"
#include "channels.h"
#include "nicklist.h"
static char *last_away_nick = NULL;
static char *last_away_msg = NULL;
static void event_user_mode(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *mode;
g_return_if_fail(data != NULL);
g_return_if_fail(server != NULL);
params = event_get_params(data, 2, NULL, &mode);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_USER_MODE, mode);
g_free(params);
}
static void event_ison(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *online;
g_return_if_fail(data != NULL);
g_return_if_fail(server != NULL);
params = event_get_params(data, 2, NULL, &online);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_ONLINE, online);
g_free(params);
}
static void event_names_list(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *names;
g_return_if_fail(data != NULL);
params = event_get_params(data, 4, NULL, NULL, &channel, &names);
if (channel_find(server, channel) == NULL)
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_NAMES, channel, names);
g_free(params);
}
static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist, gint items, gint max)
{
NICK_REC *rec, *last;
GString *str;
GSList *tmp;
gint lines, cols, line, col, skip;
gchar *linebuf;
max++; /* op/voice */
str = g_string_new(NULL);
cols = max > 65 ? 1 : (65 / (max+3)); /* "[] " */
lines = items <= cols ? 1 : items / cols+1;
last = NULL; linebuf = g_malloc(max+1); linebuf[max] = '\0';
for (line = 0, col = 0, skip = 1, tmp = nicklist; line < lines; last = rec, tmp = tmp->next)
{
rec = tmp->data;
if (--skip == 0)
{
skip = lines;
memset(linebuf, ' ', max);
linebuf[0] = rec->op ? '@' : rec->voice ? '+' : ' ';
memcpy(linebuf+1, rec->nick, strlen(rec->nick));
g_string_sprintfa(str, "%%K[%%n%%_%c%%_%s%%K] ", linebuf[0], linebuf+1);
cols++;
}
if (col == cols || tmp->next == NULL)
{
printtext(channel->server, channel->name, MSGLEVEL_CLIENTCRAP, str->str);
g_string_truncate(str, 0);
col = 0; line++;
tmp = g_slist_nth(nicklist, line-1); skip = 1;
}
}
if (str->len != 0)
printtext(channel->server, channel->name, MSGLEVEL_CLIENTCRAP, str->str);
g_string_free(str, TRUE);
g_free(linebuf);
}
static void display_nicks(CHANNEL_REC *channel)
{
NICK_REC *nick;
GSList *tmp, *nicklist, *sorted;
gint nicks, normal, voices, ops, len, max;
nicks = normal = voices = ops = 0;
nicklist = nicklist_getnicks(channel);
sorted = NULL;
/* sort the nicklist */
max = 0;
for (tmp = nicklist; tmp != NULL; tmp = tmp->next)
{
nick = tmp->data;
sorted = g_slist_insert_sorted(sorted, nick, (GCompareFunc) nicklist_compare);
if (nick->op)
ops++;
else if (nick->voice)
voices++;
else
normal++;
nicks++;
len = strlen(nick->nick);
if (len > max) max = len;
}
g_slist_free(nicklist);
/* display the nicks */
printformat(channel->server, channel->name, MSGLEVEL_CRAP, IRCTXT_NAMES, channel->name, "");
display_sorted_nicks(channel, sorted, nicks, max);
g_slist_free(sorted);
printformat(channel->server, channel->name, MSGLEVEL_CRAP, IRCTXT_ENDOFNAMES,
channel->name, nicks, ops, voices, normal);
}
static void event_end_of_names(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel;
CHANNEL_REC *chanrec;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
chanrec = channel_find(server, channel);
if (chanrec == NULL)
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_ENDOFNAMES, channel, 0, 0, 0, 0);
else
display_nicks(chanrec);
g_free(params);
}
static void event_who(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *channel, *user, *host, *stat, *realname, *hops;
g_return_if_fail(data != NULL);
params = event_get_params(data, 8, NULL, &channel, &user, &host, NULL, &nick, &stat, &realname);
/* split hops/realname */
hops = realname;
while (*realname != '\0' && *realname != ' ') realname++;
while (*realname == ' ') realname++;
if (realname > hops) realname[-1] = '\0';
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHO,
channel, nick, stat, hops, user, host, realname);
g_free(params);
}
static void event_end_of_who(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_END_OF_WHO, channel);
g_free(params);
}
static void event_ban_list(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *ban, *setby, *tims;
glong secs, tim;
g_return_if_fail(data != NULL);
params = event_get_params(data, 5, NULL, &channel, &ban, &setby, &tims);
if (sscanf(tims, "%ld", &tim) != 1) tim = (glong) time(NULL);
secs = (glong) time(NULL)-tim;
printformat(server, channel, MSGLEVEL_CRAP,
*setby == '\0' ? IRCTXT_BANLIST : IRCTXT_BANLIST_LONG,
channel, ban, setby, secs);
g_free(params);
}
static void event_eban_list(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *ban, *setby, *tims;
glong secs, tim;
g_return_if_fail(data != NULL);
params = event_get_params(data, 5, NULL, &channel, &ban, &setby, &tims);
if (sscanf(tims, "%ld", &tim) != 1) tim = (glong) time(NULL);
secs = (glong) time(NULL)-tim;
printformat(server, channel, MSGLEVEL_CRAP,
*setby == '\0' ? IRCTXT_EBANLIST : IRCTXT_EBANLIST_LONG,
channel, ban, setby, secs);
g_free(params);
}
static void event_invite_list(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *invite;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3, NULL, &channel, &invite);
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_INVITELIST, channel, invite);
g_free(params);
}
static void event_nick_in_use(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &nick);
if (server->connected)
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_NICK_IN_USE, nick);
g_free(params);
}
static void event_topic_get(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *topic;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3, NULL, &channel, &topic);
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_TOPIC, channel, topic);
g_free(params);
}
static void event_topic_info(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *timestr, *channel, *topicby, *topictime;
glong ltime;
time_t t;
struct tm *tim;
g_return_if_fail(data != NULL);
params = event_get_params(data, 4, NULL, &channel, &topicby, &topictime);
if (sscanf(topictime, "%lu", &ltime) != 1) ltime = 0; /* topic set date */
t = (time_t) ltime;
tim = localtime(&t);
timestr = g_strdup(asctime(tim));
if (timestr[strlen(timestr)-1] == '\n') timestr[strlen(timestr)-1] = '\0';
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_TOPIC_INFO, topicby, timestr);
g_free(timestr);
g_free(params);
}
static void event_channel_mode(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *mode;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3 | PARAM_FLAG_GETREST, NULL, &channel, &mode);
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_CHANNEL_MODE, channel, mode);
g_free(params);
}
static void event_channel_created(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel, *times, *timestr;
glong timeval;
time_t t;
struct tm *tim;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3, NULL, &channel, &times);
if (sscanf(times, "%ld", &timeval) != 1) timeval = 0;
t = (time_t) timeval;
tim = localtime(&t);
timestr = g_strdup(asctime(tim));
if (timestr[strlen(timestr)-1] == '\n') timestr[strlen(timestr)-1] = '\0';
printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_CHANNEL_CREATED, channel, timestr);
g_free(timestr);
g_free(params);
}
static void event_away(gchar *data, IRC_SERVER_REC *server)
{
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_AWAY);
}
static void event_unaway(gchar *data, IRC_SERVER_REC *server)
{
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_UNAWAY);
}
static void event_userhost(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *hosts;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &hosts);
printtext(server, NULL, MSGLEVEL_CRAP, "%s", hosts);
g_free(params);
}
static void event_whois(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *user, *host, *realname;
g_return_if_fail(data != NULL);
params = event_get_params(data, 6, NULL, &nick, &user, &host, NULL, &realname);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHOIS, nick, user, host, realname);
g_free(params);
}
static void event_whois_idle(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *secstr, *signon, *rest;
glong secs, lsignon;
gint h, m, s;
g_return_if_fail(data != NULL);
params = event_get_params(data, 5 | PARAM_FLAG_GETREST, NULL, &nick, &secstr, &signon, &rest);
if (sscanf(secstr, "%ld", &secs) == 0) secs = 0;
lsignon = 0;
if (strstr(rest, ", signon time") != NULL)
sscanf(signon, "%ld", &lsignon);
h = secs/3600; m = (secs%3600)/60; s = secs%60;
if (lsignon == 0)
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHOIS_IDLE, nick, h, m, s);
else
{
gchar *timestr;
struct tm *tim;
time_t t;
t = (time_t) lsignon;
tim = localtime(&t);
timestr = g_strdup(asctime(tim));
if (timestr[strlen(timestr)-1] == '\n') timestr[strlen(timestr)-1] = '\0';
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHOIS_IDLE_SIGNON, nick, h, m, s, timestr);
g_free(timestr);
}
g_free(params);
}
static void event_whois_server(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *whoserver, *desc;
g_return_if_fail(data != NULL);
params = event_get_params(data, 4, NULL, &nick, &whoserver, &desc);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHOIS_SERVER, nick, whoserver, desc);
g_free(params);
}
static void event_whois_oper(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &nick);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHOIS_OPER, nick);
g_free(params);
}
static void event_whois_channels(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *chans;
GString *str;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3, NULL, &nick, &chans);
str = g_string_new(NULL);
for (; *chans != '\0'; chans++)
{
if ((unsigned char) *chans >= 32)
g_string_append_c(str, *chans);
else
{
g_string_append_c(str, '^');
g_string_append_c(str, *chans+'A'-1);
}
}
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHOIS_CHANNELS, nick, str->str);
g_free(params);
g_string_free(str, TRUE);
}
static void event_whois_away(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *awaymsg;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3, NULL, &nick, &awaymsg);
if (server->whois_coming || !settings_get_bool("show_away_once") ||
last_away_nick == NULL || g_strcasecmp(last_away_nick, nick) != 0 ||
last_away_msg == NULL || g_strcasecmp(last_away_msg, awaymsg) != 0) {
/* don't show the same away message from the same nick all the time */
g_free_not_null(last_away_nick);
g_free_not_null(last_away_msg);
last_away_nick = g_strdup(nick);
last_away_msg = g_strdup(awaymsg);
printformat(server, NULL, MSGLEVEL_CRAP, server->whois_coming ?
IRCTXT_WHOIS_AWAY : IRCTXT_NICK_AWAY, nick, awaymsg);
}
g_free(params);
}
static void event_end_of_whois(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &nick);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_END_OF_WHOIS, nick);
g_free(params);
}
static void event_target_unavailable(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
if (!ischannel(*channel))
{
/* nick unavailable */
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_NICK_UNAVAILABLE, channel);
}
else
{
/* channel is unavailable. */
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_JOINERROR_UNAVAIL, channel);
}
g_free(params);
}
static void event_no_such_nick(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &nick);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_NO_SUCH_NICK, nick);
g_free(params);
}
static void event_no_such_channel(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_NO_SUCH_CHANNEL, channel);
g_free(params);
}
static void cannot_join(gchar *data, IRC_SERVER_REC *server, gint format)
{
gchar *params, *channel;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
printformat(server, NULL, MSGLEVEL_CRAP, format, channel);
g_free(params);
}
static void event_too_many_channels(gchar *data, IRC_SERVER_REC *server)
{
cannot_join(data, server, IRCTXT_JOINERROR_TOOMANY);
}
static void event_channel_is_full(gchar *data, IRC_SERVER_REC *server)
{
cannot_join(data, server, IRCTXT_JOINERROR_FULL);
}
static void event_invite_only(gchar *data, IRC_SERVER_REC *server)
{
cannot_join(data, server, IRCTXT_JOINERROR_INVITE);
}
static void event_banned(gchar *data, IRC_SERVER_REC *server)
{
cannot_join(data, server, IRCTXT_JOINERROR_BANNED);
}
static void event_bad_channel_key(gchar *data, IRC_SERVER_REC *server)
{
cannot_join(data, server, IRCTXT_JOINERROR_BAD_KEY);
}
static void event_bad_channel_mask(gchar *data, IRC_SERVER_REC *server)
{
cannot_join(data, server, IRCTXT_JOINERROR_BAD_MASK);
}
static void event_unknown_mode(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *mode;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &mode);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_UNKNOWN_MODE, mode);
g_free(params);
}
static void event_not_chanop(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *channel;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_NOT_CHANOP, channel);
g_free(params);
}
static void event_received(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
gchar *params, *args, *ptr;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, NULL, &args);
ptr = strstr(args, " :");
if (ptr != NULL) *(ptr+1) = ' ';
printtext(server, NULL, MSGLEVEL_CRAP, "%s", args);
g_free(params);
}
static void event_motd(gchar *data, SERVER_REC *server, gchar *nick, gchar *addr)
{
/* numeric event. */
gchar *params, *args, *ptr;
if (settings_get_bool("toggle_skip_motd"))
return;
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, NULL, &args);
ptr = strstr(args, " :");
if (ptr != NULL) *(ptr+1) = ' ';
printtext(server, NULL, MSGLEVEL_CRAP, "%s", args);
g_free(params);
}
void fe_events_numeric_init(void)
{
last_away_nick = NULL;
last_away_msg = NULL;
signal_add("event 221", (SIGNAL_FUNC) event_user_mode);
signal_add("event 303", (SIGNAL_FUNC) event_ison);
signal_add("event 353", (SIGNAL_FUNC) event_names_list);
signal_add("event 366", (SIGNAL_FUNC) event_end_of_names);
signal_add("event 352", (SIGNAL_FUNC) event_who);
signal_add("event 315", (SIGNAL_FUNC) event_end_of_who);
signal_add("event 367", (SIGNAL_FUNC) event_ban_list);
signal_add("event 348", (SIGNAL_FUNC) event_eban_list);
signal_add("event 346", (SIGNAL_FUNC) event_invite_list);
signal_add("event 433", (SIGNAL_FUNC) event_nick_in_use);
signal_add("event 332", (SIGNAL_FUNC) event_topic_get);
signal_add("event 333", (SIGNAL_FUNC) event_topic_info);
signal_add("event 324", (SIGNAL_FUNC) event_channel_mode);
signal_add("event 329", (SIGNAL_FUNC) event_channel_created);
signal_add("event 306", (SIGNAL_FUNC) event_away);
signal_add("event 305", (SIGNAL_FUNC) event_unaway);
signal_add("event 311", (SIGNAL_FUNC) event_whois);
signal_add("event 301", (SIGNAL_FUNC) event_whois_away);
signal_add("event 312", (SIGNAL_FUNC) event_whois_server);
signal_add("event 313", (SIGNAL_FUNC) event_whois_oper);
signal_add("event 317", (SIGNAL_FUNC) event_whois_idle);
signal_add("event 318", (SIGNAL_FUNC) event_end_of_whois);
signal_add("event 319", (SIGNAL_FUNC) event_whois_channels);
signal_add("event 302", (SIGNAL_FUNC) event_userhost);
signal_add("event 437", (SIGNAL_FUNC) event_target_unavailable);
signal_add("event 401", (SIGNAL_FUNC) event_no_such_nick);
signal_add("event 403", (SIGNAL_FUNC) event_no_such_channel);
signal_add("event 405", (SIGNAL_FUNC) event_too_many_channels);
signal_add("event 471", (SIGNAL_FUNC) event_channel_is_full);
signal_add("event 472", (SIGNAL_FUNC) event_unknown_mode);
signal_add("event 473", (SIGNAL_FUNC) event_invite_only);
signal_add("event 474", (SIGNAL_FUNC) event_banned);
signal_add("event 475", (SIGNAL_FUNC) event_bad_channel_key);
signal_add("event 476", (SIGNAL_FUNC) event_bad_channel_mask);
signal_add("event 482", (SIGNAL_FUNC) event_not_chanop);
signal_add("event 375", (SIGNAL_FUNC) event_motd);
signal_add("event 376", (SIGNAL_FUNC) event_motd);
signal_add("event 372", (SIGNAL_FUNC) event_motd);
signal_add("event 004", (SIGNAL_FUNC) event_received);
signal_add("event 364", (SIGNAL_FUNC) event_received);
signal_add("event 365", (SIGNAL_FUNC) event_received);
}
void fe_events_numeric_deinit(void)
{
g_free_not_null(last_away_nick);
g_free_not_null(last_away_msg);
signal_remove("event 221", (SIGNAL_FUNC) event_user_mode);
signal_remove("event 303", (SIGNAL_FUNC) event_ison);
signal_remove("event 353", (SIGNAL_FUNC) event_names_list);
signal_remove("event 366", (SIGNAL_FUNC) event_end_of_names);
signal_remove("event 352", (SIGNAL_FUNC) event_who);
signal_remove("event 315", (SIGNAL_FUNC) event_end_of_who);
signal_remove("event 367", (SIGNAL_FUNC) event_ban_list);
signal_remove("event 348", (SIGNAL_FUNC) event_eban_list);
signal_remove("event 346", (SIGNAL_FUNC) event_invite_list);
signal_remove("event 433", (SIGNAL_FUNC) event_nick_in_use);
signal_remove("event 332", (SIGNAL_FUNC) event_topic_get);
signal_remove("event 333", (SIGNAL_FUNC) event_topic_info);
signal_remove("event 324", (SIGNAL_FUNC) event_channel_mode);
signal_remove("event 329", (SIGNAL_FUNC) event_channel_created);
signal_remove("event 306", (SIGNAL_FUNC) event_away);
signal_remove("event 305", (SIGNAL_FUNC) event_unaway);
signal_remove("event 311", (SIGNAL_FUNC) event_whois);
signal_remove("event 301", (SIGNAL_FUNC) event_whois_away);
signal_remove("event 312", (SIGNAL_FUNC) event_whois_server);
signal_remove("event 313", (SIGNAL_FUNC) event_whois_oper);
signal_remove("event 317", (SIGNAL_FUNC) event_whois_idle);
signal_remove("event 318", (SIGNAL_FUNC) event_end_of_whois);
signal_remove("event 319", (SIGNAL_FUNC) event_whois_channels);
signal_remove("event 302", (SIGNAL_FUNC) event_userhost);
signal_remove("event 437", (SIGNAL_FUNC) event_target_unavailable);
signal_remove("event 401", (SIGNAL_FUNC) event_no_such_nick);
signal_remove("event 403", (SIGNAL_FUNC) event_no_such_channel);
signal_remove("event 405", (SIGNAL_FUNC) event_too_many_channels);
signal_remove("event 471", (SIGNAL_FUNC) event_channel_is_full);
signal_remove("event 472", (SIGNAL_FUNC) event_unknown_mode);
signal_remove("event 473", (SIGNAL_FUNC) event_invite_only);
signal_remove("event 474", (SIGNAL_FUNC) event_banned);
signal_remove("event 475", (SIGNAL_FUNC) event_bad_channel_key);
signal_remove("event 476", (SIGNAL_FUNC) event_bad_channel_mask);
signal_remove("event 482", (SIGNAL_FUNC) event_not_chanop);
signal_remove("event 375", (SIGNAL_FUNC) event_motd);
signal_remove("event 376", (SIGNAL_FUNC) event_motd);
signal_remove("event 372", (SIGNAL_FUNC) event_motd);
signal_remove("event 004", (SIGNAL_FUNC) event_received);
signal_remove("event 364", (SIGNAL_FUNC) event_received);
signal_remove("event 365", (SIGNAL_FUNC) event_received);
}

View File

@ -0,0 +1,682 @@
/*
fe-events.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "settings.h"
#include "irc.h"
#include "levels.h"
#include "server.h"
#include "server-redirect.h"
#include "server-reconnect.h"
#include "channels.h"
#include "query.h"
#include "nicklist.h"
#include "ignore.h"
#include "irc-hilight-text.h"
#include "windows.h"
#include "completion.h"
static int beep_msg_level, beep_when_away;
static void msg_beep_check(IRC_SERVER_REC *server, int level)
{
if (level != 0 && (beep_msg_level & level) &&
(!server->usermode_away || beep_when_away)) {
printbeep();
}
}
static void event_privmsg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
CHANNEL_REC *chanrec;
WI_ITEM_REC *item;
gchar *params, *target, *msg, *nickmode;
int level;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (nick == NULL) nick = server->real_address;
level = 0;
if (*msg == 1)
{
/* ctcp message, handled in fe-ctcp.c */
}
else if (ignore_check(server, nick, addr, target, msg,
ischannel(*target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS))
{
/* ignored */
}
else if (ischannel(*target))
{
/* message to some channel */
WINDOW_REC *window;
NICK_REC *nickrec;
gboolean toyou;
gchar *color;
chanrec = channel_find(server, target);
toyou = completion_msgtoyou((SERVER_REC *) server, msg);
color = irc_hilight_find_nick(target, nick, addr);
nickrec = chanrec == NULL ? NULL : nicklist_find(chanrec, nick);
nickmode = !settings_get_bool("toggle_show_nickmode") || nickrec == NULL ? "" :
nickrec->op ? "@" : nickrec->voice ? "+" : " ";
window = chanrec == NULL ? NULL : window_item_window((WI_ITEM_REC *) chanrec);
if (window != NULL && window->active == (WI_ITEM_REC *) chanrec)
{
/* message to active channel in window */
if (color != NULL)
{
/* highlighted nick */
printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT,
IRCTXT_PUBMSG_HILIGHT, color, nick, msg, nickmode);
}
else
{
printformat(server, target, MSGLEVEL_PUBLIC | (toyou ? MSGLEVEL_NOHILIGHT : 0),
toyou ? IRCTXT_PUBMSG_ME : IRCTXT_PUBMSG, nick, msg, nickmode);
}
}
else
{
/* message to not existing/active channel */
if (color != NULL)
{
/* highlighted nick */
printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT,
IRCTXT_PUBMSG_HILIGHT_CHANNEL, color, nick, target, msg, nickmode);
}
else
{
printformat(server, target, MSGLEVEL_PUBLIC | (toyou ? MSGLEVEL_NOHILIGHT : 0),
toyou ? IRCTXT_PUBMSG_ME_CHANNEL : IRCTXT_PUBMSG_CHANNEL,
nick, target, msg, nickmode);
}
}
g_free_not_null(color);
level = MSGLEVEL_PUBLIC;
}
else
{
/* private message */
if (settings_get_bool("toggle_autocreate_query") && query_find(server, nick) == NULL)
item = (WI_ITEM_REC *) query_create(server, nick, TRUE);
else
item = (WI_ITEM_REC *) query_find(server, nick);
printformat(server, nick, MSGLEVEL_MSGS,
item == NULL ? IRCTXT_MSG_PRIVATE : IRCTXT_MSG_PRIVATE_QUERY, nick, addr == NULL ? "" : addr, msg);
level = MSGLEVEL_MSGS;
}
msg_beep_check(server, level);
g_free(params);
}
/* we use "ctcp msg" here because "ctcp msg action" can be ignored with
/IGNORE * CTCPS */
static void ctcp_action_msg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr, gchar *target)
{
WINDOW_REC *window;
CHANNEL_REC *channel;
WI_ITEM_REC *item;
int level;
g_return_if_fail(data != NULL);
if (g_strncasecmp(data, "ACTION ", 7) != 0)
return;
data += 7;
level = 0;
if (ignore_check(server, nick, addr, target, data, MSGLEVEL_ACTIONS))
{
/* ignored */
}
else if (ischannel(*target))
{
/* channel action */
channel = channel_find(server, target);
window = channel == NULL ? NULL : window_item_window((WI_ITEM_REC *) channel);
if (window != NULL && window->active == (WI_ITEM_REC *) channel)
{
/* message to active channel in window */
printformat(server, target, MSGLEVEL_ACTIONS,
IRCTXT_ACTION_PUBLIC, nick, data);
}
else
{
/* message to not existing/active channel */
printformat(server, target, MSGLEVEL_ACTIONS,
IRCTXT_ACTION_PUBLIC_CHANNEL, nick, target, data);
}
level = MSGLEVEL_PUBLIC;
}
else
{
/* private action */
if (settings_get_bool("toggle_autocreate_query") && query_find(server, nick) == NULL)
item = (WI_ITEM_REC *) query_create(server, nick, TRUE);
else
item = (WI_ITEM_REC *) channel_find(server, nick);
printformat(server, nick, MSGLEVEL_ACTIONS,
item == NULL ? IRCTXT_ACTION_PRIVATE : IRCTXT_ACTION_PRIVATE_QUERY, nick, addr == NULL ? "" : addr, data);
level = MSGLEVEL_MSGS;
}
msg_beep_check(server, level);
}
static void event_notice(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
char *params, *target, *msg;
int level;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (nick == NULL) nick = server->real_address;
level = 0;
if (*msg == 1)
{
/* ctcp reply */
}
else if (addr == NULL)
{
/* notice from server */
if (nick == NULL || !ignore_check(server, nick, "", target, msg, MSGLEVEL_SNOTES))
printformat(server, target, MSGLEVEL_SNOTES, IRCTXT_NOTICE_SERVER, nick == NULL ? "" : nick, msg);
}
else if (ischannel(*target) || (*target == '@' && ischannel(target[1])))
{
/* notice in some channel */
if (!ignore_check(server, nick, addr, target, msg, MSGLEVEL_NOTICES))
printformat(server, target, MSGLEVEL_NOTICES,
*target == '@' ? IRCTXT_NOTICE_PUBLIC_OPS : IRCTXT_NOTICE_PUBLIC,
nick, *target == '@' ? target+1 : target, msg);
level = MSGLEVEL_NOTICES;
}
else
{
/* private notice */
if (!ignore_check(server, nick, addr, NULL, msg, MSGLEVEL_NOTICES))
printformat(server, nick, MSGLEVEL_NOTICES, IRCTXT_NOTICE_PRIVATE, nick, addr, msg);
level = MSGLEVEL_NOTICES;
}
msg_beep_check(server, level);
g_free(params);
}
static void event_join(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
gchar *params, *channel, *tmp;
g_return_if_fail(data != NULL);
params = event_get_params(data, 1, &channel);
tmp = strchr(channel, 7); /* ^G does something weird.. */
if (tmp != NULL) *tmp = '\0';
if (!ignore_check(server, nick, addr, channel, NULL, MSGLEVEL_JOINS))
printformat(server, channel, MSGLEVEL_JOINS, IRCTXT_JOIN, nick, addr, channel);
g_free(params);
}
static void event_part(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
gchar *params, *channel, *reason;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &reason);
if (!ignore_check(server, nick, addr, channel, NULL, MSGLEVEL_PARTS))
printformat(server, channel, MSGLEVEL_PARTS, IRCTXT_PART, nick, addr, channel, reason);
g_free(params);
}
static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
{
GString *chans;
GSList *tmp;
int once;
g_return_if_fail(data != NULL);
if (ignore_check(server, nick, addr, NULL, NULL, MSGLEVEL_QUITS))
return;
if (*data == ':') data++; /* quit message */
once = settings_get_bool("show_quit_once");
chans = !once ? NULL : g_string_new(NULL);
for (tmp = channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *rec = tmp->data;
if (rec->server == server && nicklist_find(rec, nick) &&
!ignore_check(server, nick, addr, rec->name, data, MSGLEVEL_QUITS)) {
if (once)
g_string_sprintfa(chans, "%s,", rec->name);
else
printformat(server, rec->name, MSGLEVEL_QUITS, IRCTXT_QUIT, nick, addr, data);
}
}
if (once) {
g_string_truncate(chans, chans->len-1);
printformat(server, NULL, MSGLEVEL_QUITS,
chans->len == 0 ? IRCTXT_QUIT : IRCTXT_QUIT_ONCE,
nick, addr, data, chans->str);
g_string_free(chans, TRUE);
}
}
static void event_kick(gchar *data, IRC_SERVER_REC *server, gchar *kicker, gchar *addr)
{
gchar *params, *channel, *nick, *reason;
g_return_if_fail(data != NULL);
params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &channel, &nick, &reason);
if (!ignore_check(server, kicker, addr, channel, reason, MSGLEVEL_KICKS))
{
printformat(server, channel, MSGLEVEL_KICKS,
IRCTXT_KICK, nick, channel, kicker, reason);
}
g_free(params);
}
static void print_nick_change(IRC_SERVER_REC *server, const char *target, const char *newnick, const char *oldnick, const char *addr, int ownnick)
{
if (ignore_check(server, oldnick, addr, target, newnick, MSGLEVEL_NICKS))
return;
if (ownnick)
printformat(server, target, MSGLEVEL_NICKS, IRCTXT_YOUR_NICK_CHANGED, newnick);
else
printformat(server, target, MSGLEVEL_NICKS, IRCTXT_NICK_CHANGED, oldnick, newnick);
}
static void event_nick(gchar *data, IRC_SERVER_REC *server, gchar *sender, gchar *addr)
{
GSList *tmp;
char *params, *newnick;
int ownnick, msgprint;
g_return_if_fail(data != NULL);
if (ignore_check(server, sender, addr, NULL, NULL, MSGLEVEL_NICKS))
return;
params = event_get_params(data, 1, &newnick);
msgprint = FALSE;
ownnick = g_strcasecmp(sender, server->nick) == 0;
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *channel = tmp->data;
if (nicklist_find(channel, sender)) {
print_nick_change(server, channel->name, newnick, sender, addr, ownnick);
msgprint = TRUE;
}
}
for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
QUERY_REC *query = tmp->data;
if (g_strcasecmp(query->nick, sender) == 0) {
print_nick_change(server, query->nick, newnick, sender, addr, ownnick);
msgprint = TRUE;
}
}
if (!msgprint && ownnick)
printformat(server, NULL, MSGLEVEL_NICKS, IRCTXT_YOUR_NICK_CHANGED, newnick);
g_free(params);
}
static void event_mode(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
{
char *params, *channel, *mode;
g_return_if_fail(data != NULL);
if (nick == NULL) nick = server->real_address;
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &mode);
if (ignore_check(server, nick, addr, channel, mode, MSGLEVEL_MODES)) {
g_free(params);
return;
}
if (!ischannel(*channel)) {
/* user mode change */
printformat(server, NULL, MSGLEVEL_MODES, IRCTXT_USERMODE_CHANGE, mode, channel);
} else if (addr == NULL) {
/* channel mode changed by server */
printformat(server, channel, MSGLEVEL_MODES,
IRCTXT_SERVER_CHANMODE_CHANGE, channel, mode, nick);
} else {
/* channel mode changed by normal user */
printformat(server, channel, MSGLEVEL_MODES,
IRCTXT_CHANMODE_CHANGE, channel, mode, nick);
}
g_free(params);
}
static void event_pong(const char *data, IRC_SERVER_REC *server, const char *nick)
{
char *params, *host, *reply;
g_return_if_fail(data != NULL);
if (nick == NULL) nick = server->real_address;
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &host, &reply);
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_PONG, host, reply);
g_free(params);
}
static void event_invite(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
gchar *params, *channel;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2, NULL, &channel);
if (*channel != '\0' && !ignore_check(server, nick, addr, channel, NULL, MSGLEVEL_INVITES))
printformat(server, NULL, MSGLEVEL_INVITES, IRCTXT_INVITE, nick, channel);
g_free(params);
}
static void event_topic(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
gchar *params, *channel, *topic;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &topic);
if (!ignore_check(server, nick, addr, channel, topic, MSGLEVEL_TOPICS))
printformat(server, channel, MSGLEVEL_TOPICS,
*topic != '\0' ? IRCTXT_NEW_TOPIC : IRCTXT_TOPIC_UNSET,
nick, channel, topic);
g_free(params);
}
static void event_error(gchar *data, IRC_SERVER_REC *server)
{
g_return_if_fail(data != NULL);
if (*data == ':') data++;
printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_ERROR, data);
}
static void event_wallops(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
g_return_if_fail(data != NULL);
if (*data == ':') data++;
if (!ignore_check(server, nick, addr, NULL, data, MSGLEVEL_WALLOPS))
{
if (g_strncasecmp(data, "\001ACTION", 7) != 0)
printformat(server, NULL, MSGLEVEL_WALLOPS, IRCTXT_WALLOPS, nick, data);
else
{
/* Action in WALLOP */
gint len;
data = g_strdup(data);
len = strlen(data);
if (data[len-1] == 1) data[len-1] = '\0';
printformat(server, NULL, MSGLEVEL_WALLOPS, IRCTXT_ACTION_WALLOPS, nick, data);
g_free(data);
}
msg_beep_check(server, MSGLEVEL_WALLOPS);
}
}
static void channel_sync(CHANNEL_REC *channel)
{
g_return_if_fail(channel != NULL);
printformat(channel->server, channel->name, MSGLEVEL_CLIENTNOTICE|MSGLEVEL_NO_ACT, IRCTXT_CHANNEL_SYNCED,
channel->name, (glong) (time(NULL)-channel->createtime));
}
static void event_connected(IRC_SERVER_REC *server)
{
gchar *str;
g_return_if_fail(server != NULL);
if (*settings_get_str("default_nick") == '\0' ||
g_strcasecmp(server->nick, settings_get_str("default_nick")) == 0)
return;
/* someone has our nick, find out who. */
str = g_strdup_printf("WHOIS %s", settings_get_str("default_nick"));
irc_send_cmd(server, str);
g_free(str);
server_redirect_event((SERVER_REC *) server, settings_get_str("default_nick"), 1,
"event 318", "event empty", 1,
"event 401", "event empty", 1,
"event 311", "nickfind event whois", 1,
"event 301", "event empty", 1,
"event 312", "event empty", 1,
"event 313", "event empty", 1,
"event 317", "event empty", 1,
"event 319", "event empty", 1, NULL);
}
static void event_nickfind_whois(gchar *data, IRC_SERVER_REC *server)
{
gchar *params, *nick, *user, *host, *realname;
g_return_if_fail(data != NULL);
params = event_get_params(data, 6, NULL, &nick, &user, &host, NULL, &realname);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_YOUR_NICK_OWNED, nick, user, host, realname);
g_free(params);
}
static void event_ban_type_changed(gchar *bantype)
{
GString *str;
g_return_if_fail(bantype != NULL);
if (strcmp(bantype, "UD") == 0)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_BANTYPE, "Normal");
else if (strcmp(bantype, "HD") == 0 || strcmp(bantype, "H") == 0)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_BANTYPE, "Host");
else if (strcmp(bantype, "D") == 0)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_BANTYPE, "Domain");
else
{
str = g_string_new("Custom:");
if (*bantype == 'N')
{
g_string_append(str, " Nick");
bantype++;
}
if (*bantype == 'U')
{
g_string_append(str, " User");
bantype++;
}
if (*bantype == 'H')
{
g_string_append(str, " Host");
bantype++;
}
if (*bantype == 'D')
g_string_append(str, " Domain");
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_BANTYPE, str->str);
g_string_free(str, TRUE);
}
}
/*FIXME: move to core
static void event_perl_error(gchar *text)
{
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, IRCTXT_PERL_ERROR, text);
}*/
static void sig_server_lag_disconnected(IRC_SERVER_REC *server)
{
g_return_if_fail(server != NULL);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_LAG_DISCONNECTED, server->connrec->address, time(NULL)-server->lag_sent);
}
static void sig_server_reconnect_removed(RECONNECT_REC *reconnect)
{
g_return_if_fail(reconnect != NULL);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_RECONNECT_REMOVED, reconnect->conn->address, reconnect->conn->port,
reconnect->conn->ircnet == NULL ? "" : reconnect->conn->ircnet);
}
static void sig_server_reconnect_not_found(gchar *tag)
{
g_return_if_fail(tag != NULL);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
IRCTXT_RECONNECT_NOT_FOUND, tag);
}
static void event_received(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr)
{
g_return_if_fail(data != NULL);
if (!isdigit((gint) *data))
printtext(server, NULL, MSGLEVEL_CRAP, "%s", data);
else
{
/* numeric event. */
gchar *params, *cmd, *args, *ptr;
params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &cmd, NULL, &args);
ptr = strstr(args, " :");
if (ptr != NULL) *(ptr+1) = ' ';
printtext(server, NULL, MSGLEVEL_CRAP, "%s", args);
g_free(params);
}
}
static void sig_empty(void)
{
}
static void read_settings(void)
{
beep_msg_level = level2bits(settings_get_str("beep_on_msg"));
beep_when_away = settings_get_bool("beep_when_away");
}
void fe_events_init(void)
{
beep_msg_level = 0;
read_settings();
signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
signal_add("ctcp msg", (SIGNAL_FUNC) ctcp_action_msg);
signal_add("ctcp msg action", (SIGNAL_FUNC) sig_empty);
signal_add("event notice", (SIGNAL_FUNC) event_notice);
signal_add("event join", (SIGNAL_FUNC) event_join);
signal_add("event part", (SIGNAL_FUNC) event_part);
signal_add("event quit", (SIGNAL_FUNC) event_quit);
signal_add("event kick", (SIGNAL_FUNC) event_kick);
signal_add("event nick", (SIGNAL_FUNC) event_nick);
signal_add("event mode", (SIGNAL_FUNC) event_mode);
signal_add("event pong", (SIGNAL_FUNC) event_pong);
signal_add("event invite", (SIGNAL_FUNC) event_invite);
signal_add("event topic", (SIGNAL_FUNC) event_topic);
signal_add("event error", (SIGNAL_FUNC) event_error);
signal_add("event wallops", (SIGNAL_FUNC) event_wallops);
signal_add("default event", (SIGNAL_FUNC) event_received);
signal_add("channel sync", (SIGNAL_FUNC) channel_sync);
signal_add("event connected", (SIGNAL_FUNC) event_connected);
signal_add("nickfind event whois", (SIGNAL_FUNC) event_nickfind_whois);
signal_add("ban type changed", (SIGNAL_FUNC) event_ban_type_changed);
//signal_add("perl error", (SIGNAL_FUNC) event_perl_error);
signal_add("server lag disconnect", (SIGNAL_FUNC) sig_server_lag_disconnected);
signal_add("server reconnect remove", (SIGNAL_FUNC) sig_server_reconnect_removed);
signal_add("server reconnect not found", (SIGNAL_FUNC) sig_server_reconnect_not_found);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
void fe_events_deinit(void)
{
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
signal_remove("ctcp msg", (SIGNAL_FUNC) ctcp_action_msg);
signal_remove("ctcp msg action", (SIGNAL_FUNC) sig_empty);
signal_remove("event notice", (SIGNAL_FUNC) event_notice);
signal_remove("event join", (SIGNAL_FUNC) event_join);
signal_remove("event part", (SIGNAL_FUNC) event_part);
signal_remove("event quit", (SIGNAL_FUNC) event_quit);
signal_remove("event kick", (SIGNAL_FUNC) event_kick);
signal_remove("event nick", (SIGNAL_FUNC) event_nick);
signal_remove("event mode", (SIGNAL_FUNC) event_mode);
signal_remove("event pong", (SIGNAL_FUNC) event_pong);
signal_remove("event invite", (SIGNAL_FUNC) event_invite);
signal_remove("event topic", (SIGNAL_FUNC) event_topic);
signal_remove("event error", (SIGNAL_FUNC) event_error);
signal_remove("event wallops", (SIGNAL_FUNC) event_wallops);
signal_remove("default event", (SIGNAL_FUNC) event_received);
signal_remove("channel sync", (SIGNAL_FUNC) channel_sync);
signal_remove("event connected", (SIGNAL_FUNC) event_connected);
signal_remove("nickfind event whois", (SIGNAL_FUNC) event_nickfind_whois);
signal_remove("ban type changed", (SIGNAL_FUNC) event_ban_type_changed);
//signal_remove("perl error", (SIGNAL_FUNC) event_perl_error);
signal_remove("server lag disconnect", (SIGNAL_FUNC) sig_server_lag_disconnected);
signal_remove("server reconnect remove", (SIGNAL_FUNC) sig_server_reconnect_removed);
signal_remove("server reconnect not found", (SIGNAL_FUNC) sig_server_reconnect_not_found);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

View File

@ -0,0 +1,248 @@
/*
fe-ignore.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "levels.h"
#include "misc.h"
#include "irc.h"
#include "irc-server.h"
#include "ignore.h"
static char *ignore_get_key(IGNORE_REC *rec)
{
char *chans, *ret;
if (rec->channels == NULL)
return rec->mask != NULL ? g_strdup(rec->mask) : NULL;
chans = g_strjoinv(",", rec->channels);
if (rec->mask == NULL) return chans;
ret = g_strdup_printf("%s %s", rec->mask, chans);
g_free(chans);
return ret;
}
static char *ignore_get_levels(int level, int xlevel)
{
GString *str;
char *levelstr, *p, *ret;
str = g_string_new(NULL);
if (level != 0) {
levelstr = bits2level(level);
g_string_append(str, levelstr);
g_free(levelstr);
}
if (xlevel != 0) {
if (str->len > 0) g_string_append_c(str, ' ');
levelstr = bits2level(xlevel);
for (p = levelstr; *p != '\0'; p++) {
if (!isspace(*p) && (p == levelstr || isspace(p[-1])))
g_string_append_c(str, '^');
g_string_append_c(str, *p);
}
g_free(levelstr);
}
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
/* msgs ^notices : level=msgs, xlevel=notices */
static void ignore_split_levels(const char *levels, int *level, int *xlevel)
{
GString *slevel, *sxlevel;
char **levellist, **tmp;
if (*levels == '\0') return;
slevel = g_string_new(NULL);
sxlevel = g_string_new(NULL);
levellist = g_strsplit(levels, " ", -1);
for (tmp = levellist; *tmp != NULL; tmp++) {
if (**tmp == '^')
g_string_sprintfa(sxlevel, "%s ", (*tmp)+1);
else if (**tmp == '-' && (*tmp)[1] == '^')
g_string_sprintfa(sxlevel, "-%s ", (*tmp)+2);
else
g_string_sprintfa(slevel, "%s ", *tmp);
}
g_strfreev(levellist);
*level = combine_level(*level, slevel->str);
*xlevel = combine_level(*xlevel, sxlevel->str);
g_string_free(slevel, TRUE);
g_string_free(sxlevel, TRUE);
}
static void ignore_print(int index, IGNORE_REC *rec)
{
char *key, *levels;
key = ignore_get_key(rec);
levels = ignore_get_levels(rec->level, rec->except_level);
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
IRCTXT_IGNORE_LINE, index,
key != NULL ? key : "",
levels != NULL ? levels : "",
rec->fullword ? " -word" : "",
rec->regexp ? " -regexp" : "");
g_free(key);
g_free(levels);
}
static void cmd_ignore_show(void)
{
GSList *tmp;
int index;
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_IGNORE_HEADER);
index = 1;
for (tmp = ignores; tmp != NULL; tmp = tmp->next, index++) {
IGNORE_REC *rec = tmp->data;
ignore_print(index, rec);
}
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_IGNORE_FOOTER);
}
static void cmd_ignore(const char *data)
{
/* /IGNORE [-regexp | -word] [-pattern <pattern>] [-except]
[-channels <channel>] <mask> <levels>
OR
/IGNORE [-regexp | -word] [-pattern <pattern>] [-except]
<channels> <levels> */
char *params, *args, *patternarg, *chanarg, *mask, *levels, *key;
char **channels;
IGNORE_REC *rec;
int new_ignore;
if (*data == '\0') {
cmd_ignore_show();
return;
}
args = "pattern channels";
params = cmd_get_params(data, 5 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST,
&args, &patternarg, &chanarg, &mask, &levels);
if (levels == 0) cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (ischannel(*mask)) {
chanarg = mask;
mask = "";
}
channels = *chanarg == '\0' ? NULL :
g_strsplit(replace_chars(chanarg, ',', ' '), " ", -1);
rec = ignore_find(NULL, mask, channels);
new_ignore = rec == NULL;
if (rec == NULL) {
rec = g_new0(IGNORE_REC, 1);
rec->mask = *mask == '\0' ? NULL : g_strdup(mask);
rec->channels = channels;
} else {
g_free_and_null(rec->pattern);
g_strfreev(channels);
}
if (stristr(args, "-except") != NULL) {
rec->except_level = combine_level(rec->except_level, levels);
} else {
ignore_split_levels(levels, &rec->level, &rec->except_level);
}
rec->pattern = *patternarg == '\0' ? NULL : g_strdup(patternarg);
rec->fullword = stristr(args, "-word") != NULL;
rec->regexp = stristr(args, "-regexp") != NULL;
if (rec->level == 0 && rec->except_level == 0)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_UNIGNORED, rec->mask);
else {
key = ignore_get_key(rec);
levels = ignore_get_levels(rec->level, rec->except_level);
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_IGNORED, key, levels);
g_free(key);
g_free(levels);
}
if (new_ignore)
ignore_add_rec(rec);
else
ignore_update_rec(rec);
g_free(params);
}
static void cmd_unignore(const char *data)
{
IGNORE_REC *rec;
GSList *tmp;
char *key;
if (is_numeric(data, ' ')) {
/* with index number */
tmp = g_slist_nth(ignores, atol(data)-1);
rec = tmp == NULL ? NULL : tmp->data;
} else {
/* with mask */
char *chans[2] = { "*", NULL };
if (ischannel(*data)) chans[0] = (char *) data;
rec = ignore_find("*", ischannel(*data) ? NULL : data, chans);
}
if (rec == NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_IGNORE_NOT_FOUND, data);
else {
key = ignore_get_key(rec);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_UNIGNORED, key);
g_free(key);
rec->level = 0;
rec->except_level = 0;
ignore_update_rec(rec);
}
}
void fe_ignore_init(void)
{
command_bind("ignore", NULL, (SIGNAL_FUNC) cmd_ignore);
command_bind("unignore", NULL, (SIGNAL_FUNC) cmd_unignore);
}
void fe_ignore_deinit(void)
{
command_unbind("ignore", (SIGNAL_FUNC) cmd_ignore);
command_unbind("unignore", (SIGNAL_FUNC) cmd_unignore);
}

View File

@ -0,0 +1,541 @@
/*
fe-irc-commands.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "special-vars.h"
#include "settings.h"
#include "levels.h"
#include "irc.h"
#include "server.h"
#include "server-reconnect.h"
#include "mode-lists.h"
#include "nicklist.h"
#include "channels.h"
#include "query.h"
#include "windows.h"
#include "window-items.h"
static void cmd_server(const char *data)
{
if (*data == '+' && data[1] != '\0')
window_create(NULL, FALSE);
}
static void print_servers(void)
{
GSList *tmp;
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
IRC_SERVER_REC *rec = tmp->data;
printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LIST,
rec->tag, rec->connrec->address, rec->connrec->port,
rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick);
}
}
static void print_lookup_servers(void)
{
GSList *tmp;
for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) {
IRC_SERVER_REC *rec = tmp->data;
printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LOOKUP_LIST,
rec->tag, rec->connrec->address, rec->connrec->port,
rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick);
}
}
static void print_reconnects(void)
{
GSList *tmp;
char *tag, *next_connect;
int left;
for (tmp = reconnects; tmp != NULL; tmp = tmp->next) {
RECONNECT_REC *rec = tmp->data;
IRC_SERVER_CONNECT_REC *conn = rec->conn;
tag = g_strdup_printf("RECON-%d", rec->tag);
left = rec->next_connect-time(NULL);
next_connect = g_strdup_printf("%02d:%02d", left/60, left%60);
printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_RECONNECT_LIST,
tag, conn->address, conn->port,
conn->ircnet == NULL ? "" : conn->ircnet,
conn->nick, next_connect);
g_free(next_connect);
g_free(tag);
}
}
static void cmd_servers(void)
{
print_servers();
print_lookup_servers();
print_reconnects();
}
static void cmd_unquery(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
QUERY_REC *query;
g_return_if_fail(data != NULL);
if (*data == '\0') {
/* remove current query */
query = irc_item_query(item);
if (query == NULL) return;
} else {
query = query_find(server, data);
if (query == NULL) {
printformat(server, NULL, MSGLEVEL_CLIENTERROR, IRCTXT_NO_QUERY, data);
return;
}
}
query_destroy(query);
}
static void cmd_query(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
WINDOW_REC *window;
QUERY_REC *query;
g_return_if_fail(data != NULL);
if (*data == '\0') {
/* remove current query */
cmd_unquery("", server, item);
return;
}
if (*data != '=' && (server == NULL || !server->connected))
cmd_return_error(CMDERR_NOT_CONNECTED);
query = query_find(server, data);
if (query != NULL) {
/* query already existed - change to query window */
window = window_item_window((WI_ITEM_REC *) query);
g_return_if_fail(window != NULL);
window_set_active(window);
window_item_set_active(window, (WI_ITEM_REC *) query);
return;
}
query_create(server, data, FALSE);
}
static void cmd_msg(gchar *data, IRC_SERVER_REC *server, WI_ITEM_REC *item)
{
WINDOW_REC *window;
CHANNEL_REC *channel;
NICK_REC *nickrec;
char *params, *target, *msg, *nickmode, *freestr, *newtarget;
int free_ret;
g_return_if_fail(data != NULL);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (*target == '=')
{
/* dcc msg - handled in fe-dcc.c */
g_free(params);
return;
}
free_ret = FALSE;
if (strcmp(target, ",") == 0 || strcmp(target, ".") == 0)
newtarget = parse_special(&target, server, item, NULL, &free_ret, NULL);
else if (strcmp(target, "*") == 0 &&
(irc_item_channel(item) || irc_item_query(item)))
newtarget = item->name;
else newtarget = target;
if (newtarget == NULL) {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, *target == ',' ?
IRCTXT_NO_MSGS_GOT : IRCTXT_NO_MSGS_SENT);
g_free(params);
signal_stop();
return;
}
target = newtarget;
if (server == NULL || !server->connected) cmd_param_error(CMDERR_NOT_CONNECTED);
channel = channel_find(server, target);
freestr = !free_ret ? NULL : target;
if (*target == '@' && ischannel(target[1]))
target++; /* Hybrid 6 feature, send msg to all ops in channel */
if (ischannel(*target))
{
/* msg to channel */
nickrec = channel == NULL ? NULL : nicklist_find(channel, server->nick);
nickmode = !settings_get_bool("toggle_show_nickmode") || nickrec == NULL ? "" :
nickrec->op ? "@" : nickrec->voice ? "+" : " ";
window = channel == NULL ? NULL : window_item_window((WI_ITEM_REC *) channel);
if (window != NULL && window->active == (WI_ITEM_REC *) channel)
{
printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT,
IRCTXT_OWN_MSG, server->nick, msg, nickmode);
}
else
{
printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT,
IRCTXT_OWN_MSG_CHANNEL, server->nick, target, msg, nickmode);
}
}
else
{
/* private message */
printformat(server, target, MSGLEVEL_MSGS | MSGLEVEL_NOHILIGHT,
channel == NULL ? IRCTXT_OWN_MSG_PRIVATE : IRCTXT_OWN_MSG_PRIVATE_QUERY, target, msg, server->nick);
}
g_free_not_null(freestr);
g_free(params);
}
static void cmd_notice(gchar *data, IRC_SERVER_REC *server)
{
char *params, *target, *msg;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (*target == '@' && ischannel(target[1]))
target++; /* Hybrid 6 feature, send notice to all ops in channel */
printformat(server, target, MSGLEVEL_NOTICES | MSGLEVEL_NOHILIGHT,
IRCTXT_OWN_NOTICE, target, msg);
g_free(params);
}
static void cmd_me(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
g_return_if_fail(data != NULL);
if (!irc_item_check(item))
return;
if (irc_item_dcc_chat(item)) {
/* DCC action - handled by fe-dcc.c */
return;
}
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
printformat(server, item->name, MSGLEVEL_ACTIONS,
IRCTXT_OWN_ME, server->nick, data);
irc_send_cmdv(server, "PRIVMSG %s :\001ACTION %s\001", item->name, data);
}
static void cmd_action(const char *data, IRC_SERVER_REC *server)
{
char *params, *target, *text;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
if (*data == '=') {
/* DCC action - handled by fe-dcc.c */
return;
}
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &text);
if (*target == '\0' || *text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
printformat(server, target, MSGLEVEL_ACTIONS, IRCTXT_OWN_ME, server->nick, text);
irc_send_cmdv(server, "PRIVMSG %s :\001ACTION %s\001", target, text);
g_free(params);
}
static void cmd_ctcp(const char *data, IRC_SERVER_REC *server)
{
char *params, *target, *ctcpcmd, *ctcpdata;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata);
if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (*target == '=') {
/* send CTCP via DCC CHAT */
g_free(params);
return;
}
if (*target == '@' && ischannel(target[1]))
target++; /* Hybrid 6 feature, send ctcp to all ops in channel */
g_strup(ctcpcmd);
printformat(server, target, MSGLEVEL_CTCPS, IRCTXT_OWN_CTCP, target, ctcpcmd, ctcpdata);
g_free(params);
}
static void cmd_nctcp(const char *data, IRC_SERVER_REC *server)
{
gchar *params, *target, *ctcpcmd, *ctcpdata;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &target, &ctcpcmd, &ctcpdata);
if (*target == '\0' || *ctcpcmd == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
if (*target == '@' && ischannel(target[1]))
target++; /* Hybrid 6 feature, send notice to all ops in channel */
g_strup(ctcpcmd);
printformat(server, target, MSGLEVEL_NOTICES, IRCTXT_OWN_NOTICE, target, ctcpcmd, ctcpdata);
g_free(params);
}
static void cmd_banstat(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
CHANNEL_REC *cur_channel, *channel;
GSList *tmp;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
cur_channel = irc_item_channel(item);
if (cur_channel == NULL) cmd_return_error(CMDERR_NOT_JOINED);
if (strcmp(data, "*") == 0 || *data == '\0')
channel = cur_channel;
else {
channel = channel_find(server, data);
if (channel == NULL) {
/* not joined to such channel, but ask ban lists from server */
GString *str;
str = g_string_new(NULL);
g_string_sprintf(str, "%s b", data);
signal_emit("command mode", 3, str->str, server, cur_channel);
g_string_sprintf(str, "%s e", data);
signal_emit("command mode", 3, str->str, server, cur_channel);
g_string_free(str, TRUE);
return;
}
}
if (channel == NULL) cmd_return_error(CMDERR_CHAN_NOT_FOUND);
/* show bans.. */
for (tmp = channel->banlist; tmp != NULL; tmp = tmp->next) {
BAN_REC *rec;
rec = (BAN_REC *) tmp->data;
if (*rec->setby == '\0')
printformat(server, channel->name, MSGLEVEL_CRAP, IRCTXT_BANLIST, channel->name, rec->ban);
else
printformat(server, channel->name, MSGLEVEL_CRAP, IRCTXT_BANLIST,
channel->name, rec->ban, rec->setby, (gint) (time(NULL)-rec->time));
}
/* ..and show ban exceptions.. */
for (tmp = channel->ebanlist; tmp != NULL; tmp = tmp->next) {
BAN_REC *rec;
rec = (BAN_REC *) tmp->data;
if (*rec->setby == '\0')
printformat(server, channel->name, MSGLEVEL_CRAP, IRCTXT_EBANLIST, channel->name, rec->ban);
else
printformat(server, channel->name, MSGLEVEL_CRAP, IRCTXT_EBANLIST,
channel->name, rec->ban, rec->setby, (gint) (time(NULL)-rec->time));
}
}
static void cmd_invitelist(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
CHANNEL_REC *channel, *cur_channel;
GSList *tmp;
g_return_if_fail(data != NULL);
if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED);
cur_channel = irc_item_channel(item);
if (cur_channel == NULL) cmd_return_error(CMDERR_NOT_JOINED);
if (strcmp(data, "*") == 0 || *data == '\0')
channel = cur_channel;
else
channel = channel_find(server, data);
if (channel == NULL) cmd_return_error(CMDERR_CHAN_NOT_FOUND);
for (tmp = channel->invitelist; tmp != NULL; tmp = tmp->next)
printformat(server, channel->name, MSGLEVEL_CRAP, IRCTXT_INVITELIST, channel->name, tmp->data);
}
static void cmd_join(const char *data, IRC_SERVER_REC *server)
{
if ((*data == '\0' || g_strncasecmp(data, "-invite", 7) == 0) &&
server->last_invite == NULL) {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_INVITED);
signal_stop();
}
}
static void cmd_channel(const char *data, IRC_SERVER_REC *server)
{
CHANNEL_REC *channel;
GString *nicks;
GSList *nicklist, *tmp, *ntmp;
char *mode;
if (*data != '\0') {
cmd_join(data, server);
return;
}
if (channels == NULL) {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_IN_CHANNELS);
return;
}
/* print active channel */
channel = irc_item_channel(active_win->active);
if (channel != NULL)
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CURRENT_CHANNEL, channel->name);
/* print list of all channels, their modes, server tags and nicks */
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANLIST_HEADER);
for (tmp = channels; tmp != NULL; tmp = tmp->next) {
channel = tmp->data;
nicklist = nicklist_getnicks(channel);
mode = channel_get_mode(channel);
nicks = g_string_new(NULL);
for (ntmp = nicklist; ntmp != NULL; ntmp = ntmp->next) {
NICK_REC *rec = ntmp->data;
g_string_sprintfa(nicks, "%s ", rec->nick);
}
g_string_truncate(nicks, nicks->len-1);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANLIST_LINE,
channel->name, mode, channel->server->tag, nicks->str);
g_free(mode);
g_slist_free(nicklist);
g_string_free(nicks, TRUE);
}
}
static void cmd_nick(const char *data, IRC_SERVER_REC *server)
{
g_return_if_fail(data != NULL);
if (*data != '\0') return;
if (server == NULL || !server->connected)
cmd_return_error(CMDERR_NOT_CONNECTED);
/* display current nick */
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_YOUR_NICK, server->nick);
signal_stop();
}
static void cmd_ver(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item)
{
char *str;
g_return_if_fail(data != NULL);
if (!irc_server_check(server))
cmd_return_error(CMDERR_NOT_CONNECTED);
if (*data == '\0' && !irc_item_check(item))
cmd_return_error(CMDERR_NOT_JOINED);
str = g_strdup_printf("%s VERSION", *data == '\0' ? item->name : data);
signal_emit("command ctcp", 3, str, server, item);
g_free(str);
}
static void cmd_ts(const char *data)
{
GSList *tmp;
g_return_if_fail(data != NULL);
for (tmp = channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *rec = tmp->data;
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_TOPIC,
rec->name, rec->topic == NULL ? "" : rec->topic);
}
}
void fe_irc_commands_init(void)
{
command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
command_bind("servers", NULL, (SIGNAL_FUNC) cmd_servers);
command_bind("query", NULL, (SIGNAL_FUNC) cmd_query);
command_bind("unquery", NULL, (SIGNAL_FUNC) cmd_unquery);
command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
command_bind("notice", NULL, (SIGNAL_FUNC) cmd_notice);
command_bind("me", NULL, (SIGNAL_FUNC) cmd_me);
command_bind("action", NULL, (SIGNAL_FUNC) cmd_action);
command_bind("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp);
command_bind("nctcp", NULL, (SIGNAL_FUNC) cmd_nctcp);
command_bind("banstat", NULL, (SIGNAL_FUNC) cmd_banstat);
command_bind("invitelist", NULL, (SIGNAL_FUNC) cmd_invitelist);
command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel);
command_bind("nick", NULL, (SIGNAL_FUNC) cmd_nick);
command_bind("ver", NULL, (SIGNAL_FUNC) cmd_ver);
command_bind("ts", NULL, (SIGNAL_FUNC) cmd_ts);
}
void fe_irc_commands_deinit(void)
{
command_unbind("server", (SIGNAL_FUNC) cmd_server);
command_unbind("servers", (SIGNAL_FUNC) cmd_servers);
command_unbind("query", (SIGNAL_FUNC) cmd_query);
command_unbind("unquery", (SIGNAL_FUNC) cmd_unquery);
command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
command_unbind("notice", (SIGNAL_FUNC) cmd_notice);
command_unbind("me", (SIGNAL_FUNC) cmd_me);
command_unbind("action", (SIGNAL_FUNC) cmd_action);
command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp);
command_unbind("nctcp", (SIGNAL_FUNC) cmd_nctcp);
command_unbind("banstat", (SIGNAL_FUNC) cmd_banstat);
command_unbind("invitelist", (SIGNAL_FUNC) cmd_invitelist);
command_unbind("join", (SIGNAL_FUNC) cmd_join);
command_unbind("channel", (SIGNAL_FUNC) cmd_channel);
command_unbind("nick", (SIGNAL_FUNC) cmd_nick);
command_unbind("ver", (SIGNAL_FUNC) cmd_ver);
command_unbind("ts", (SIGNAL_FUNC) cmd_ts);
}

View File

@ -0,0 +1,133 @@
/*
fe-query.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "modules.h"
#include "signals.h"
#include "commands.h"
#include "irc.h"
#include "levels.h"
#include "query.h"
#include "windows.h"
#include "window-items.h"
static void signal_query_created(QUERY_REC *query, gpointer automatic)
{
window_item_create((WI_ITEM_REC *) query, GPOINTER_TO_INT(automatic));
}
static void signal_query_created_curwin(QUERY_REC *query)
{
g_return_if_fail(query != NULL);
window_add_item(active_win, (WI_ITEM_REC *) query, FALSE);
signal_stop();
}
static void signal_query_destroyed(QUERY_REC *query)
{
WINDOW_REC *window;
g_return_if_fail(query != NULL);
window = window_item_window((WI_ITEM_REC *) query);
if (window != NULL) window_remove_item(window, (WI_ITEM_REC *) query);
}
static void signal_window_item_removed(WINDOW_REC *window, WI_ITEM_REC *item)
{
QUERY_REC *query;
g_return_if_fail(window != NULL);
query = irc_item_query(item);
if (query != NULL) query_destroy(query);
}
static void sig_server_connected(IRC_SERVER_REC *server)
{
GSList *tmp;
if (!irc_server_check(server))
return;
/* check if there's any queries without server */
for (tmp = queries; tmp != NULL; tmp = tmp->next) {
QUERY_REC *rec = tmp->data;
if (rec->server == NULL &&
g_strcasecmp(rec->server_tag, server->tag) == 0) {
window_item_change_server((WI_ITEM_REC *) rec, server);
server->queries = g_slist_append(server->queries, rec);
}
}
}
static void cmd_window_server(const char *data)
{
SERVER_REC *server;
g_return_if_fail(data != NULL);
server = server_find_tag(data);
if (irc_server_check(server) && irc_item_query(active_win->active)) {
/* /WINDOW SERVER used in a query window */
query_change_server((QUERY_REC *) active_win->active,
(IRC_SERVER_REC *) server);
window_change_server(active_win, server);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_QUERY_SERVER_CHANGED, server->tag, server->connrec->address,
server->connrec->ircnet == NULL ? "" : server->connrec->ircnet);
signal_stop();
}
}
static void cmd_wquery(const char *data, void *server, WI_ITEM_REC *item)
{
signal_add("query created", (SIGNAL_FUNC) signal_query_created_curwin);
signal_emit("command query", 3, data, server, item);
signal_remove("query created", (SIGNAL_FUNC) signal_query_created_curwin);
}
void fe_query_init(void)
{
signal_add("query created", (SIGNAL_FUNC) signal_query_created);
signal_add("query destroyed", (SIGNAL_FUNC) signal_query_destroyed);
signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_removed);
signal_add("server connected", (SIGNAL_FUNC) sig_server_connected);
command_bind("wquery", NULL, (SIGNAL_FUNC) cmd_wquery);
command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server);
}
void fe_query_deinit(void)
{
signal_remove("query created", (SIGNAL_FUNC) signal_query_created);
signal_remove("query destroyed", (SIGNAL_FUNC) signal_query_destroyed);
signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_removed);
signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected);
command_unbind("wquery", (SIGNAL_FUNC) cmd_wquery);
command_unbind("window server", (SIGNAL_FUNC) cmd_window_server);
}

View File

@ -0,0 +1,17 @@
noinst_LTLIBRARIES = libfe_common_irc_flood.la
INCLUDES = \
$(GLIB_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core/ \
-I$(top_srcdir)/src/irc/core/ \
-I$(top_srcdir)/src/fe-common/core/ \
-DHELPDIR=\""$(datadir)/irssi/help"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\"
libfe_common_irc_flood_la_SOURCES = \
fe-flood.c \
module-formats.c
noinst_headers = \
module-formats.h

View File

@ -0,0 +1,54 @@
/*
fe-flood.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "levels.h"
#include "irc-server.h"
#include "irc/flood/autoignore.h"
static void event_autoignore_new(IRC_SERVER_REC *server, AUTOIGNORE_REC *ignore)
{
g_return_if_fail(ignore != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_AUTOIGNORE,
ignore->nick, (ignore->timeleft+59)/60);
}
static void event_autoignore_remove(IRC_SERVER_REC *server, AUTOIGNORE_REC *ignore)
{
g_return_if_fail(ignore != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_AUTOUNIGNORE, ignore->nick);
}
void fe_flood_init(void)
{
signal_add("autoignore new", (SIGNAL_FUNC) event_autoignore_new);
signal_add("autoignore remove", (SIGNAL_FUNC) event_autoignore_remove);
}
void fe_flood_deinit(void)
{
signal_remove("autoignore new", (SIGNAL_FUNC) event_autoignore_new);
signal_remove("autoignore remove", (SIGNAL_FUNC) event_autoignore_remove);
}

View File

@ -0,0 +1,33 @@
/*
module-formats.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "printtext.h"
FORMAT_REC fecommon_irc_flood_formats[] =
{
{ MODULE_NAME, N_("Flood"), 0 },
/* ---- */
{ NULL, N_("Autoignore"), 0 },
{ "autoignore", N_("Flood detected from %_$0%_, autoignoring for %_$1%_ minutes"), 2, { 0, 1 } },
{ "autounignore", N_("Unignoring %_$0"), 1, { 0 } }
};

View File

@ -0,0 +1,13 @@
#include "printtext.h"
enum {
IRCTXT_MODULE_NAME,
IRCTXT_FILL_1,
IRCTXT_AUTOIGNORE,
IRCTXT_AUTOUNIGNORE
};
extern FORMAT_REC fecommon_irc_flood_formats[];
#define MODULE_FORMATS fecommon_irc_flood_formats

View File

@ -0,0 +1,54 @@
/*
irc-hilight-text.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "hilight-text.h"
char *irc_hilight_find_nick(const char *channel, const char *nick, const char *address)
{
GSList *tmp;
char *color;
int len, best_match;
g_return_val_if_fail(channel != NULL, NULL);
g_return_val_if_fail(nick != NULL, NULL);
g_return_val_if_fail(address != NULL, NULL);
color = NULL; best_match = 0;
for (tmp = hilights; tmp != NULL; tmp = tmp->next) {
HILIGHT_REC *rec = tmp->data;
if (!rec->nickmask)
continue;
len = strlen(rec->text);
if (best_match < len) {
best_match = len;
color = rec->color;
}
}
if (best_match == 0)
return NULL;
if (color == NULL) color = "\00316";
return g_strconcat(isdigit(*color) ? "\003" : "", color, NULL);
}

View File

@ -0,0 +1,6 @@
#ifndef __IRC_HILIGHT_TEXT_H
#define __IRC_HILIGHT_TEXT_H
char *irc_hilight_find_nick(const char *channel, const char *nick, const char *address);
#endif

View File

@ -0,0 +1,89 @@
/*
irc-nick-hilight.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "signals.h"
#include "levels.h"
#include "irc.h"
#include "ignore.h"
#include "irc-server.h"
#include "completion.h"
#include "windows.h"
#include "window-items.h"
static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr)
{
WINDOW_REC *window;
WI_ITEM_REC *item;
char *params, *target, *msg;
int level;
g_return_if_fail(data != NULL);
params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
if (*msg == 1) {
/* don't hilight CTCPs */
g_free(params);
return;
}
/* get window and window item */
level = ischannel(*target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS;
item = window_item_find(server, ischannel(*target) ? target : nick);
window = item == NULL ?
window_find_closest(server, target, GPOINTER_TO_INT(level)) :
window_item_window(item);
/* check that msg wasn't send to current window and
that it didn't get ignored */
if (window != active_win && !ignore_check(server, nick, addr, target, msg, level)) {
/* hilight */
level = !ischannel(*target) ||
completion_msgtoyou((SERVER_REC *) server, msg) ?
NEWDATA_MSG_FORYOU : NEWDATA_MSG;
if (item != NULL && item->new_data < level) {
item->new_data = level;
signal_emit("window item hilight", 1, item);
} else {
int oldlevel = window->new_data;
if (window->new_data < level) {
window->new_data = level;
signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel));
}
signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel));
}
}
g_free(params);
}
void irc_nick_hilight_init(void)
{
signal_add_last("event privmsg", (SIGNAL_FUNC) event_privmsg);
}
void irc_nick_hilight_deinit(void)
{
signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
}

View File

@ -0,0 +1,174 @@
/*
module-formats.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "printtext.h"
FORMAT_REC fecommon_irc_formats[] =
{
{ MODULE_NAME, N_("IRC"), 0 },
/* ---- */
{ NULL, N_("Server"), 0 },
{ "lag_disconnected", N_("No PONG reply from server %_$0%_ in $1 seconds, disconnecting"), 2, { 0, 1 } },
{ "disconnected", N_("Disconnected from %_$0%_ %K[%n$1%K]"), 2, { 0, 0 } },
{ "server_list", N_("%_$0%_: $1:$2 ($3)"), 5, { 0, 0, 1, 0, 0 } },
{ "server_lookup_list", N_("%_$0%_: $1:$2 ($3) (connecting...)"), 5, { 0, 0, 1, 0, 0 } },
{ "server_reconnect_list", N_("%_$0%_: $1:$2 ($3) ($5 left before reconnecting)"), 6, { 0, 0, 1, 0, 0, 0 } },
{ "server_reconnect_removed", N_("Removed reconnection to server %_$0%_ port %_$1%_"), 3, { 0, 1, 0 } },
{ "server_reconnect_not_found", N_("Reconnection tag %_$0%_ not found"), 1, { 0 } },
{ "query_server_changed", N_("Query with %_$2%_ changed to server %_$1%_"), 3, { 0, 0, 0 } },
/* ---- */
{ NULL, N_("Channels"), 0 },
{ "join", N_("%c%_$0%_ %K[%c$1%K]%n has joined %_$2"), 3, { 0, 0, 0 } },
{ "part", N_("%c$0 %K[%n$1%K]%n has left %_$2%_ %K[%n$3%K]"), 4, { 0, 0, 0, 0 } },
{ "joinerror_toomany", N_("Cannot join to channel %_$0%_ %K(%nYou have joined to too many channels%K)"), 1, { 0 } },
{ "joinerror_full", N_("Cannot join to channel %_$0%_ %K(%nChannel is full%K)"), 1, { 0 } },
{ "joinerror_invite", N_("Cannot join to channel %_$0%_ %K(%nYou must be invited%K)"), 1, { 0 } },
{ "joinerror_banned", N_("Cannot join to channel %_$0%_ %K(%nYou are banned%K)"), 1, { 0 } },
{ "joinerror_bad_key", N_("Cannot join to channel %_$0%_ %K(%nBad channel key%K)"), 1, { 0 } },
{ "joinerror_bad_mask", N_("Cannot join to channel %_$0%_ %K(%nBad channel mask%K)"), 1, { 0 } },
{ "joinerror_unavail", N_("Cannot join to channel %_$0%_ %K(%nChannel is temporarily unavailable%K)"), 1, { 0 } },
{ "kick", N_("%c$0%n was kicked from %_$1%_ by %_$2%_ %K[%n$3%K]"), 4, { 0, 0, 0, 0 } },
{ "quit", N_("%c$0 %K[%n$1%K]%n has quit IRC %K[%n$2%K]"), 3, { 0, 0, 0 } },
{ "quit_once", N_("%_$3%_ %c$0 %K[%n$1%K]%n has quit IRC %K[%n$2%K]"), 4, { 0, 0, 0, 0 } },
{ "invite", N_("%_$0%_ invites you to %_$1"), 2, { 0, 0 } },
{ "not_invited", N_("You have not been invited to a channel!"), 0 },
{ "names", N_("%K[%g%_Users%_%K(%g$0%K)]%n $1"), 2, { 0, 0 } },
{ "endofnames", N_("%g%_$0%_%K:%n Total of %_$1%_ nicks %K[%n%_$2%_ ops, %_$3%_ voices, %_$4%_ normal%K]"), 5, { 0, 1, 1, 1, 1 } },
{ "channel_created", N_("Channel %_$0%_ created $1"), 2, { 0, 0 } },
{ "topic", N_("Topic for %c$0%K:%n $1"), 2, { 0, 0 } },
{ "no_topic", N_("No topic set for %c$0"), 1, { 0 } },
{ "new_topic", N_("%_$0%_ changed the topic of %c$1%n to%K:%n $2"), 3, { 0, 0, 0 } },
{ "topic_unset", N_("Topic unset by %_$0%_ on %c$1"), 2, { 0, 0 } },
{ "topic_info", N_("Topic set by %_$0%_ %K[%n$1%K]"), 2, { 0, 0 } },
{ "chanmode_change", N_("mode/%c$0 %K[%n$1%K]%n by %_$2"), 3, { 0, 0, 0 } },
{ "server_chanmode_change", N_("%RServerMode/%c$0 %K[%n$1%K]%n by %_$2"), 3, { 0, 0, 0 } },
{ "channel_mode", N_("mode/%c$0 %K[%n$1%K]"), 2, { 0, 0 } },
{ "bantype", N_("Ban type changed to %_$0"), 1, { 0 } },
{ "banlist", N_("%_$0%_: ban %c$1"), 2, { 0, 0 } },
{ "banlist_long", N_("%_$0%_: ban %c$1 %K[%nby %_$2%_, $3 secs ago%K]"), 4, { 0, 0, 0, 1 } },
{ "ebanlist", N_("%_$0%_: ban exception %c$1"), 2, { 0, 0 } },
{ "ebanlist_long", N_("%_$0%_: ban exception %c$1 %K[%nby %_$2%_, $3 secs ago%K]"), 4, { 0, 0, 0, 1 } },
{ "invitelist", N_("%_$0%_: invite %c$1"), 2, { 0, 0 } },
{ "no_such_channel", N_("$0: No such channel"), 1, { 0 } },
{ "not_in_channels", N_("You are not on any channels"), 0 },
{ "current_channel", N_("Current channel $0"), 1, { 0 } },
{ "chanlist_header", N_("You are on the following channels:"), 0 },
{ "chanlist_line", N_("$[-10]0 %|+$1 ($2): $3"), 4, { 0, 0, 0, 0 } },
{ "channel_synced", N_("Join to %_$0%_ was synced in %_$1%_ secs"), 2, { 0, 2 } },
/* ---- */
{ NULL, N_("Nick"), 0 },
{ "usermode_change", N_("Mode change %K[%n%_$0%_%K]%n for user %c$1"), 2, { 0, 0 } },
{ "user_mode", N_("Your user mode is %K[%n%_$0%_%K]"), 1, { 0 } },
{ "away", N_("You have been marked as being away"), 0 },
{ "unaway", N_("You are no longer marked as being away"), 0 },
{ "nick_away", N_("$0 is away: $1"), 2, { 0, 0 } },
{ "no_such_nick", N_("$0: No such nick/channel"), 1, { 0 } },
{ "your_nick", N_("Your nickname is $0"), 1, { 0 } },
{ "your_nick_changed", N_("You're now known as %c$0"), 1, { 0 } },
{ "nick_changed", N_("%_$0%_ is now known as %c$1"), 2, { 0, 0 } },
{ "nick_in_use", N_("Nick %_$0%_ is already in use"), 1, { 0 } },
{ "nick_unavailable", N_("Nick %_$0%_ is temporarily unavailable"), 1, { 0 } },
{ "your_nick_owned", N_("Your nick is owned by %_$3%_ %K[%n$1@$2%K]"), 4, { 0, 0, 0, 0 } },
/* ---- */
{ NULL, N_("Who queries"), 0 },
{ "whois", N_("%_$0%_ %K[%n$1@$2%K]%n%: ircname : $3"), 4, { 0, 0, 0, 0 } },
{ "whois_idle", N_(" idle : $1 hours $2 mins $3 secs"), 4, { 0, 1, 1, 1 } },
{ "whois_idle_signon", N_(" idle : $1 hours $2 mins $3 secs %K[%nsignon: $4%K]"), 5, { 0, 1, 1, 1, 0 } },
{ "whois_server", N_(" server : $1 %K[%n$2%K]"), 3, { 0, 0, 0 } },
{ "whois_oper", N_(" : %_IRC operator%_"), 1, { 0 } },
{ "whois_channels", N_(" channels : $1"), 2, { 0, 0 } },
{ "whois_away", N_(" away : $1"), 2, { 0, 0 } },
{ "end_of_whois", N_("End of WHOIS"), 1, { 0 } },
{ "who", N_("$[-10]0 %|%_$[!9]1%_ $[!3]2 $[!2]3 $4@$5 %K(%W$6%K)"), 7, { 0, 0, 0, 0, 0, 0, 0 } },
{ "end_of_who", N_("End of /WHO list"), 1, { 0 } },
/* ---- */
{ NULL, N_("Your messages"), 0 },
{ "own_msg", N_("%K<%n$2%W$0%K>%n %|$1"), 3, { 0, 0, 0 } },
{ "own_msg_channel", N_("%K<%n$3%W$0%K:%c$1%K>%n %|$2"), 4, { 0, 0, 0, 0 } },
{ "own_msg_private", N_("%K[%rmsg%K(%R$0%K)]%n $1"), 2, { 0, 0 } },
{ "own_msg_private_query", N_("%K<%W$2%K>%n %|$1"), 3, { 0, 0, 0 } },
{ "own_notice", N_("%K[%rnotice%K(%R$0%K)]%n $1"), 2, { 0, 0 } },
{ "own_me", N_("%W * $0%n $1"), 2, { 0, 0 } },
{ "own_ctcp", N_("%K[%rctcp%K(%R$0%K)]%n $1 $2"), 3, { 0, 0, 0 } },
/* ---- */
{ NULL, N_("Received messages"), 0 },
{ "pubmsg_me", N_("%K<%n$2%Y$0%K>%n %|$1"), 3, { 0, 0, 0 } },
{ "pubmsg_me_channel", N_("%K<%n$3%Y$0%K:%c$1%K>%n %|$2"), 4, { 0, 0, 0, 0 } },
{ "pubmsg_hilight", N_("%K<%n$3$0$1%K>%n %|$2"), 4, { 0, 0, 0, 0 } },
{ "pubmsg_hilight_channel", N_("%K<%n$4$0$1%K:%c$2%K>%n %|$3"), 5, { 0, 0, 0, 0, 0 } },
{ "pubmsg", N_("%K<%n$2$0%K>%n %|$1"), 3, { 0, 0, 0 } },
{ "pubmsg_channel", N_("%K<%n$3$0%K:%c$1%K>%n %|$2"), 4, { 0, 0, 0, 0 } },
{ "msg_private", N_("%K[%R$0%K(%r$1%K)]%n $2"), 3, { 0, 0, 0 } },
{ "msg_private_query", N_("%K<%R$0%K>%n %|$2"), 3, { 0, 0, 0 } },
{ "notice_server", N_("%g!$0%n $1"), 2, { 0, 0 } },
{ "notice_public", N_("%K-%M$0%K:%m$1%K-%n $2"), 3, { 0, 0, 0 } },
{ "notice_public_ops", N_("%K-%M$0%K:%m@$1%K-%n $2"), 3, { 0, 0, 0 } },
{ "notice_private", N_("%K-%M$0%K(%m$1%K)-%n $2"), 3, { 0, 0, 0 } },
{ "action_private", N_("%W (*) $0%n $2"), 3, { 0, 0, 0 } },
{ "action_private_query", N_("%W * $0%n $2"), 3, { 0, 0, 0 } },
{ "action_public", N_("%W * $0%n $1"), 2, { 0, 0 } },
{ "action_public_channel", N_("%W * $0%K:%c$1%n $2"), 3, { 0, 0, 0 } },
/* ---- */
{ NULL, N_("CTCPs"), 0 },
{ "ctcp_reply", N_("CTCP %_$0%_ reply from %_$1%_%K:%n $2"), 3, { 0, 0, 0 } },
{ "ctcp_ping_reply", N_("CTCP %_PING%_ reply from %_$0%_: $1.$2 seconds"), 3, { 0, 2, 2 } },
{ "ctcp_requested", N_("%g>>> %_$0%_ %K[%g$1%K] %grequested %_$2%_ from %_$3"), 4, { 0, 0, 0, 0 } },
/* ---- */
{ NULL, N_("Other server events"), 0 },
{ "online", N_("Users online: %_$0"), 1, { 0 } },
{ "pong", N_("PONG received from $0: $1"), 2, { 0, 0 } },
{ "wallops", N_("%WWALLOP%n $0: $1"), 2, { 0, 0 } },
{ "action_wallops", N_("%WWALLOP * $0%n $1"), 2, { 0, 0 } },
{ "error", N_("%_ERROR%_ $0"), 1, { 0 } },
{ "unknown_mode", N_("Unknown mode character $0"), 1, { 0 } },
{ "not_chanop", N_("You're not channel operator in $0"), 1, { 0 } },
/* ---- */
{ NULL, N_("Misc"), 0 },
{ "ignored", N_("Ignoring %_$1%_ from %_$0%_"), 2, { 0, 0 } },
{ "unignored", N_("Unignored %_$0%_"), 1, { 0 } },
{ "ignore_not_found", N_("%_$0%_ is not being ignored"), 1, { 0 } },
{ "ignore_no_ignores", N_("There are no ignores"), 0 },
{ "ignore_header", N_("Ignorance List:"), 0 },
{ "ignore_line", N_("$[-4]0 $1: $2 $3 $4"), 5, { 1, 0, 0, 0, 0 } },
{ "ignore_footer", N_(""), 0 },
{ "talking_in", N_("You are now talking in %_$0%_"), 1, { 0 } },
{ "no_query", N_("No query with %_$0%_"), 1, { 0 } },
{ "no_msgs_got", N_("You have not received a message from anyone yet"), 0 },
{ "no_msgs_sent", N_("You have not sent a message to anyone yet"), 0 }
};

View File

@ -0,0 +1,146 @@
#include "printtext.h"
enum {
IRCTXT_MODULE_NAME,
IRCTXT_FILL_1,
IRCTXT_LAG_DISCONNECTED,
IRCTXT_DISCONNECTED,
IRCTXT_SERVER_LIST,
IRCTXT_SERVER_LOOKUP_LIST,
IRCTXT_SERVER_RECONNECT_LIST,
IRCTXT_RECONNECT_REMOVED,
IRCTXT_RECONNECT_NOT_FOUND,
IRCTXT_QUERY_SERVER_CHANGED,
IRCTXT_FILL_2,
IRCTXT_JOIN,
IRCTXT_PART,
IRCTXT_JOINERROR_TOOMANY,
IRCTXT_JOINERROR_FULL,
IRCTXT_JOINERROR_INVITE,
IRCTXT_JOINERROR_BANNED,
IRCTXT_JOINERROR_BAD_KEY,
IRCTXT_JOINERROR_BAD_MASK,
IRCTXT_JOINERROR_UNAVAIL,
IRCTXT_KICK,
IRCTXT_QUIT,
IRCTXT_QUIT_ONCE,
IRCTXT_INVITE,
IRCTXT_NOT_INVITED,
IRCTXT_NAMES,
IRCTXT_ENDOFNAMES,
IRCTXT_CHANNEL_CREATED,
IRCTXT_TOPIC,
IRCTXT_NO_TOPIC,
IRCTXT_NEW_TOPIC,
IRCTXT_TOPIC_UNSET,
IRCTXT_TOPIC_INFO,
IRCTXT_CHANMODE_CHANGE,
IRCTXT_SERVER_CHANMODE_CHANGE,
IRCTXT_CHANNEL_MODE,
IRCTXT_BANTYPE,
IRCTXT_BANLIST,
IRCTXT_BANLIST_LONG,
IRCTXT_EBANLIST,
IRCTXT_EBANLIST_LONG,
IRCTXT_INVITELIST,
IRCTXT_NO_SUCH_CHANNEL,
IRCTXT_NOT_IN_CHANNELS,
IRCTXT_CURRENT_CHANNEL,
IRCTXT_CHANLIST_HEADER,
IRCTXT_CHANLIST_LINE,
IRCTXT_CHANNEL_SYNCED,
IRCTXT_FILL_4,
IRCTXT_USERMODE_CHANGE,
IRCTXT_USER_MODE,
IRCTXT_AWAY,
IRCTXT_UNAWAY,
IRCTXT_NICK_AWAY,
IRCTXT_NO_SUCH_NICK,
IRCTXT_YOUR_NICK,
IRCTXT_YOUR_NICK_CHANGED,
IRCTXT_NICK_CHANGED,
IRCTXT_NICK_IN_USE,
IRCTXT_NICK_UNAVAILABLE,
IRCTXT_YOUR_NICK_OWNED,
IRCTXT_FILL_5,
IRCTXT_WHOIS,
IRCTXT_WHOIS_IDLE,
IRCTXT_WHOIS_IDLE_SIGNON,
IRCTXT_WHOIS_SERVER,
IRCTXT_WHOIS_OPER,
IRCTXT_WHOIS_CHANNELS,
IRCTXT_WHOIS_AWAY,
IRCTXT_END_OF_WHOIS,
IRCTXT_WHO,
IRCTXT_END_OF_WHO,
IRCTXT_FILL_6,
IRCTXT_OWN_MSG,
IRCTXT_OWN_MSG_CHANNEL,
IRCTXT_OWN_MSG_PRIVATE,
IRCTXT_OWN_MSG_PRIVATE_QUERY,
IRCTXT_OWN_NOTICE,
IRCTXT_OWN_ME,
IRCTXT_OWN_CTCP,
IRCTXT_FILL_7,
IRCTXT_PUBMSG_ME,
IRCTXT_PUBMSG_ME_CHANNEL,
IRCTXT_PUBMSG_HILIGHT,
IRCTXT_PUBMSG_HILIGHT_CHANNEL,
IRCTXT_PUBMSG,
IRCTXT_PUBMSG_CHANNEL,
IRCTXT_MSG_PRIVATE,
IRCTXT_MSG_PRIVATE_QUERY,
IRCTXT_NOTICE_SERVER,
IRCTXT_NOTICE_PUBLIC,
IRCTXT_NOTICE_PUBLIC_OPS,
IRCTXT_NOTICE_PRIVATE,
IRCTXT_ACTION_PRIVATE,
IRCTXT_ACTION_PRIVATE_QUERY,
IRCTXT_ACTION_PUBLIC,
IRCTXT_ACTION_PUBLIC_CHANNEL,
IRCTXT_FILL_8,
IRCTXT_CTCP_REPLY,
IRCTXT_CTCP_PING_REPLY,
IRCTXT_CTCP_REQUESTED,
IRCTXT_FILL_10,
IRCTXT_ONLINE,
IRCTXT_PONG,
IRCTXT_WALLOPS,
IRCTXT_ACTION_WALLOPS,
IRCTXT_ERROR,
IRCTXT_UNKNOWN_MODE,
IRCTXT_NOT_CHANOP,
IRCTXT_FILL_11,
IRCTXT_IGNORED,
IRCTXT_UNIGNORED,
IRCTXT_IGNORE_NOT_FOUND,
IRCTXT_IGNORE_NO_IGNORES,
IRCTXT_IGNORE_HEADER,
IRCTXT_IGNORE_LINE,
IRCTXT_IGNORE_FOOTER,
IRCTXT_TALKING_IN,
IRCTXT_NO_QUERY,
IRCTXT_NO_MSGS_GOT,
IRCTXT_NO_MSGS_SENT
};
extern FORMAT_REC fecommon_irc_formats[];
#define MODULE_FORMATS fecommon_irc_formats

View File

@ -0,0 +1,3 @@
#include "common.h"
#define MODULE_NAME "fe-common/irc"

View File

@ -0,0 +1,17 @@
noinst_LTLIBRARIES = libfe_common_irc_notifylist.la
INCLUDES = \
$(GLIB_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core/ \
-I$(top_srcdir)/src/irc/core/ \
-I$(top_srcdir)/src/fe-common/core/ \
-DHELPDIR=\""$(datadir)/irssi/help"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\"
libfe_common_irc_notifylist_la_SOURCES = \
fe-notifylist.c \
module-formats.c
noinst_headers = \
module-formats.h

View File

@ -0,0 +1,241 @@
/*
fe-notifylist.c : irssi
Copyright (C) 1999-2000 Timo Sirainen
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
*/
#include "module.h"
#include "module-formats.h"
#include "signals.h"
#include "commands.h"
#include "misc.h"
#include "lib-config/iconfig.h"
#include "settings.h"
#include "levels.h"
#include "irc-server.h"
#include "ircnet-setup.h"
#include "irc/notifylist/notifylist.h"
/* add the nick of a hostmask to list if it isn't there already */
static GSList *mask_add_once(GSList *list, const char *mask)
{
char *str, *ptr;
g_return_val_if_fail(mask != NULL, NULL);
ptr = strchr(mask, '!');
str = ptr == NULL ? g_strdup(mask) :
g_strndup(mask, (int) (ptr-mask)+1);
if (gslist_find_icase_string(list, str) == NULL)
return g_slist_append(list, str);
g_free(str);
return list;
}
/* search for online people, print them and update offline list */
static void print_notify_onserver(IRC_SERVER_REC *server, GSList *nicks,
GSList **offline, const char *desc)
{
GSList *tmp;
GString *str;
g_return_if_fail(server != NULL);
g_return_if_fail(offline != NULL);
g_return_if_fail(desc != NULL);
str = g_string_new(NULL);
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
char *nick = tmp->data;
if (!notifylist_ison_server(server, nick))
continue;
g_string_sprintfa(str, "%s, ", nick);
*offline = g_slist_remove(*offline, nick);
}
if (str->len > 0) {
g_string_truncate(str, str->len-2);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_ONLINE, desc, str->str);
}
g_string_free(str, TRUE);
}
/* show the notify list, displaying who is on which net */
static void cmd_notify_show(void)
{
GSList *nicks, *offline, *tmp;
IRC_SERVER_REC *server;
if (notifies == NULL)
return;
/* build a list containing only the nicks */
nicks = NULL;
for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
NOTIFYLIST_REC *rec = tmp->data;
nicks = mask_add_once(nicks, rec->mask);
}
offline = g_slist_copy(nicks);
/* print the notifies on specific ircnets */
for (tmp = ircnets; tmp != NULL; tmp = tmp->next) {
IRCNET_REC *rec = tmp->data;
server = (IRC_SERVER_REC *) server_find_ircnet(rec->name);
if (server == NULL) continue;
print_notify_onserver(server, nicks, &offline, rec->name);
}
/* print the notifies on servers without a specified ircnet */
for (tmp = servers; tmp != NULL; tmp = tmp->next) {
server = tmp->data;
if (server->connrec->ircnet != NULL)
continue;
print_notify_onserver(server, nicks, &offline, server->tag);
}
/* print offline people */
if (offline != NULL) {
GString *str;
str = g_string_new(NULL);
for (tmp = offline; tmp != NULL; tmp = tmp->next)
g_string_sprintfa(str, "%s, ", (char *) tmp->data);
g_string_truncate(str, str->len-2);
printformat(NULL,NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_OFFLINE, str->str);
g_string_free(str, TRUE);
g_slist_free(offline);
}
g_slist_foreach(nicks, (GFunc) g_free, NULL);
g_slist_free(nicks);
}
static void notifylist_print(NOTIFYLIST_REC *rec)
{
char idle[MAX_INT_STRLEN], *ircnets;
if (rec->idle_check_time <= 0)
idle[0] = '\0';
else
g_snprintf(idle, sizeof(idle), "%d", rec->idle_check_time);
ircnets = rec->ircnets == NULL ? NULL :
g_strjoinv(",", rec->ircnets);
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NOTIFY_LIST,
rec->mask, ircnets != NULL ? ircnets : "",
rec->away_check ? "-away" : "", idle);
g_free_not_null(ircnets);
}
static void cmd_notifylist_show(void)
{
g_slist_foreach(notifies, (GFunc) notifylist_print, NULL);
}
static void cmd_notify(const char *data)
{
if (*data == '\0') {
cmd_notify_show();
signal_stop();
}
if (g_strcasecmp(data, "-list") == 0) {
cmd_notifylist_show();
signal_stop();
}
}
static void notifylist_joined(IRC_SERVER_REC *server, const char *nick,
const char *username, const char *host,
const char *realname, const char *awaymsg)
{
g_return_if_fail(nick != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_JOIN,
nick, username, host, realname,
server->connrec->ircnet == NULL ? "IRC" : server->connrec->ircnet);
}
static void notifylist_left(IRC_SERVER_REC *server, const char *nick,
const char *username, const char *host,
const char *realname, const char *awaymsg)
{
g_return_if_fail(nick != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_PART,
nick, username, host, realname,
server->connrec->ircnet == NULL ? "IRC" : server->connrec->ircnet);
}
static void notifylist_away(IRC_SERVER_REC *server, const char *nick,
const char *username, const char *host,
const char *realname, const char *awaymsg)
{
g_return_if_fail(nick != NULL);
if (awaymsg != NULL) {
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_AWAY,
nick, username, host, realname, awaymsg,
server->connrec->ircnet == NULL ? "IRC" : server->connrec->ircnet);
} else {
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_UNAWAY,
nick, username, host, realname,
server->connrec->ircnet == NULL ? "IRC" : server->connrec->ircnet);
}
}
static void notifylist_unidle(IRC_SERVER_REC *server, const char *nick,
const char *username, const char *host,
const char *realname, const char *awaymsg)
{
g_return_if_fail(nick != NULL);
printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_UNIDLE,
nick, username, host, realname, awaymsg != NULL ? awaymsg : "",
server->connrec->ircnet == NULL ? "IRC" : server->connrec->ircnet);
}
void fe_notifylist_init(void)
{
command_bind("notify", NULL, (SIGNAL_FUNC) cmd_notify);
signal_add("notifylist joined", (SIGNAL_FUNC) notifylist_joined);
signal_add("notifylist left", (SIGNAL_FUNC) notifylist_left);
signal_add("notifylist away changed", (SIGNAL_FUNC) notifylist_away);
signal_add("notifylist unidle", (SIGNAL_FUNC) notifylist_unidle);
}
void fe_notifylist_deinit(void)
{
command_unbind("notify", (SIGNAL_FUNC) cmd_notify);
signal_remove("notifylist joined", (SIGNAL_FUNC) notifylist_joined);
signal_remove("notifylist left", (SIGNAL_FUNC) notifylist_left);
signal_remove("notifylist away changed", (SIGNAL_FUNC) notifylist_away);
signal_remove("notifylist unidle", (SIGNAL_FUNC) notifylist_unidle);
}

View File

@ -0,0 +1,39 @@
/*
module-formats.c : irssi
Copyright (C) 2000 Timo Sirainen
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
*/
#include "module.h"
#include "printtext.h"
FORMAT_REC fecommon_irc_notifylist_formats[] =
{
{ MODULE_NAME, N_("Notifylist"), 0 },
/* ---- */
{ NULL, N_("Notifylist"), 0 },
{ "notify_join", N_("%_$0%_ %K[%n$1@$2%K] [%n%_$3%_%K]%n has joined to $4"), 5, { 0, 0, 0, 0, 0 } },
{ "notify_part", N_("%_$0%_ has left $4"), 5, { 0, 0, 0, 0, 0 } },
{ "notify_away", N_("%_$0%_ %K[%n$5%K]%n %K[%n$1@$2%K] [%n%_$3%_%K]%n is now away: $4"), 6, { 0, 0, 0, 0, 0, 0 } },
{ "notify_unaway", N_("%_$0%_ %K[%n$4%K]%n %K[%n$1@$2%K] [%n%_$3%_%K]%n is now unaway"), 5, { 0, 0, 0, 0, 0 } },
{ "notify_unidle", N_("%_$0%_ %K[%n$5%K]%n %K[%n$1@$2%K] [%n%_$3%_%K]%n just stopped idling"), 6, { 0, 0, 0, 0, 0, 0 } },
{ "notify_online", N_("On $0: %_$1%_"), 2, { 0, 0 } },
{ "notify_offline", N_("Offline: $0"), 1, { 0 } },
{ "notify_list", N_("$0: $1 $2 $3"), 4, { 0, 0, 0, 0 } }
};

View File

@ -0,0 +1,19 @@
#include "printtext.h"
enum {
IRCTXT_MODULE_NAME,
IRCTXT_FILL_1,
IRCTXT_NOTIFY_JOIN,
IRCTXT_NOTIFY_PART,
IRCTXT_NOTIFY_AWAY,
IRCTXT_NOTIFY_UNAWAY,
IRCTXT_NOTIFY_UNIDLE,
IRCTXT_NOTIFY_ONLINE,
IRCTXT_NOTIFY_OFFLINE,
IRCTXT_NOTIFY_LIST
};
extern FORMAT_REC fecommon_irc_notifylist_formats[];
#define MODULE_FORMATS fecommon_irc_notifylist_formats

Some files were not shown because too many files have changed in this diff Show More