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:
parent
d01b094151
commit
c95034c6de
59
src/core/Makefile.am
Normal file
59
src/core/Makefile.am
Normal 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
60
src/core/args.c
Normal 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
15
src/core/args.h
Normal 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
462
src/core/commands.c
Normal 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
74
src/core/commands.h
Normal 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
68
src/core/core.c
Normal 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
17
src/core/core.h
Normal 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
160
src/core/levels.c
Normal 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
44
src/core/levels.h
Normal 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
147
src/core/line-split.c
Normal 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
13
src/core/line-split.h
Normal 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
438
src/core/log.c
Normal 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
49
src/core/log.h
Normal 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
356
src/core/memdebug.c
Normal 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
31
src/core/memdebug.h
Normal 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
467
src/core/misc.c
Normal 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
57
src/core/misc.h
Normal 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
3
src/core/module.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MODULE_NAME "core"
|
185
src/core/modules.c
Normal file
185
src/core/modules.c
Normal 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
33
src/core/modules.h
Normal 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
155
src/core/net-disconnect.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/core/net-disconnect.h
Normal file
7
src/core/net-disconnect.h
Normal 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
6
src/core/net-internal.h
Normal 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
210
src/core/net-nonblock.c
Normal 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
26
src/core/net-nonblock.h
Normal 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
451
src/core/network.c
Normal 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
71
src/core/network.h
Normal 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
74
src/core/pidwait.c
Normal 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
12
src/core/pidwait.h
Normal 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
167
src/core/rawlog.c
Normal 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
28
src/core/rawlog.h
Normal 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
323
src/core/server-redirect.c
Normal 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);
|
||||||
|
}
|
38
src/core/server-redirect.h
Normal file
38
src/core/server-redirect.h
Normal 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
273
src/core/server.c
Normal 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
66
src/core/server.h
Normal 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
336
src/core/settings.c
Normal 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
56
src/core/settings.h
Normal 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
356
src/core/signals.c
Normal 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
30
src/core/signals.h
Normal 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
635
src/core/special-vars.c
Normal 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
27
src/core/special-vars.h
Normal 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
|
1
src/fe-common/Makefile.am
Normal file
1
src/fe-common/Makefile.am
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = core irc
|
38
src/fe-common/core/Makefile.am
Normal file
38
src/fe-common/core/Makefile.am
Normal 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
|
62
src/fe-common/core/autorun.c
Normal file
62
src/fe-common/core/autorun.c
Normal 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);
|
||||||
|
}
|
182
src/fe-common/core/command-history.c
Normal file
182
src/fe-common/core/command-history.c
Normal 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);
|
||||||
|
}
|
16
src/fe-common/core/command-history.h
Normal file
16
src/fe-common/core/command-history.h
Normal 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
|
132
src/fe-common/core/fe-common-core.c
Normal file
132
src/fe-common/core/fe-common-core.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
8
src/fe-common/core/fe-common-core.h
Normal file
8
src/fe-common/core/fe-common-core.h
Normal 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
|
266
src/fe-common/core/fe-core-commands.c
Normal file
266
src/fe-common/core/fe-core-commands.c
Normal 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
402
src/fe-common/core/fe-log.c
Normal 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);
|
||||||
|
}
|
96
src/fe-common/core/fe-server.c
Normal file
96
src/fe-common/core/fe-server.c
Normal 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);
|
||||||
|
}
|
215
src/fe-common/core/fe-settings.c
Normal file
215
src/fe-common/core/fe-settings.c
Normal 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);
|
||||||
|
}
|
354
src/fe-common/core/hilight-text.c
Normal file
354
src/fe-common/core/hilight-text.c
Normal 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);
|
||||||
|
}
|
22
src/fe-common/core/hilight-text.h
Normal file
22
src/fe-common/core/hilight-text.h
Normal 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
|
297
src/fe-common/core/keyboard.c
Normal file
297
src/fe-common/core/keyboard.c
Normal 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);
|
||||||
|
}
|
40
src/fe-common/core/keyboard.h
Normal file
40
src/fe-common/core/keyboard.h
Normal 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
|
87
src/fe-common/core/module-formats.c
Normal file
87
src/fe-common/core/module-formats.c
Normal 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 }
|
||||||
|
};
|
62
src/fe-common/core/module-formats.h
Normal file
62
src/fe-common/core/module-formats.h
Normal 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
|
3
src/fe-common/core/module.h
Normal file
3
src/fe-common/core/module.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MODULE_NAME "fe-common/core"
|
115
src/fe-common/core/nick-hilight.c
Normal file
115
src/fe-common/core/nick-hilight.c
Normal 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);
|
||||||
|
}
|
858
src/fe-common/core/printtext.c
Normal file
858
src/fe-common/core/printtext.c
Normal 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);
|
||||||
|
}
|
61
src/fe-common/core/printtext.h
Normal file
61
src/fe-common/core/printtext.h
Normal 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
278
src/fe-common/core/themes.c
Normal 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;
|
||||||
|
}
|
40
src/fe-common/core/themes.h
Normal file
40
src/fe-common/core/themes.h
Normal 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
|
122
src/fe-common/core/translation.c
Normal file
122
src/fe-common/core/translation.c
Normal 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);
|
||||||
|
}
|
12
src/fe-common/core/translation.h
Normal file
12
src/fe-common/core/translation.h
Normal 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
|
224
src/fe-common/core/window-items.c
Normal file
224
src/fe-common/core/window-items.c
Normal 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);
|
||||||
|
}
|
22
src/fe-common/core/window-items.h
Normal file
22
src/fe-common/core/window-items.h
Normal 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
|
466
src/fe-common/core/windows.c
Normal file
466
src/fe-common/core/windows.c
Normal 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);
|
||||||
|
}
|
67
src/fe-common/core/windows.h
Normal file
67
src/fe-common/core/windows.h
Normal 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
|
32
src/fe-common/irc/Makefile.am
Normal file
32
src/fe-common/irc/Makefile.am
Normal 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
|
628
src/fe-common/irc/completion.c
Normal file
628
src/fe-common/irc/completion.c
Normal 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);
|
||||||
|
}
|
13
src/fe-common/irc/completion.h
Normal file
13
src/fe-common/irc/completion.h
Normal 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
|
17
src/fe-common/irc/dcc/Makefile.am
Normal file
17
src/fe-common/irc/dcc/Makefile.am
Normal 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
|
457
src/fe-common/irc/dcc/fe-dcc.c
Normal file
457
src/fe-common/irc/dcc/fe-dcc.c
Normal 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);
|
||||||
|
}
|
57
src/fe-common/irc/dcc/module-formats.c
Normal file
57
src/fe-common/irc/dcc/module-formats.c
Normal 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 } }
|
||||||
|
};
|
37
src/fe-common/irc/dcc/module-formats.h
Normal file
37
src/fe-common/irc/dcc/module-formats.h
Normal 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
|
123
src/fe-common/irc/fe-channels.c
Normal file
123
src/fe-common/irc/fe-channels.c
Normal 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);
|
||||||
|
}
|
172
src/fe-common/irc/fe-common-irc.c
Normal file
172
src/fe-common/irc/fe-common-irc.c
Normal 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);
|
||||||
|
}
|
8
src/fe-common/irc/fe-common-irc.h
Normal file
8
src/fe-common/irc/fe-common-irc.h
Normal 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
110
src/fe-common/irc/fe-ctcp.c
Normal 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);
|
||||||
|
}
|
707
src/fe-common/irc/fe-events-numeric.c
Normal file
707
src/fe-common/irc/fe-events-numeric.c
Normal 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", <ime) != 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, ×);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
682
src/fe-common/irc/fe-events.c
Normal file
682
src/fe-common/irc/fe-events.c
Normal 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);
|
||||||
|
}
|
248
src/fe-common/irc/fe-ignore.c
Normal file
248
src/fe-common/irc/fe-ignore.c
Normal 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);
|
||||||
|
}
|
541
src/fe-common/irc/fe-irc-commands.c
Normal file
541
src/fe-common/irc/fe-irc-commands.c
Normal 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);
|
||||||
|
}
|
133
src/fe-common/irc/fe-query.c
Normal file
133
src/fe-common/irc/fe-query.c
Normal 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);
|
||||||
|
}
|
17
src/fe-common/irc/flood/Makefile.am
Normal file
17
src/fe-common/irc/flood/Makefile.am
Normal 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
|
54
src/fe-common/irc/flood/fe-flood.c
Normal file
54
src/fe-common/irc/flood/fe-flood.c
Normal 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);
|
||||||
|
}
|
33
src/fe-common/irc/flood/module-formats.c
Normal file
33
src/fe-common/irc/flood/module-formats.c
Normal 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 } }
|
||||||
|
};
|
13
src/fe-common/irc/flood/module-formats.h
Normal file
13
src/fe-common/irc/flood/module-formats.h
Normal 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
|
54
src/fe-common/irc/irc-hilight-text.c
Normal file
54
src/fe-common/irc/irc-hilight-text.c
Normal 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);
|
||||||
|
}
|
6
src/fe-common/irc/irc-hilight-text.h
Normal file
6
src/fe-common/irc/irc-hilight-text.h
Normal 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
|
89
src/fe-common/irc/irc-nick-hilight.c
Normal file
89
src/fe-common/irc/irc-nick-hilight.c
Normal 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);
|
||||||
|
}
|
174
src/fe-common/irc/module-formats.c
Normal file
174
src/fe-common/irc/module-formats.c
Normal 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 }
|
||||||
|
};
|
146
src/fe-common/irc/module-formats.h
Normal file
146
src/fe-common/irc/module-formats.h
Normal 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
|
3
src/fe-common/irc/module.h
Normal file
3
src/fe-common/irc/module.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MODULE_NAME "fe-common/irc"
|
17
src/fe-common/irc/notifylist/Makefile.am
Normal file
17
src/fe-common/irc/notifylist/Makefile.am
Normal 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
|
241
src/fe-common/irc/notifylist/fe-notifylist.c
Normal file
241
src/fe-common/irc/notifylist/fe-notifylist.c
Normal 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);
|
||||||
|
}
|
39
src/fe-common/irc/notifylist/module-formats.c
Normal file
39
src/fe-common/irc/notifylist/module-formats.c
Normal 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 } }
|
||||||
|
};
|
19
src/fe-common/irc/notifylist/module-formats.h
Normal file
19
src/fe-common/irc/notifylist/module-formats.h
Normal 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
Loading…
Reference in New Issue
Block a user