mirror of
https://github.com/irssi/irssi.git
synced 2025-02-02 15:08:01 -05:00
Merge branch 'master' into integrate/0.8.20
This commit is contained in:
commit
ac73255483
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# On Windows, some Git clients may normalize all text files' line-endings to
|
||||
# CRLF, which causes obscure errors when running shell scripts.
|
||||
*.sh eol=lf
|
30
.travis.yml
30
.travis.yml
@ -16,11 +16,31 @@ addons:
|
||||
|
||||
before_install:
|
||||
- perl -V
|
||||
- ./autogen.sh --with-proxy --with-bot --with-perl=module
|
||||
- make dist
|
||||
- cd ..
|
||||
- tar xaf */irssi-*.tar.*
|
||||
- cd irssi-*
|
||||
|
||||
install: true
|
||||
|
||||
script:
|
||||
- ./autogen.sh --with-proxy --with-bot --with-perl=module --prefix=$HOME/irssi-build
|
||||
- cat config.log
|
||||
install:
|
||||
- ./configure --with-proxy --with-bot --with-perl=module --prefix=$HOME/irssi-build
|
||||
- make CFLAGS="-Wall -Werror"
|
||||
- make install
|
||||
|
||||
before_script:
|
||||
- cd
|
||||
- mkdir irssi-test
|
||||
- echo echo automated irssi launch test > irssi-test/startup;
|
||||
echo ^set settings_autosave off >> irssi-test/startup;
|
||||
echo ^set -clear log_close_string >> irssi-test/startup;
|
||||
echo ^set -clear log_day_changed >> irssi-test/startup;
|
||||
echo ^set -clear log_open_string >> irssi-test/startup;
|
||||
echo ^set log_timestamp '* ' >> irssi-test/startup;
|
||||
echo ^window log on >> irssi-test/startup
|
||||
- echo load perl >> irssi-test/startup
|
||||
- echo load proxy >> irssi-test/startup
|
||||
- echo ^quit >> irssi-test/startup
|
||||
- irssi-build/bin/irssi --home irssi-test
|
||||
- cat irc.log.*
|
||||
|
||||
script: true
|
||||
|
2
AUTHORS
2
AUTHORS
@ -97,3 +97,5 @@ Other patches (grep for "patch" in ChangeLog) by:
|
||||
Paul Johnson
|
||||
KindOne
|
||||
Fabian Kurz
|
||||
Todd Pratt
|
||||
xavierog
|
||||
|
26
INSTALL
26
INSTALL
@ -11,7 +11,8 @@ To compile irssi you need:
|
||||
|
||||
For most people, this should work just fine:
|
||||
|
||||
./configure
|
||||
./autogen.sh (for people who just cloned the repository)
|
||||
./configure (if this script already exists, skip ./autogen.sh)
|
||||
make
|
||||
su
|
||||
make install (not _really_ required except for perl support)
|
||||
@ -28,10 +29,6 @@ configure options
|
||||
|
||||
Build the irssi proxy (see startup-HOWTO).
|
||||
|
||||
--disable-ipv6
|
||||
|
||||
Disable IPv6 support.
|
||||
|
||||
--disable-ssl
|
||||
|
||||
Disable SSL support.
|
||||
@ -62,17 +59,11 @@ configure options
|
||||
|
||||
Build without text frontend
|
||||
|
||||
If ncurses is installed in a non-standard path you can specify it with
|
||||
--with-ncurses=/path. If anything else is in non-standard path, you can just
|
||||
give the paths in CPPFLAGS and LIBS environment variable, eg.:
|
||||
If anything is in non-standard path, you can just give the paths in
|
||||
CPPFLAGS and LIBS environment variable, eg.:
|
||||
|
||||
CPPFLAGS=-I/opt/openssl/include LDFLAGS=-L/opt/openssl/lib ./configure
|
||||
|
||||
Irssi doesn't really need curses anymore, by default it uses
|
||||
terminfo/termcap directly. The functions for using terminfo/termcap
|
||||
however are usually only in curses library, some systems use libtermcap
|
||||
as well. If you want to use only curses calls for some reason, use
|
||||
--without-terminfo.
|
||||
|
||||
|
||||
Perl problems
|
||||
@ -94,10 +85,11 @@ things that can go wrong:
|
||||
- If configure complains that it doesn't find some perl stuff, you're
|
||||
probably missing libperl.so or libperl.a. In debian, you'll need to do
|
||||
apt-get install libperl-dev
|
||||
- For unprivileged home directory installations, using the local::lib CPAN
|
||||
module is recommended. Read its docs, bootstrap it if needed, ensure that
|
||||
the environment variables are set before running the configure script, and
|
||||
append "--with-perl-lib=site" to the configure parameters to use it.
|
||||
- For unprivileged home directory installations, you probably do not want
|
||||
to specify --with-perl-lib=(site|vendor). Instead, you can use the
|
||||
default perl installation target (below the irssi prefix). If you are
|
||||
using local::lib you can also choose to install there by specifying
|
||||
--with-perl-lib=$PERL_LOCAL_LIB_ROOT/lib/perl5
|
||||
|
||||
You can verify that the perl module is loaded and working with "/LOAD"
|
||||
command. It should print something like:
|
||||
|
24
NEWS
24
NEWS
@ -1,3 +1,27 @@
|
||||
v0.8.21-head 2016-xx-xx The Irssi team <staff@irssi.org>
|
||||
* Removed --disable-ipv6
|
||||
* /connect Network now aborts with an error if no servers have been
|
||||
added to that network.
|
||||
* /dcc commands now use quotes around spaces consistently.
|
||||
+ irssiproxy can now forward all tags through a single port.
|
||||
+ irssiproxy can also listen on unix sockets.
|
||||
+ send channel -botcmds immediately when no mask is specified (#175).
|
||||
+ the kill buffer now remembers consecutive kills.
|
||||
New bindings were added: yank_next_cutbuffer and append_next_kill
|
||||
+ connections will avoid looking up IPv6 addresses if the machine does
|
||||
not have an IPv6 address assigned (exact behaviour is implementation
|
||||
defined).
|
||||
+ Fix potential crash if scripts insert undef values into the completion
|
||||
list.
|
||||
+ Paste warning is now also shown on pasting overlong lines.
|
||||
+ autolog_ignore_targets and activity_hide_targets learn a new syntax
|
||||
tag/* and * to ignore whole networks or everything.
|
||||
+ /hilight got a -matchcase flag to hilight case sensitively (#421).
|
||||
- IP addresses are no longer stored when resolve_reverse_lookup is
|
||||
used.
|
||||
- /names and $[...] now uses utf8 string operations (#40, #411).
|
||||
- Removed broken support for curses.
|
||||
|
||||
v0.8.20 2016-09-16 The Irssi team <staff@irssi.org>
|
||||
- Correct the name of an emitted sasl signal (#484)
|
||||
- Correct the prototype for the 'message private' signal (#515)
|
||||
|
31
acconfig.h
31
acconfig.h
@ -1,31 +0,0 @@
|
||||
/* misc.. */
|
||||
#undef HAVE_IPV6
|
||||
#undef HAVE_SOCKS_H
|
||||
#undef HAVE_STATIC_PERL
|
||||
#undef HAVE_GMODULE
|
||||
|
||||
/* macros/curses checks */
|
||||
#undef HAS_CURSES
|
||||
#undef USE_SUNOS_CURSES
|
||||
#undef USE_BSD_CURSES
|
||||
#undef USE_SYSV_CURSES
|
||||
#undef USE_NCURSES
|
||||
#undef NO_COLOR_CURSES
|
||||
#undef SCO_FLAVOR
|
||||
|
||||
/* our own curses checks */
|
||||
#undef HAVE_NCURSES_USE_DEFAULT_COLORS
|
||||
#undef HAVE_CURSES_IDCOK
|
||||
#undef HAVE_CURSES_RESIZETERM
|
||||
#undef HAVE_CURSES_WRESIZE
|
||||
|
||||
/* terminfo/termcap */
|
||||
#undef HAVE_TERMINFO
|
||||
|
||||
/* What type should be used for uoff_t */
|
||||
#undef UOFF_T_INT
|
||||
#undef UOFF_T_LONG
|
||||
#undef UOFF_T_LONG_LONG
|
||||
|
||||
/* printf()-format for uoff_t, eg. "u" or "lu" or "llu" */
|
||||
#undef PRIuUOFF_T
|
168
configure.ac
168
configure.ac
@ -1,4 +1,4 @@
|
||||
AC_INIT(irssi, 0.8.20)
|
||||
AC_INIT(irssi, 0.8.21-head)
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_AUX_DIR(build-aux)
|
||||
AC_PREREQ(2.50)
|
||||
@ -61,15 +61,6 @@ AC_ARG_WITH(proxy,
|
||||
fi,
|
||||
want_irssiproxy=no)
|
||||
|
||||
AC_ARG_WITH(terminfo,
|
||||
[ --without-terminfo Use curses backend instead of terminfo],
|
||||
if test x$withval = xno; then
|
||||
want_terminfo=no
|
||||
else
|
||||
want_terminfo=yes
|
||||
fi,
|
||||
want_terminfo=yes)
|
||||
|
||||
AC_ARG_WITH(modules,
|
||||
[ --with-modules Specify what modules to build in binary],
|
||||
if test x$withval != xyes -a x$withval != xno; then
|
||||
@ -79,7 +70,6 @@ AC_ARG_WITH(modules,
|
||||
if test "x$prefix" != "xNONE"; then
|
||||
prefix=`eval echo $prefix`
|
||||
PERL_MM_PARAMS="INSTALLDIRS=perl INSTALL_BASE=$prefix"
|
||||
perl_library_dir="PERL_USE_LIB"
|
||||
perl_set_use_lib=yes
|
||||
|
||||
perl_prefix_note=yes
|
||||
@ -97,30 +87,35 @@ AC_ARG_WITH(perl-staticlib,
|
||||
|
||||
|
||||
AC_ARG_WITH(perl-lib,
|
||||
[ --with-perl-lib=[site|vendor|DIR] Specify where to install the
|
||||
[ --with-perl-lib=[perl|site|vendor|DIR] Specify where to install the
|
||||
Perl libraries for irssi, default is site],
|
||||
if test "x$withval" = xyes; then
|
||||
want_perl=yes
|
||||
elif test "x$withval" = xno; then
|
||||
want_perl=no
|
||||
elif test "x$withval" = xperl; then
|
||||
want_perl=yes
|
||||
perl_prefix_note=no
|
||||
PERL_MM_PARAMS="INSTALLDIRS=perl"
|
||||
perl_set_use_lib=no
|
||||
elif test "x$withval" = xsite; then
|
||||
want_perl=yes
|
||||
perl_prefix_note=no
|
||||
PERL_MM_PARAMS=""
|
||||
perl_set_use_lib=no
|
||||
elif test "x$withval" = xvendor; then
|
||||
want_perl=yes
|
||||
perl_prefix_note=no
|
||||
if test -z "`$perlpath -v|grep '5\.0'`"; then
|
||||
PERL_MM_PARAMS="INSTALLDIRS=vendor"
|
||||
else
|
||||
PERL_MM_PARAMS="INSTALLDIRS=perl PREFIX=`perl -e 'use Config; print $Config{prefix}'`"
|
||||
PERL_MM_PARAMS="INSTALLDIRS=perl PREFIX=`$perlpath -e 'use Config; print $Config{prefix}'`"
|
||||
fi
|
||||
perl_library_dir="(vendor default - `$perlpath -e 'use Config; print $Config{archlib}'`)"
|
||||
perl_set_use_lib=no
|
||||
else
|
||||
want_perl=yes
|
||||
perl_prefix_note=no
|
||||
PERL_MM_PARAMS="INSTALLDIRS=perl LIB=$withval"
|
||||
perl_library_dir="PERL_USE_LIB"
|
||||
perl_set_use_lib=yes
|
||||
fi,
|
||||
want_perl=yes)
|
||||
@ -140,15 +135,6 @@ AC_ARG_WITH(perl,
|
||||
fi,
|
||||
want_perl=static)
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
[ --disable-ipv6 Disable IPv6 support],
|
||||
if test x$enableval = xno; then
|
||||
want_ipv6=no
|
||||
else
|
||||
want_ipv6=yes
|
||||
fi,
|
||||
want_ipv6=yes)
|
||||
|
||||
AC_ARG_ENABLE(dane,
|
||||
[ --enable-dane Enable DANE support],
|
||||
if test x$enableval = xno ; then
|
||||
@ -319,45 +305,19 @@ dnl **
|
||||
dnl ** curses checks
|
||||
dnl **
|
||||
|
||||
if test "x$want_textui" = "xyes"; then
|
||||
AC_CHECK_CURSES
|
||||
if test "x$want_textui" != "xno"; then
|
||||
|
||||
TEXTUI_LIBS="$CURSES_LIBS"
|
||||
if test "x$has_curses" = "xtrue"; then
|
||||
old_libs=$LIBS
|
||||
LIBS="$LIBS $CURSES_LIBS"
|
||||
if test $want_terminfo = no; then
|
||||
AC_CHECK_FUNC(use_default_colors, AC_DEFINE(HAVE_NCURSES_USE_DEFAULT_COLORS))
|
||||
AC_CHECK_FUNC(idcok, AC_DEFINE(HAVE_CURSES_IDCOK))
|
||||
AC_CHECK_FUNC(resizeterm, AC_DEFINE(HAVE_CURSES_RESIZETERM))
|
||||
AC_CHECK_FUNC(wresize, AC_DEFINE(HAVE_CURSES_WRESIZE))
|
||||
fi
|
||||
AC_CHECK_FUNC(setupterm,, [
|
||||
want_termcap=yes
|
||||
TEXTUI_NO_LIBS="$LIBS"
|
||||
LIBS=
|
||||
AC_SEARCH_LIBS([setupterm], [tinfo ncursesw ncurses], [want_textui=yes], [
|
||||
AC_ERROR(Terminfo not found - install libncurses-dev or ncurses-devel package)
|
||||
want_textui="no, Terminfo not found"
|
||||
])
|
||||
LIBS=$old_libs
|
||||
else
|
||||
AC_CHECK_LIB(tinfo, setupterm, [
|
||||
TEXTUI_LIBS="-ltinfo"
|
||||
want_terminfo=yes
|
||||
], AC_CHECK_LIB(termlib, tgetent, [
|
||||
TEXTUI_LIBS="-ltermlib"
|
||||
want_termcap=yes
|
||||
], AC_CHECK_LIB(termcap, tgetent, [
|
||||
TEXTUI_LIBS="-ltermcap"
|
||||
want_termcap=yes
|
||||
], [
|
||||
AC_ERROR(Terminfo/termcap not found - install libncurses-dev or ncurses-devel package)
|
||||
want_textui=no
|
||||
])))
|
||||
fi
|
||||
AC_SUBST(TEXTUI_LIBS)
|
||||
|
||||
if test "x$want_termcap" = "xyes"; then
|
||||
AC_CHECK_FUNC(tparm,, need_tparm=yes)
|
||||
else
|
||||
AC_DEFINE(HAVE_TERMINFO)
|
||||
fi
|
||||
TEXTUI_LIBS="$LIBS"
|
||||
AC_SUBST(TEXTUI_LIBS)
|
||||
LIBS="$TEXTUI_NO_LIBS"
|
||||
|
||||
fi
|
||||
|
||||
dnl **
|
||||
@ -380,7 +340,7 @@ if test "$want_perl" != "no"; then
|
||||
dnl * complain about them. Normally there's only few options
|
||||
dnl * that we want to keep:
|
||||
dnl * -Ddefine -Uundef -I/path -fopt -mopt
|
||||
PERL_CFLAGS=`echo $PERL_CFLAGS | $perlpath -pe 's/^(.* )?-[^DUIfm][^ ]+/\1/g; s/^(.* )?\+[^ ]+/\1/g'`
|
||||
PERL_CFLAGS=`echo $PERL_CFLAGS | $perlpath -pe 's/^(.* )?-@<:@^DUIfm@:>@@<:@^ @:>@+/\1/g; s/^(.* )?\+@<:@^ @:>@+/\1/g'`
|
||||
|
||||
PERL_EXTRA_OPTS="CCCDLFLAGS=\"-fPIC\""
|
||||
AC_SUBST(PERL_EXTRA_OPTS)
|
||||
@ -464,13 +424,37 @@ if test "$want_perl" != "no"; then
|
||||
PERL_STATIC_LIBS=0
|
||||
fi
|
||||
|
||||
# remove any prefix from PERL_MM_OPT
|
||||
PERL_MM_OPT=`perl -MText::ParseWords -e 'sub qu{$_=shift;s{^(.*?)=(.*)$}{($a,$b)=($1,$2);$b=~s/"/\\\\"/g;qq{$a="$b"}}ge if /@<:@\s"@:>@/;$_} local $,=" "; print map qu($_), grep !/^(INSTALL_BASE|PREFIX)=/, shellwords(@ARGV)' "$PERL_MM_OPT"`
|
||||
# figure out the correct @INC path - we'll need to do this
|
||||
# through MakeMaker since it's difficult to get it right
|
||||
# otherwise.
|
||||
if test "x$perl_set_use_lib" = "xyes"; then
|
||||
perl -e 'use ExtUtils::MakeMaker; WriteMakefile("NAME" => "test", "MAKEFILE" => "Makefile.test");' $PERL_MM_PARAMS >/dev/null
|
||||
PERL_USE_LIB=`perl -e 'open(F, "Makefile.test"); while (<F>) { chomp; if (/^(\w+) = (.*$)/) { $keys{$1} = $2; } }; $key = $keys{INSTALLARCHLIB}; while ($key =~ /\\$\((\w+)\)/) { $value = $keys{$1}; $key =~ s/\\$\($1\)/$value/; }; print $key;'`
|
||||
$perlpath -MExtUtils::MakeMaker -e 'WriteMakefile(NAME => "test", MAKEFILE => "Makefile.test", FIRST_MAKEFILE => "/dev/null", NO_META => 1, NO_MYMETA => 1);' $PERL_MM_PARAMS >/dev/null
|
||||
echo 'show-INSTALLDIRS:' >> Makefile.test
|
||||
echo ' @echo $(INSTALLDIRS)' >> Makefile.test
|
||||
perl_INSTALLDIRS=`$am_make -s -f Makefile.test show-INSTALLDIRS`
|
||||
if test "x$perl_INSTALLDIRS" = "xsite"; then
|
||||
perl_library_dir="site default"
|
||||
perl_INSTALL_VAR=INSTALLSITEARCH
|
||||
elif test "x$perl_INSTALLDIRS" = "xvendor"; then
|
||||
perl_library_dir="vendor default"
|
||||
perl_INSTALL_VAR=INSTALLVENDORARCH
|
||||
else
|
||||
perl_library_dir="module default"
|
||||
perl_INSTALL_VAR=INSTALLARCHLIB
|
||||
fi
|
||||
echo 'show-ARCHLIB:' >> Makefile.test
|
||||
echo ' @echo $('"$perl_INSTALL_VAR"')' >> Makefile.test
|
||||
perl_use_lib=`$am_make -s -f Makefile.test show-ARCHLIB`
|
||||
rm -f Makefile.test
|
||||
if test "x$perl_set_use_lib" = "xyes"; then
|
||||
if $perlpath -e 'exit ! grep $_ eq $ARGV@<:@0@:>@, grep /^\//, @INC' "$perl_use_lib"; then
|
||||
perl_library_dir="other path in @INC"
|
||||
perl_set_use_lib=no
|
||||
else
|
||||
perl_library_dir="prepends to @INC with /set perl_use_lib"
|
||||
PERL_USE_LIB="$perl_use_lib"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(perl_module_lib)
|
||||
@ -486,6 +470,7 @@ if test "$want_perl" != "no"; then
|
||||
AC_SUBST(PERL_CFLAGS)
|
||||
|
||||
AC_SUBST(PERL_USE_LIB)
|
||||
AC_SUBST(PERL_MM_OPT)
|
||||
AC_SUBST(PERL_MM_PARAMS)
|
||||
AC_SUBST(PERL_STATIC_LIBS)
|
||||
fi
|
||||
@ -496,8 +481,6 @@ AM_CONDITIONAL(BUILD_TEXTUI, test "$want_textui" = "yes")
|
||||
AM_CONDITIONAL(BUILD_IRSSIBOT, test "$want_irssibot" = "yes")
|
||||
AM_CONDITIONAL(BUILD_IRSSIPROXY, test "$want_irssiproxy" = "yes")
|
||||
AM_CONDITIONAL(HAVE_PERL, test "$want_perl" != "no")
|
||||
AM_CONDITIONAL(NEED_TPARM, test "$need_tparm" = "yes")
|
||||
AM_CONDITIONAL(USE_CURSES, test "$want_terminfo" != "yes" -a "$want_termcap" != "yes")
|
||||
|
||||
# move LIBS to PROG_LIBS so they're not tried to be used when linking eg. perl libraries
|
||||
PROG_LIBS=$LIBS
|
||||
@ -577,29 +560,6 @@ COMMON_LIBS="$FE_COMMON_LIBS $COMMON_NOUI_LIBS"
|
||||
AC_SUBST(COMMON_NOUI_LIBS)
|
||||
AC_SUBST(COMMON_LIBS)
|
||||
|
||||
dnl **
|
||||
dnl ** IPv6 support
|
||||
dnl **
|
||||
|
||||
have_ipv6=no
|
||||
if test "x$want_ipv6" = "xyes"; then
|
||||
AC_MSG_CHECKING([for IPv6])
|
||||
AC_CACHE_VAL(irssi_cv_type_in6_addr,
|
||||
[AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>],
|
||||
[struct in6_addr i = in6addr_any; return &i == &i;],
|
||||
have_ipv6=yes,
|
||||
)])
|
||||
if test $have_ipv6 = yes; then
|
||||
AC_DEFINE(HAVE_IPV6)
|
||||
fi
|
||||
AC_MSG_RESULT($have_ipv6)
|
||||
fi
|
||||
|
||||
have_dane=no
|
||||
if test "x$want_dane" = "xyes"; then
|
||||
AC_MSG_CHECKING([for DANE])
|
||||
@ -617,12 +577,20 @@ if test "x$want_dane" = "xyes"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$want_truecolor" = "xyes" -a "x$want_termcap" != "xyes" -a "x$want_terminfo" = "xyes" ; then
|
||||
if test "x$want_truecolor" = "xyes"; then
|
||||
AC_DEFINE([TERM_TRUECOLOR], [], [true color support in terminal])
|
||||
else
|
||||
want_truecolor=no
|
||||
fi
|
||||
|
||||
AH_TEMPLATE(HAVE_GMODULE)
|
||||
AH_TEMPLATE(HAVE_SOCKS_H, [misc..])
|
||||
AH_TEMPLATE(HAVE_STATIC_PERL)
|
||||
AH_TEMPLATE(PRIuUOFF_T, [printf()-format for uoff_t, eg. "u" or "lu" or "llu"])
|
||||
AH_TEMPLATE(UOFF_T_INT, [What type should be used for uoff_t])
|
||||
AH_TEMPLATE(UOFF_T_LONG)
|
||||
AH_TEMPLATE(UOFF_T_LONG_LONG)
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
@ -675,16 +643,7 @@ fi
|
||||
|
||||
echo
|
||||
|
||||
if test "x$want_textui" = "xno"; then
|
||||
text=no
|
||||
elif test "x$want_termcap" = "xyes"; then
|
||||
text="yes, using termcap"
|
||||
elif test "x$want_terminfo" = "xyes"; then
|
||||
text="yes, using terminfo"
|
||||
else
|
||||
text="yes, using curses"
|
||||
fi
|
||||
echo "Building text frontend ........... : $text"
|
||||
echo "Building text frontend ........... : $want_textui"
|
||||
echo "Building irssi bot ............... : $want_irssibot"
|
||||
echo "Building irssi proxy ............. : $want_irssiproxy"
|
||||
if test "x$have_gmodule" = "xyes"; then
|
||||
@ -724,13 +683,7 @@ if test "x$want_perl" != "xno" -a "x$perl_mod_error" != "x"; then
|
||||
fi
|
||||
|
||||
if test "x$want_perl" != "xno"; then
|
||||
if test "$perl_library_dir" = "PERL_USE_LIB"; then
|
||||
perl_library_dir=$PERL_USE_LIB
|
||||
fi
|
||||
if test -z "$perl_library_dir"; then
|
||||
perl_library_dir="(site default - `$perlpath -e 'use Config; print $Config{sitearch}'`)"
|
||||
fi
|
||||
echo "Perl library directory ........... : $perl_library_dir"
|
||||
echo "Perl library directory ........... : ($perl_library_dir - $perl_use_lib)"
|
||||
if test "x$perl_prefix_note" = "xyes"; then
|
||||
echo " - NOTE: This was automatically set to the same directory you gave with"
|
||||
echo " --prefix. If you want the perl libraries to install to their 'correct'"
|
||||
@ -742,7 +695,6 @@ echo "Install prefix ................... : $prefix"
|
||||
|
||||
echo
|
||||
|
||||
echo "Building with IPv6 support ....... : $have_ipv6"
|
||||
echo "Building with SSL support ........ : $have_openssl"
|
||||
if test "x$have_openssl" = "xno" -a "x$enable_ssl" = "xyes"; then
|
||||
if test -f /etc/debian_version; then
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
LIST: Displays the list of configured channels.
|
||||
ADD: Adds a channel to your configuration.
|
||||
MODIFY: Modifies a channel in your configuration.
|
||||
REMOVE: Removes a channel from your configuration.
|
||||
|
||||
-auto: Automatically join the channel.
|
||||
@ -36,6 +37,7 @@
|
||||
/CHANNEL ADD -auto #basementcat Quakenet secret_lair
|
||||
/CHANNEL ADD -auto -bots '*!@*.irssi.org *!bot@irssi.org' -botcmd 'msg $0 op WzerTrzq' #hideout Freenode
|
||||
/CHANNEL ADD -auto -bots 'Q!TheQBot@CServe.quakenet.org' -botcmd '^MSG Q op #irssi' #irssi Quakenet
|
||||
/CHANNEL MODIFY -noauto #irssi Freenode
|
||||
/CHANNEL REMOVE #hideout Freenode
|
||||
|
||||
%9Special Example:%9
|
||||
|
@ -36,10 +36,10 @@
|
||||
%9Examples:%9
|
||||
|
||||
/DCC CHAT mike
|
||||
/DCC GET bob summer vacation.mkv
|
||||
/DCC GET bob "summer vacation.mkv"
|
||||
/DCC SEND sarah "summer vacation.mkv"
|
||||
/DCC CLOSE get mike
|
||||
/DCC CLOSE send bob summer vacation.mkv
|
||||
/DCC CLOSE send bob "summer vacation.mkv"
|
||||
|
||||
%9See also:%9 CD
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
-line: Highlights the whole line.
|
||||
-mask: Highlights all messages from users matching the mask.
|
||||
-full: The text must match the full word.
|
||||
-matchcase: The text must match case.
|
||||
-regexp: The text is a regular expression.
|
||||
-color: The color the display the highlight in.
|
||||
-actcolor: The color to mark the highlight activity in the statusbar.
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
LIST: Displays the list of configured networks.
|
||||
ADD: Adds a network to your configuration.
|
||||
MODIFY: Modifies a network in your configuration.
|
||||
REMOVE: Removes a network from your configuration.
|
||||
|
||||
-nick: Specifies the nickname to use.
|
||||
@ -59,6 +60,7 @@
|
||||
/NETWORK ADD -usermode +iw -nick mike -realname 'The one and only mike!' -host staff.irssi.org Freenode
|
||||
/NETWORK ADD -autosendcmd '^MSG NickServ identify WzerT8zq' Freenode
|
||||
/NETWORK ADD -autosendcmd '^MSG Q@CServe.quakenet.org AUTH mike WzerT8zq; WAIT 2000; OPER mike WzerT8zq; WAIT 2000; MODE mike +kXP' Quakenet
|
||||
/NETWORK MODIFY -usermode +gi EFnet
|
||||
/NETWORK REMOVE Freenode
|
||||
|
||||
%9See also:%9 CHANNEL, CONNECT, SERVER
|
||||
|
@ -12,6 +12,8 @@
|
||||
RESET: Unloads all the scripts.
|
||||
-permanent: In combination with EXEC, the code will be loaded into the
|
||||
memory.
|
||||
-autorun: When passed to RESET the scripts in the autorun folder are
|
||||
reloaded.
|
||||
|
||||
If no argument is given, the list of active scripts will be displayed.
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
LIST: Displays the list of servers you are connected to.
|
||||
CONNECT: Connects to the given server.
|
||||
ADD: Adds a server to your configuration.
|
||||
MODIFY: Modifies a server in your configuration.
|
||||
REMOVE: Removes a server from your configuration.
|
||||
PURGE: Purges the commands queued to be sent to the server.
|
||||
|
||||
@ -62,6 +63,7 @@
|
||||
/SERVER CONNECT +chat.freenode.net
|
||||
/SERVER ADD -network Freenode -noautosendcmd orwell.freenode.net
|
||||
/SERVER ADD -! -auto -host staff.irssi.org -port 6667 -4 -network Freenode -noproxy orwell.freenode.net
|
||||
/SERVER MODIFY -network Freenode -noauto orwell.freenode.net
|
||||
/SERVER REMOVE orwell.freenode.net 6667 Freenode
|
||||
/SERVER PURGE
|
||||
/SERVER PURGE orwell.freenode.net
|
||||
|
@ -51,9 +51,6 @@ use
|
||||
.I HOSTNAME
|
||||
for your irc session
|
||||
.TP
|
||||
.BI "\-d, \-\-dummy"
|
||||
use dummy terminal mode
|
||||
.TP
|
||||
.BI "\-v, \-\-version"
|
||||
display the version of Irssi
|
||||
.TP
|
||||
|
@ -30,6 +30,18 @@ There we have 3 different irc networks answering in 3 ports. Note that
|
||||
you'll have to make the correct /IRCNET ADD and /SERVER ADD commands to
|
||||
make it work properly.
|
||||
|
||||
The special network name "?" allows the client to select the network
|
||||
dynamically on connect:
|
||||
|
||||
/SET irssiproxy_ports ?=2777
|
||||
|
||||
Now the client can send <network>:<password> as the server password, e.g.
|
||||
|
||||
/CONNECT ... 2777 efnet:secret
|
||||
|
||||
to connect to efnet. If there is no irssiproxy_password set, you can
|
||||
omit the ":" and just send the network name as the password.
|
||||
|
||||
By default, the proxy binds to all available interfaces. To make it
|
||||
only listen on (for example) the loopback address:
|
||||
|
||||
|
@ -497,6 +497,13 @@
|
||||
<pre><code> /SET irssiproxy_ports *=2777
|
||||
</code></pre>
|
||||
|
||||
<p>The special network name <code>?</code> allows the client to select the
|
||||
network dynamically on connect (see below):</p>
|
||||
|
||||
<pre>
|
||||
/SET irssiproxy_ports ?=2777
|
||||
</pre>
|
||||
|
||||
<p>Usage in client side:</p>
|
||||
|
||||
<p>Just connect to the irssi proxy like it is a normal server with password specified in <code>/SET irssiproxy_password</code>. For example:</p>
|
||||
@ -505,6 +512,16 @@
|
||||
/SERVER ADD -network efnet my.irssi-proxy.org 2778 secret
|
||||
</code></pre>
|
||||
|
||||
<p>Or, if you used <code>?</code> in <code>irssiproxy_ports</code>:</p>
|
||||
|
||||
<pre>
|
||||
/SERVER ADD -network IRCnet my.irssi-proxy.org 2777 IRCnet:secret
|
||||
/SERVER ADD -network efnet my.irssi-proxy.org 2777 efnet:secret
|
||||
</pre>
|
||||
|
||||
<p>I.e. the network to connect to is specified as part of the password,
|
||||
separated by <code>:</code> from the actual proxy password.</p>
|
||||
|
||||
<p>Irssi proxy works fine with other IRC clients as well.</p>
|
||||
|
||||
<p><strong>SOCKS</strong></p>
|
||||
|
298
m4/curses.m4
298
m4/curses.m4
@ -1,298 +0,0 @@
|
||||
dnl Curses detection: Munged from Midnight Commander's configure.in
|
||||
dnl
|
||||
dnl What it does:
|
||||
dnl =============
|
||||
dnl
|
||||
dnl - Determine which version of curses is installed on your system
|
||||
dnl and set the -I/-L/-l compiler entries and add a few preprocessor
|
||||
dnl symbols
|
||||
dnl - Do an AC_SUBST on the CURSES_INCLUDEDIR and CURSES_LIBS so that
|
||||
dnl @CURSES_INCLUDEDIR@ and @CURSES_LIBS@ will be available in
|
||||
dnl Makefile.in's
|
||||
dnl - Modify the following configure variables (these are the only
|
||||
dnl curses.m4 variables you can access from within configure.in)
|
||||
dnl CURSES_INCLUDEDIR - contains -I's and possibly -DRENAMED_CURSES if
|
||||
dnl an ncurses.h that's been renamed to curses.h
|
||||
dnl is found.
|
||||
dnl CURSES_LIBS - sets -L and -l's appropriately
|
||||
dnl CFLAGS - if --with-sco, add -D_SVID3
|
||||
dnl has_curses - exports result of tests to rest of configure
|
||||
dnl
|
||||
dnl Usage:
|
||||
dnl ======
|
||||
dnl 1) Add lines indicated below to acconfig.h
|
||||
dnl 2) call AC_CHECK_CURSES after AC_PROG_CC in your configure.in
|
||||
dnl 3) Instead of #include <curses.h> you should use the following to
|
||||
dnl properly locate ncurses or curses header file
|
||||
dnl
|
||||
dnl #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
|
||||
dnl #include <ncurses.h>
|
||||
dnl #else
|
||||
dnl #include <curses.h>
|
||||
dnl #endif
|
||||
dnl
|
||||
dnl 4) Make sure to add @CURSES_INCLUDEDIR@ to your preprocessor flags
|
||||
dnl 5) Make sure to add @CURSES_LIBS@ to your linker flags or LIBS
|
||||
dnl
|
||||
dnl Notes with automake:
|
||||
dnl - call AM_CONDITIONAL(HAS_CURSES, test "$has_curses" = true) from
|
||||
dnl configure.in
|
||||
dnl - your Makefile.am can look something like this
|
||||
dnl -----------------------------------------------
|
||||
dnl INCLUDES= blah blah blah $(CURSES_INCLUDEDIR)
|
||||
dnl if HAS_CURSES
|
||||
dnl CURSES_TARGETS=name_of_curses_prog
|
||||
dnl endif
|
||||
dnl bin_PROGRAMS = other_programs $(CURSES_TARGETS)
|
||||
dnl other_programs_SOURCES = blah blah blah
|
||||
dnl name_of_curses_prog_SOURCES = blah blah blah
|
||||
dnl other_programs_LDADD = blah
|
||||
dnl name_of_curses_prog_LDADD = blah $(CURSES_LIBS)
|
||||
dnl -----------------------------------------------
|
||||
dnl
|
||||
dnl
|
||||
dnl The following lines should be added to acconfig.h:
|
||||
dnl ==================================================
|
||||
dnl
|
||||
dnl /*=== Curses version detection defines ===*/
|
||||
dnl /* Found some version of curses that we're going to use */
|
||||
dnl #undef HAS_CURSES
|
||||
dnl
|
||||
dnl /* Use SunOS SysV curses? */
|
||||
dnl #undef USE_SUNOS_CURSES
|
||||
dnl
|
||||
dnl /* Use old BSD curses - not used right now */
|
||||
dnl #undef USE_BSD_CURSES
|
||||
dnl
|
||||
dnl /* Use SystemV curses? */
|
||||
dnl #undef USE_SYSV_CURSES
|
||||
dnl
|
||||
dnl /* Use Ncurses? */
|
||||
dnl #undef USE_NCURSES
|
||||
dnl
|
||||
dnl /* If you Curses does not have color define this one */
|
||||
dnl #undef NO_COLOR_CURSES
|
||||
dnl
|
||||
dnl /* Define if you want to turn on SCO-specific code */
|
||||
dnl #undef SCO_FLAVOR
|
||||
dnl
|
||||
dnl /* Set to reflect version of ncurses *
|
||||
dnl * 0 = version 1.*
|
||||
dnl * 1 = version 1.9.9g
|
||||
dnl * 2 = version 4.0/4.1 */
|
||||
dnl #undef NCURSES_970530
|
||||
dnl
|
||||
dnl /*=== End new stuff for acconfig.h ===*/
|
||||
dnl
|
||||
|
||||
|
||||
AC_DEFUN([AC_CHECK_CURSES],[
|
||||
search_ncurses=true
|
||||
screen_manager=""
|
||||
has_curses=false
|
||||
|
||||
CFLAGS=${CFLAGS--O}
|
||||
|
||||
AC_SUBST(CURSES_LIBS)
|
||||
AC_SUBST(CURSES_INCLUDEDIR)
|
||||
|
||||
AC_ARG_WITH(sco,
|
||||
[ --with-sco Use this to turn on SCO-specific code],[
|
||||
if test x$withval = xyes; then
|
||||
AC_DEFINE(SCO_FLAVOR)
|
||||
CFLAGS="$CFLAGS -D_SVID3"
|
||||
fi
|
||||
])
|
||||
|
||||
AC_ARG_WITH(sunos-curses,
|
||||
[ --with-sunos-curses Used to force SunOS 4.x curses],[
|
||||
if test x$withval = xyes; then
|
||||
AC_USE_SUNOS_CURSES
|
||||
fi
|
||||
])
|
||||
|
||||
AC_ARG_WITH(osf1-curses,
|
||||
[ --with-osf1-curses Used to force OSF/1 curses],[
|
||||
if test x$withval = xyes; then
|
||||
AC_USE_OSF1_CURSES
|
||||
fi
|
||||
])
|
||||
|
||||
AC_ARG_WITH(vcurses,
|
||||
[[ --with-vcurses[=incdir] Used to force SysV curses]],
|
||||
if test x$withval != xyes; then
|
||||
CURSES_INCLUDEDIR="-I$withval"
|
||||
fi
|
||||
AC_USE_SYSV_CURSES
|
||||
)
|
||||
|
||||
AC_ARG_WITH(ncurses,
|
||||
[[ --with-ncurses[=dir] Compile with ncurses/locate base dir]],
|
||||
if test x$withval = xno ; then
|
||||
search_ncurses=false
|
||||
elif test x$withval != xyes ; then
|
||||
AC_NCURSES($withval/include, ncurses.h, -L$withval/lib -lncurses, -I$withval/include, [ncurses on $withval/include])
|
||||
fi
|
||||
)
|
||||
|
||||
if $search_ncurses
|
||||
then
|
||||
AC_SEARCH_NCURSES()
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([AC_USE_SUNOS_CURSES], [
|
||||
search_ncurses=false
|
||||
screen_manager="SunOS 4.x /usr/5include curses"
|
||||
AC_MSG_RESULT(Using SunOS 4.x /usr/5include curses)
|
||||
AC_DEFINE(USE_SUNOS_CURSES)
|
||||
AC_DEFINE(HAS_CURSES)
|
||||
has_curses=true
|
||||
AC_DEFINE(NO_COLOR_CURSES)
|
||||
AC_DEFINE(USE_SYSV_CURSES)
|
||||
CURSES_INCLUDEDIR="-I/usr/5include"
|
||||
CURSES_LIBS="/usr/5lib/libcurses.a /usr/5lib/libtermcap.a"
|
||||
AC_MSG_RESULT(Please note that some screen refreshs may fail)
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_USE_OSF1_CURSES], [
|
||||
AC_MSG_RESULT(Using OSF1 curses)
|
||||
search_ncurses=false
|
||||
screen_manager="OSF1 curses"
|
||||
AC_DEFINE(HAS_CURSES)
|
||||
has_curses=true
|
||||
AC_DEFINE(NO_COLOR_CURSES)
|
||||
AC_DEFINE(USE_SYSV_CURSES)
|
||||
CURSES_LIBS="-lcurses"
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_USE_SYSV_CURSES], [
|
||||
AC_MSG_RESULT(Using SysV curses)
|
||||
AC_DEFINE(HAS_CURSES)
|
||||
has_curses=true
|
||||
AC_DEFINE(USE_SYSV_CURSES)
|
||||
search_ncurses=false
|
||||
screen_manager="SysV/curses"
|
||||
CURSES_LIBS="-lcurses"
|
||||
])
|
||||
|
||||
dnl AC_ARG_WITH(bsd-curses,
|
||||
dnl [--with-bsd-curses Used to compile with bsd curses, not very fancy],
|
||||
dnl search_ncurses=false
|
||||
dnl screen_manager="Ultrix/cursesX"
|
||||
dnl if test $system = ULTRIX
|
||||
dnl then
|
||||
dnl THIS_CURSES=cursesX
|
||||
dnl else
|
||||
dnl THIS_CURSES=curses
|
||||
dnl fi
|
||||
dnl
|
||||
dnl CURSES_LIBS="-l$THIS_CURSES -ltermcap"
|
||||
dnl AC_DEFINE(HAS_CURSES)
|
||||
dnl has_curses=true
|
||||
dnl AC_DEFINE(USE_BSD_CURSES)
|
||||
dnl AC_MSG_RESULT(Please note that some screen refreshs may fail)
|
||||
dnl AC_WARN(Use of the bsdcurses extension has some)
|
||||
dnl AC_WARN(display/input problems.)
|
||||
dnl AC_WARN(Reconsider using xcurses)
|
||||
dnl)
|
||||
|
||||
|
||||
dnl
|
||||
dnl Parameters: directory filename curses_LIBS curses_INCLUDEDIR nicename
|
||||
dnl
|
||||
AC_DEFUN([AC_NCURSES], [
|
||||
if $search_ncurses
|
||||
then
|
||||
if test -f $1/$2
|
||||
then
|
||||
AC_MSG_RESULT(Found ncurses on $1/$2)
|
||||
|
||||
CURSES_LIBS="$3"
|
||||
AC_CHECK_LIB(ncurses, initscr, [
|
||||
true;
|
||||
], [
|
||||
CHECKLIBS=`echo "$3"|sed 's/-lncurses/-lcurses/g'`
|
||||
AC_CHECK_LIB(curses, initscr, [
|
||||
CURSES_LIBS="$CHECKLIBS"
|
||||
],, $CHECKLIBS)
|
||||
], $CURSES_LIBS)
|
||||
CURSES_INCLUDEDIR="$4"
|
||||
search_ncurses=false
|
||||
screen_manager="$5"
|
||||
AC_DEFINE(HAS_CURSES)
|
||||
has_curses=true
|
||||
has_ncurses=true
|
||||
AC_DEFINE(USE_NCURSES)
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_SEARCH_NCURSES], [
|
||||
AC_CHECKING("location of ncurses.h file")
|
||||
|
||||
AC_NCURSES(/usr/include, ncurses.h, -lncurses,,
|
||||
[ncurses in /usr/include])
|
||||
AC_NCURSES(/usr/include/ncurses, ncurses.h, -lncurses, -I/usr/include/ncurses,
|
||||
[ncurses in /usr/include/ncurses])
|
||||
AC_NCURSES(/usr/local/include, ncurses.h, -L/usr/local/lib -lncurses, -I/usr/local/include,
|
||||
[ncurses in /usr/local/include])
|
||||
AC_NCURSES(/usr/local/include/ncurses, ncurses.h, -L/usr/local/lib -lncurses, -I/usr/local/include/ncurses,
|
||||
[ncurses in /usr/local/include/ncurses])
|
||||
AC_NCURSES(/usr/local/include/ncurses, curses.h, -L/usr/local/lib -lncurses, -I/usr/local/include/ncurses -DRENAMED_NCURSES,
|
||||
[renamed ncurses in /usr/local/include/ncurses])
|
||||
AC_NCURSES(/usr/include/ncurses, curses.h, -lncurses, -I/usr/include/ncurses -DRENAMED_NCURSES,
|
||||
[renamed ncurses in /usr/include/ncurses])
|
||||
|
||||
dnl
|
||||
dnl We couldn't find ncurses, try SysV curses
|
||||
dnl
|
||||
if $search_ncurses
|
||||
then
|
||||
AC_EGREP_HEADER(init_color, /usr/include/curses.h,
|
||||
AC_USE_SYSV_CURSES)
|
||||
AC_EGREP_CPP(USE_NCURSES,[
|
||||
#include <curses.h>
|
||||
#ifdef __NCURSES_H
|
||||
#undef USE_NCURSES
|
||||
USE_NCURSES
|
||||
#endif
|
||||
],[
|
||||
CURSES_INCLUDEDIR="$CURSES_INCLUDEDIR -DRENAMED_NCURSES"
|
||||
AC_DEFINE(HAS_CURSES)
|
||||
has_curses=true
|
||||
has_ncurses=true
|
||||
AC_DEFINE(USE_NCURSES)
|
||||
search_ncurses=false
|
||||
screen_manager="ncurses installed as curses"
|
||||
])
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl Try SunOS 4.x /usr/5{lib,include} ncurses
|
||||
dnl The flags USE_SUNOS_CURSES, USE_BSD_CURSES and BUGGY_CURSES
|
||||
dnl should be replaced by a more fine grained selection routine
|
||||
dnl
|
||||
if $search_ncurses
|
||||
then
|
||||
if test -f /usr/5include/curses.h
|
||||
then
|
||||
AC_USE_SUNOS_CURSES
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl use whatever curses there happens to be
|
||||
if $search_ncurses
|
||||
then
|
||||
if test -f /usr/include/curses.h
|
||||
then
|
||||
CURSES_LIBS="-lcurses"
|
||||
AC_DEFINE(HAS_CURSES)
|
||||
has_curses=true
|
||||
search_ncurses=false
|
||||
screen_manager="curses"
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
|
||||
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
|
||||
|
||||
#define IRSSI_ABI_VERSION 2
|
||||
#define IRSSI_ABI_VERSION 6
|
||||
|
||||
#define DEFAULT_SERVER_ADD_PORT 6667
|
||||
|
||||
|
@ -44,6 +44,8 @@ libcore_a_SOURCES = \
|
||||
settings.c \
|
||||
signals.c \
|
||||
special-vars.c \
|
||||
utf8.c \
|
||||
wcwidth.c \
|
||||
write-buffer.c
|
||||
|
||||
structure_headers = \
|
||||
@ -93,6 +95,7 @@ pkginc_core_HEADERS = \
|
||||
settings.h \
|
||||
signals.h \
|
||||
special-vars.h \
|
||||
utf8.h \
|
||||
window-item-def.h \
|
||||
write-buffer.h \
|
||||
$(structure_headers)
|
||||
|
@ -231,6 +231,31 @@ static int match_nick_flags(SERVER_REC *server, NICK_REC *nick, char flag)
|
||||
|
||||
/* Send the auto send command to channel */
|
||||
void channel_send_autocommands(CHANNEL_REC *channel)
|
||||
{
|
||||
CHANNEL_SETUP_REC *rec;
|
||||
|
||||
g_return_if_fail(IS_CHANNEL(channel));
|
||||
|
||||
if (channel->session_rejoin)
|
||||
return;
|
||||
|
||||
rec = channel_setup_find(channel->name, channel->server->connrec->chatnet);
|
||||
if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
|
||||
return;
|
||||
|
||||
/* if the autosendcmd alone (with no -bots parameter) has been
|
||||
* specified then send it right after joining the channel, when
|
||||
* the WHO list hasn't been yet retrieved.
|
||||
* Depending on the value of the 'channel_max_who_sync' option
|
||||
* the WHO list might not be retrieved after the join event. */
|
||||
|
||||
if (rec->botmasks == NULL || !*rec->botmasks) {
|
||||
/* just send the command. */
|
||||
eval_special_string(rec->autosendcmd, "", channel->server, channel);
|
||||
}
|
||||
}
|
||||
|
||||
void channel_send_botcommands(CHANNEL_REC *channel)
|
||||
{
|
||||
CHANNEL_SETUP_REC *rec;
|
||||
NICK_REC *nick;
|
||||
@ -245,11 +270,9 @@ void channel_send_autocommands(CHANNEL_REC *channel)
|
||||
if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
|
||||
return;
|
||||
|
||||
if (rec->botmasks == NULL || !*rec->botmasks) {
|
||||
/* just send the command. */
|
||||
eval_special_string(rec->autosendcmd, "", channel->server, channel);
|
||||
/* this case has already been handled by channel_send_autocommands */
|
||||
if (rec->botmasks == NULL || !*rec->botmasks)
|
||||
return;
|
||||
}
|
||||
|
||||
/* find first available bot.. */
|
||||
bots = g_strsplit(rec->botmasks, " ", -1);
|
||||
|
@ -31,6 +31,7 @@ void channel_change_visible_name(CHANNEL_REC *channel, const char *name);
|
||||
|
||||
/* Send the auto send command to channel */
|
||||
void channel_send_autocommands(CHANNEL_REC *channel);
|
||||
void channel_send_botcommands(CHANNEL_REC *channel);
|
||||
|
||||
void channels_init(void);
|
||||
void channels_deinit(void);
|
||||
|
@ -73,6 +73,13 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
|
||||
|
||||
conn = server_create_conn(proto != NULL ? proto->id : -1, addr,
|
||||
atoi(portstr), chatnet, password, nick);
|
||||
if (conn == NULL) {
|
||||
signal_emit("error command", 1,
|
||||
GINT_TO_POINTER(CMDERR_NO_SERVER_DEFINED));
|
||||
cmd_params_free(free_arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (proto == NULL)
|
||||
proto = chat_protocol_find_id(conn->chat_type);
|
||||
|
||||
|
@ -41,7 +41,8 @@ enum {
|
||||
CMDERR_INVALID_TIME, /* invalid time specification */
|
||||
CMDERR_INVALID_CHARSET, /* invalid charset specification */
|
||||
CMDERR_EVAL_MAX_RECURSE, /* eval hit recursion limit */
|
||||
CMDERR_PROGRAM_NOT_FOUND /* program not found */
|
||||
CMDERR_PROGRAM_NOT_FOUND, /* program not found */
|
||||
CMDERR_NO_SERVER_DEFINED, /* no server has been defined for a given chatnet */
|
||||
};
|
||||
|
||||
/* Return the full command for `alias' */
|
||||
|
@ -241,7 +241,7 @@ IGNORE_REC *ignore_find_full(const char *servertag, const char *mask, const char
|
||||
if (channels == NULL || rec->channels == NULL)
|
||||
continue; /* other doesn't have channels */
|
||||
|
||||
if (strarray_length(channels) != strarray_length(rec->channels))
|
||||
if (g_strv_length(channels) != g_strv_length(rec->channels))
|
||||
continue; /* different amount of channels */
|
||||
|
||||
/* check that channels match */
|
||||
|
@ -114,7 +114,7 @@ int log_start_logging(LOG_REC *log)
|
||||
/* path may contain variables (%time, $vars),
|
||||
make sure the directory is created */
|
||||
dir = g_path_get_dirname(log->real_fname);
|
||||
mkpath(dir, log_dir_create_mode);
|
||||
g_mkdir_with_parents(dir, log_dir_create_mode);
|
||||
g_free(dir);
|
||||
}
|
||||
|
||||
|
143
src/core/misc.c
143
src/core/misc.c
@ -20,6 +20,7 @@
|
||||
|
||||
#include "module.h"
|
||||
#include "misc.h"
|
||||
#include "commands.h"
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
# include <regex.h>
|
||||
@ -150,27 +151,13 @@ int find_substr(const char *list, const char *item)
|
||||
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);
|
||||
g_return_val_if_fail(array != NULL, -1);
|
||||
g_return_val_if_fail(item != NULL, -1);
|
||||
|
||||
index = 0;
|
||||
for (tmp = array; *tmp != NULL; tmp++, index++) {
|
||||
@ -279,14 +266,23 @@ void hash_save_key(char *key, void *value, GSList **list)
|
||||
*list = g_slist_append(*list, key);
|
||||
}
|
||||
|
||||
/* save all keys in hash table to linked list - you shouldn't remove any
|
||||
items while using this list, use g_slist_free() after you're done with it */
|
||||
GSList *hashtable_get_keys(GHashTable *hash)
|
||||
/* remove all the options from the optlist hash table that are valid for the
|
||||
* command cmd */
|
||||
GList *optlist_remove_known(const char *cmd, GHashTable *optlist)
|
||||
{
|
||||
GSList *list;
|
||||
GList *list, *tmp, *next;
|
||||
|
||||
list = g_hash_table_get_keys(optlist);
|
||||
if (cmd != NULL && list != NULL) {
|
||||
for (tmp = list; tmp != NULL; tmp = next) {
|
||||
char *option = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (command_have_option(cmd, option))
|
||||
list = g_list_remove(list, option);
|
||||
}
|
||||
}
|
||||
|
||||
list = NULL;
|
||||
g_hash_table_foreach(hash, (GHFunc) hash_save_key, &list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -389,62 +385,6 @@ char *stristr_full(const char *data, const char *key)
|
||||
return strstr_full_case(data, key, TRUE);
|
||||
}
|
||||
|
||||
int regexp_match(const char *str, const char *regexp)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
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;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create the directory and all it's parent directories */
|
||||
int mkpath(const char *path, int mode)
|
||||
{
|
||||
struct stat statbuf;
|
||||
const char *p;
|
||||
char *dir;
|
||||
|
||||
g_return_val_if_fail(path != NULL, -1);
|
||||
|
||||
p = g_path_skip_root((char *) path);
|
||||
if (p == NULL) {
|
||||
/* not a full path, maybe not what we wanted
|
||||
but continue anyway.. */
|
||||
p = path;
|
||||
}
|
||||
for (;;) {
|
||||
if (*p != G_DIR_SEPARATOR && *p != '\0') {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
dir = g_strndup(path, (int) (p-path));
|
||||
if (stat(dir, &statbuf) != 0) {
|
||||
if (mkdir(dir, mode) == -1)
|
||||
{
|
||||
g_free(dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
g_free(dir);
|
||||
|
||||
if (*p++ == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* convert ~/ to $HOME */
|
||||
char *convert_home(const char *path)
|
||||
{
|
||||
@ -471,22 +411,15 @@ int g_istr_cmp(gconstpointer v, gconstpointer v2)
|
||||
return g_ascii_strcasecmp((const char *) v, (const char *) v2);
|
||||
}
|
||||
|
||||
/* a char* hash function from ASU */
|
||||
unsigned int g_istr_hash(gconstpointer v)
|
||||
guint g_istr_hash(gconstpointer v)
|
||||
{
|
||||
const char *s = (const char *) v;
|
||||
unsigned int h = 0, g;
|
||||
const signed char *p;
|
||||
guint32 h = 5381;
|
||||
|
||||
while (*s != '\0') {
|
||||
h = (h << 4) + i_toupper(*s);
|
||||
if ((g = h & 0xf0000000UL)) {
|
||||
h = h ^ (g >> 24);
|
||||
h = h ^ g;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
for (p = v; *p != '\0'; p++)
|
||||
h = (h << 5) + h + g_ascii_toupper(*p);
|
||||
|
||||
return h /* % M */;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Find `mask' from `data', you can use * and ? wildcards. */
|
||||
@ -592,15 +525,11 @@ int dec2octal(int decimal)
|
||||
/* string -> uoff_t */
|
||||
uoff_t str_to_uofft(const char *str)
|
||||
{
|
||||
uoff_t ret;
|
||||
|
||||
ret = 0;
|
||||
while (*str != '\0') {
|
||||
ret = ret*10 + (*str - '0');
|
||||
str++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#ifdef UOFF_T_LONG_LONG
|
||||
return (uoff_t)strtoull(str, NULL, 10);
|
||||
#else
|
||||
return (uoff_t)strtoul(str, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* convert all low-ascii (<32) to ^<A..> combinations */
|
||||
@ -811,20 +740,6 @@ char *escape_string(const char *str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int strocpy(char *dest, const char *src, size_t dstsize)
|
||||
{
|
||||
if (dstsize == 0)
|
||||
return -1;
|
||||
|
||||
while (*src != '\0' && dstsize > 1) {
|
||||
*dest++ = *src++;
|
||||
dstsize--;
|
||||
}
|
||||
|
||||
*dest++ = '\0';
|
||||
return *src == '\0' ? 0 : -1;
|
||||
}
|
||||
|
||||
int nearest_power(int num)
|
||||
{
|
||||
int n = 1;
|
||||
|
@ -32,15 +32,8 @@ char *gslistptr_to_string(GSList *list, int offset, const char *delimiter);
|
||||
/* `list' contains char* */
|
||||
char *gslist_to_string(GSList *list, const char *delimiter);
|
||||
|
||||
/* save all keys in hash table to linked list - you shouldn't remove any
|
||||
items while using this list, use g_slist_free() after you're done with it */
|
||||
GSList *hashtable_get_keys(GHashTable *hash);
|
||||
GList *optlist_remove_known(const char *cmd, GHashTable *optlist);
|
||||
|
||||
/* easy way to check if regexp matches */
|
||||
int regexp_match(const char *str, const char *regexp);
|
||||
|
||||
/* Create the directory and all it's parent directories */
|
||||
int mkpath(const char *path, int mode);
|
||||
/* convert ~/ to $HOME */
|
||||
char *convert_home(const char *path);
|
||||
|
||||
@ -85,9 +78,6 @@ int parse_size(const char *size, int *bytes);
|
||||
Stop when `end_char' is found from string. */
|
||||
int is_numeric(const char *str, char end_char);
|
||||
|
||||
/* Like strlcpy(), but return -1 if buffer was overflown, 0 if not. */
|
||||
int strocpy(char *dest, const char *src, size_t dstsize);
|
||||
|
||||
/* strstr() with case-ignoring */
|
||||
char *stristr(const char *data, const char *key);
|
||||
|
||||
@ -107,8 +97,6 @@ char *show_lowascii(const char *str);
|
||||
/* replace all `from' chars in string to `to' chars. returns `str' */
|
||||
char *replace_chars(char *str, char from, char to);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -30,17 +30,11 @@
|
||||
union sockaddr_union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
# define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
|
||||
#define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
|
||||
sizeof(so.sin6) : sizeof(so.sin))
|
||||
#else
|
||||
# define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
|
||||
#endif
|
||||
|
||||
GIOChannel *g_io_channel_new(int handle)
|
||||
{
|
||||
@ -56,7 +50,7 @@ GIOChannel *g_io_channel_new(int handle)
|
||||
|
||||
IPADDR ip4_any = {
|
||||
AF_INET,
|
||||
#if defined(HAVE_IPV6) && defined(IN6ADDR_ANY_INIT)
|
||||
#if defined(IN6ADDR_ANY_INIT)
|
||||
IN6ADDR_ANY_INIT
|
||||
#else
|
||||
{ INADDR_ANY }
|
||||
@ -68,10 +62,8 @@ 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->ip, &ip2->ip, sizeof(ip1->ip)) == 0;
|
||||
#endif
|
||||
|
||||
return memcmp(&ip1->ip, &ip2->ip, 4) == 0;
|
||||
}
|
||||
@ -80,22 +72,16 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2)
|
||||
static void sin_set_ip(union sockaddr_union *so, const IPADDR *ip)
|
||||
{
|
||||
if (ip == NULL) {
|
||||
#ifdef HAVE_IPV6
|
||||
so->sin6.sin6_family = AF_INET6;
|
||||
so->sin6.sin6_addr = in6addr_any;
|
||||
#else
|
||||
so->sin.sin_family = AF_INET;
|
||||
so->sin.sin_addr.s_addr = INADDR_ANY;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
so->sin.sin_family = ip->family;
|
||||
#ifdef HAVE_IPV6
|
||||
|
||||
if (ip->family == AF_INET6)
|
||||
memcpy(&so->sin6.sin6_addr, &ip->ip, sizeof(ip->ip));
|
||||
else
|
||||
#endif
|
||||
memcpy(&so->sin.sin_addr, &ip->ip, 4);
|
||||
}
|
||||
|
||||
@ -103,31 +89,25 @@ 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->ip, &so->sin6.sin6_addr, sizeof(ip->ip));
|
||||
else
|
||||
#endif
|
||||
memcpy(&ip->ip, &so->sin.sin_addr, 4);
|
||||
}
|
||||
|
||||
static 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((unsigned short)port);
|
||||
else
|
||||
#endif
|
||||
so->sin.sin_port = htons((unsigned short)port);
|
||||
}
|
||||
|
||||
static 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);
|
||||
return ntohs((so->sin.sin_family == AF_INET6) ?
|
||||
so->sin6.sin6_port :
|
||||
so->sin.sin_port);
|
||||
}
|
||||
|
||||
/* Connect to socket */
|
||||
@ -272,7 +252,7 @@ GIOChannel *net_listen(IPADDR *my_ip, int *port)
|
||||
|
||||
/* create the socket */
|
||||
handle = socket(so.sin.sin_family, SOCK_STREAM, 0);
|
||||
#ifdef HAVE_IPV6
|
||||
|
||||
if (handle == -1 && (errno == EINVAL || errno == EAFNOSUPPORT)) {
|
||||
/* IPv6 is not supported by OS */
|
||||
so.sin.sin_family = AF_INET;
|
||||
@ -280,7 +260,7 @@ GIOChannel *net_listen(IPADDR *my_ip, int *port)
|
||||
|
||||
handle = socket(AF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (handle == -1)
|
||||
return NULL;
|
||||
|
||||
@ -399,23 +379,18 @@ int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port)
|
||||
Returns 0 = ok, others = error code for net_gethosterror() */
|
||||
int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
union sockaddr_union *so;
|
||||
struct addrinfo hints, *ai, *ailist;
|
||||
int ret, count_v4, count_v6, use_v4, use_v6;
|
||||
#else
|
||||
struct hostent *hp;
|
||||
int count;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail(addr != NULL, -1);
|
||||
|
||||
memset(ip4, 0, sizeof(IPADDR));
|
||||
memset(ip6, 0, sizeof(IPADDR));
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
|
||||
/* save error to host_error for later use */
|
||||
ret = getaddrinfo(addr, NULL, &hints, &ailist);
|
||||
@ -454,85 +429,40 @@ int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6)
|
||||
}
|
||||
freeaddrinfo(ailist);
|
||||
return 0;
|
||||
#else
|
||||
hp = gethostbyname(addr);
|
||||
if (hp == NULL)
|
||||
return h_errno;
|
||||
|
||||
/* count IPs */
|
||||
count = 0;
|
||||
while (hp->h_addr_list[count] != NULL)
|
||||
count++;
|
||||
|
||||
if (count == 0)
|
||||
return HOST_NOT_FOUND; /* shouldn't happen? */
|
||||
|
||||
/* if there are multiple addresses, return random one */
|
||||
ip4->family = AF_INET;
|
||||
memcpy(&ip4->ip, hp->h_addr_list[rand() % count], 4);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get name for host, *name should be g_free()'d unless it's NULL.
|
||||
Return values are the same as with net_gethostbyname() */
|
||||
int net_gethostbyaddr(IPADDR *ip, char **name)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
union sockaddr_union so;
|
||||
int host_error;
|
||||
char hostname[NI_MAXHOST];
|
||||
#else
|
||||
struct hostent *hp;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail(ip != NULL, -1);
|
||||
g_return_val_if_fail(name != NULL, -1);
|
||||
|
||||
*name = NULL;
|
||||
#ifdef HAVE_IPV6
|
||||
|
||||
memset(&so, 0, sizeof(so));
|
||||
sin_set_ip(&so, ip);
|
||||
|
||||
/* save error to host_error for later use */
|
||||
host_error = getnameinfo((struct sockaddr *) &so, sizeof(so),
|
||||
hostname, sizeof(hostname), NULL, 0, 0);
|
||||
host_error = getnameinfo((struct sockaddr *)&so, sizeof(so),
|
||||
hostname, sizeof(hostname),
|
||||
NULL, 0,
|
||||
NI_NAMEREQD);
|
||||
if (host_error != 0)
|
||||
return host_error;
|
||||
|
||||
*name = g_strdup(hostname);
|
||||
#else
|
||||
if (ip->family != AF_INET) return -1;
|
||||
hp = gethostbyaddr((const char *) &ip->ip, 4, AF_INET);
|
||||
if (hp == NULL) return -1;
|
||||
|
||||
*name = g_strdup(hp->h_name);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_ip2host(IPADDR *ip, char *host)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (!inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN))
|
||||
return -1;
|
||||
#else
|
||||
unsigned long ip4;
|
||||
|
||||
if (ip->family != AF_INET) {
|
||||
strcpy(host, "0.0.0.0");
|
||||
} else {
|
||||
ip4 = ntohl(ip->ip.s_addr);
|
||||
g_snprintf(host, MAX_IP_LEN, "%lu.%lu.%lu.%lu",
|
||||
(ip4 & 0xff000000UL) >> 24,
|
||||
(ip4 & 0x00ff0000) >> 16,
|
||||
(ip4 & 0x0000ff00) >> 8,
|
||||
(ip4 & 0x000000ff));
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
return inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN) ? 0 : -1;
|
||||
}
|
||||
|
||||
int net_host2ip(const char *host, IPADDR *ip)
|
||||
@ -542,12 +472,8 @@ int net_host2ip(const char *host, IPADDR *ip)
|
||||
if (strchr(host, ':') != NULL) {
|
||||
/* IPv6 */
|
||||
ip->family = AF_INET6;
|
||||
#ifdef HAVE_IPV6
|
||||
if (inet_pton(AF_INET6, host, &ip->ip) == 0)
|
||||
return -1;
|
||||
#else
|
||||
ip->ip.s_addr = 0;
|
||||
#endif
|
||||
} else {
|
||||
/* IPv4 */
|
||||
ip->family = AF_INET;
|
||||
@ -582,7 +508,6 @@ int net_geterror(GIOChannel *handle)
|
||||
/* get error of net_gethostname() */
|
||||
const char *net_gethosterror(int error)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
g_return_val_if_fail(error != 0, NULL);
|
||||
|
||||
if (error == EAI_SYSTEM) {
|
||||
@ -590,36 +515,17 @@ const char *net_gethosterror(int error)
|
||||
} else {
|
||||
return gai_strerror(error);
|
||||
}
|
||||
#else
|
||||
switch (error) {
|
||||
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
|
||||
}
|
||||
|
||||
/* return TRUE if host lookup failed because it didn't exist (ie. not
|
||||
some error with name server) */
|
||||
int net_hosterror_notfound(int error)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
#ifdef EAI_NODATA /* NODATA is deprecated */
|
||||
return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
|
||||
#else
|
||||
return error != 1 && (error == EAI_NONAME);
|
||||
#endif
|
||||
#else
|
||||
return error == HOST_NOT_FOUND || error == NO_ADDRESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get name of TCP service */
|
||||
|
@ -21,19 +21,11 @@
|
||||
|
||||
struct _IPADDR {
|
||||
unsigned short family;
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr ip;
|
||||
#else
|
||||
struct in_addr ip;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* maxmimum string length of IP address */
|
||||
#ifdef HAVE_IPV6
|
||||
# define MAX_IP_LEN INET6_ADDRSTRLEN
|
||||
#else
|
||||
# define MAX_IP_LEN 20
|
||||
#endif
|
||||
#define MAX_IP_LEN INET6_ADDRSTRLEN
|
||||
|
||||
#define IPADDR_IS_V6(ip) ((ip)->family != AF_INET)
|
||||
|
||||
@ -45,7 +37,7 @@ GIOChannel *g_io_channel_new(int handle);
|
||||
int net_ip_compare(IPADDR *ip1, IPADDR *ip2);
|
||||
|
||||
/* Connect to socket */
|
||||
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
|
||||
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) G_GNUC_DEPRECATED;
|
||||
/* Connect to socket with ip address and SSL*/
|
||||
GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server);
|
||||
int irssi_ssl_handshake(GIOChannel *handle);
|
||||
|
@ -150,13 +150,18 @@ void rawlog_save(RAWLOG_REC *rawlog, const char *fname)
|
||||
int f;
|
||||
|
||||
dir = g_path_get_dirname(fname);
|
||||
mkpath(dir, log_dir_create_mode);
|
||||
g_mkdir_with_parents(dir, log_dir_create_mode);
|
||||
g_free(dir);
|
||||
|
||||
path = convert_home(fname);
|
||||
f = open(path, O_WRONLY | O_APPEND | O_CREAT, log_file_create_mode);
|
||||
g_free(path);
|
||||
|
||||
if (f < 0) {
|
||||
g_warning("rawlog open() failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
rawlog_dump(rawlog, f);
|
||||
close(f);
|
||||
}
|
||||
|
@ -190,6 +190,7 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
|
||||
dest->away_reason = g_strdup(src->away_reason);
|
||||
dest->no_autojoin_channels = src->no_autojoin_channels;
|
||||
dest->no_autosendcmd = src->no_autosendcmd;
|
||||
dest->unix_socket = src->unix_socket;
|
||||
|
||||
dest->use_ssl = src->use_ssl;
|
||||
dest->ssl_cert = g_strdup(src->ssl_cert);
|
||||
|
@ -321,7 +321,7 @@ server_create_conn(int chat_type, const char *dest, int port,
|
||||
chatrec = chatnet_find(dest);
|
||||
if (chatrec != NULL) {
|
||||
rec = create_chatnet_conn(chatrec->name, port, password, nick);
|
||||
if (rec != NULL)
|
||||
/* If rec is NULL the chatnet has no url to connect to */
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
@ -684,21 +684,11 @@ SERVER_REC *cmd_options_get_server(const char *cmd,
|
||||
SERVER_REC *defserver)
|
||||
{
|
||||
SERVER_REC *server;
|
||||
GSList *list, *tmp, *next;
|
||||
GList *list;
|
||||
|
||||
/* get all the options, then remove the known ones. there should
|
||||
be only one left - the server tag. */
|
||||
list = hashtable_get_keys(optlist);
|
||||
if (cmd != NULL) {
|
||||
for (tmp = list; tmp != NULL; tmp = next) {
|
||||
char *option = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (command_have_option(cmd, option))
|
||||
list = g_slist_remove(list, option);
|
||||
}
|
||||
}
|
||||
|
||||
list = optlist_remove_known(cmd, optlist);
|
||||
if (list == NULL)
|
||||
return defserver;
|
||||
|
||||
@ -713,7 +703,7 @@ SERVER_REC *cmd_options_get_server(const char *cmd,
|
||||
server = NULL;
|
||||
}
|
||||
|
||||
g_slist_free(list);
|
||||
g_list_free(list);
|
||||
return server;
|
||||
}
|
||||
|
||||
|
@ -148,11 +148,36 @@ int settings_get_size(const char *key)
|
||||
return str == NULL ? 0 : bytes;
|
||||
}
|
||||
|
||||
int settings_get_choice(const char *key)
|
||||
{
|
||||
SETTINGS_REC *rec;
|
||||
CONFIG_NODE *node;
|
||||
char *str;
|
||||
int index;
|
||||
|
||||
rec = settings_get(key, SETTING_TYPE_CHOICE);
|
||||
if (rec == NULL) return -1;
|
||||
|
||||
node = iconfig_node_traverse("settings", FALSE);
|
||||
node = node == NULL ? NULL : iconfig_node_section(node, rec->module, -1);
|
||||
|
||||
str = node == NULL ? rec->default_value.v_string :
|
||||
config_node_get_str(node, key, rec->default_value.v_string);
|
||||
|
||||
if (str == NULL || (index = strarray_find(rec->choices, str)) < 0)
|
||||
return rec->default_value.v_int;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
char *settings_get_print(SETTINGS_REC *rec)
|
||||
{
|
||||
char *value = NULL;
|
||||
|
||||
switch(rec->type) {
|
||||
case SETTING_TYPE_CHOICE:
|
||||
value = g_strdup(rec->choices[settings_get_choice(rec->key)]);
|
||||
break;
|
||||
case SETTING_TYPE_BOOLEAN:
|
||||
value = g_strdup(settings_get_bool(rec->key) ? "ON" : "OFF");
|
||||
break;
|
||||
@ -172,13 +197,31 @@ char *settings_get_print(SETTINGS_REC *rec)
|
||||
|
||||
static void settings_add(const char *module, const char *section,
|
||||
const char *key, SettingType type,
|
||||
const SettingValue *default_value)
|
||||
const SettingValue *default_value,
|
||||
const char *choices)
|
||||
{
|
||||
SETTINGS_REC *rec;
|
||||
char **choices_vec = NULL;
|
||||
|
||||
g_return_if_fail(key != NULL);
|
||||
g_return_if_fail(section != NULL);
|
||||
|
||||
if (type == SETTING_TYPE_CHOICE) {
|
||||
if (choices == NULL) {
|
||||
g_warning("Trying to add setting '%s' with no choices.", key);
|
||||
return;
|
||||
}
|
||||
|
||||
choices_vec = g_strsplit(choices, ";", -1);
|
||||
|
||||
/* validate the default value */
|
||||
if (default_value->v_int < 0 || default_value->v_int >= g_strv_length(choices_vec)) {
|
||||
g_warning("Trying to add setting '%s' with an invalid default value.", key);
|
||||
g_strfreev(choices_vec);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rec = g_hash_table_lookup(settings, key);
|
||||
if (rec != NULL) {
|
||||
/* Already exists, make sure it's correct type */
|
||||
@ -197,6 +240,7 @@ static void settings_add(const char *module, const char *section,
|
||||
rec->type = type;
|
||||
|
||||
rec->default_value = *default_value;
|
||||
rec->choices = choices_vec;
|
||||
g_hash_table_insert(settings, rec->key, rec);
|
||||
}
|
||||
}
|
||||
@ -208,7 +252,17 @@ void settings_add_str_module(const char *module, const char *section,
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_string = g_strdup(def);
|
||||
settings_add(module, section, key, SETTING_TYPE_STRING, &default_value);
|
||||
settings_add(module, section, key, SETTING_TYPE_STRING, &default_value, NULL);
|
||||
}
|
||||
|
||||
void settings_add_choice_module(const char *module, const char *section,
|
||||
const char *key, int def, const char *choices)
|
||||
{
|
||||
SettingValue default_value;
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_int = def;
|
||||
settings_add(module, section, key, SETTING_TYPE_CHOICE, &default_value, choices);
|
||||
}
|
||||
|
||||
void settings_add_int_module(const char *module, const char *section,
|
||||
@ -218,7 +272,7 @@ void settings_add_int_module(const char *module, const char *section,
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_int = def;
|
||||
settings_add(module, section, key, SETTING_TYPE_INT, &default_value);
|
||||
settings_add(module, section, key, SETTING_TYPE_INT, &default_value, NULL);
|
||||
}
|
||||
|
||||
void settings_add_bool_module(const char *module, const char *section,
|
||||
@ -228,8 +282,7 @@ void settings_add_bool_module(const char *module, const char *section,
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_bool = def;
|
||||
settings_add(module, section, key, SETTING_TYPE_BOOLEAN,
|
||||
&default_value);
|
||||
settings_add(module, section, key, SETTING_TYPE_BOOLEAN, &default_value, NULL);
|
||||
}
|
||||
|
||||
void settings_add_time_module(const char *module, const char *section,
|
||||
@ -239,7 +292,7 @@ void settings_add_time_module(const char *module, const char *section,
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_string = g_strdup(def);
|
||||
settings_add(module, section, key, SETTING_TYPE_TIME, &default_value);
|
||||
settings_add(module, section, key, SETTING_TYPE_TIME, &default_value, NULL);
|
||||
}
|
||||
|
||||
void settings_add_level_module(const char *module, const char *section,
|
||||
@ -249,7 +302,7 @@ void settings_add_level_module(const char *module, const char *section,
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_string = g_strdup(def);
|
||||
settings_add(module, section, key, SETTING_TYPE_LEVEL, &default_value);
|
||||
settings_add(module, section, key, SETTING_TYPE_LEVEL, &default_value, NULL);
|
||||
}
|
||||
|
||||
void settings_add_size_module(const char *module, const char *section,
|
||||
@ -259,14 +312,16 @@ void settings_add_size_module(const char *module, const char *section,
|
||||
|
||||
memset(&default_value, 0, sizeof(default_value));
|
||||
default_value.v_string = g_strdup(def);
|
||||
settings_add(module, section, key, SETTING_TYPE_SIZE, &default_value);
|
||||
settings_add(module, section, key, SETTING_TYPE_SIZE, &default_value, NULL);
|
||||
}
|
||||
|
||||
static void settings_destroy(SETTINGS_REC *rec)
|
||||
{
|
||||
if (rec->type != SETTING_TYPE_INT &&
|
||||
rec->type != SETTING_TYPE_BOOLEAN)
|
||||
rec->type != SETTING_TYPE_BOOLEAN &&
|
||||
rec->type != SETTING_TYPE_CHOICE)
|
||||
g_free(rec->default_value.v_string);
|
||||
g_strfreev(rec->choices);
|
||||
g_free(rec->module);
|
||||
g_free(rec->section);
|
||||
g_free(rec->key);
|
||||
@ -328,6 +383,20 @@ static CONFIG_NODE *settings_get_node(const char *key)
|
||||
return iconfig_node_section(node, rec->module, NODE_TYPE_BLOCK);
|
||||
}
|
||||
|
||||
gboolean settings_set_choice(const char *key, const char *value)
|
||||
{
|
||||
SETTINGS_REC *rec;
|
||||
|
||||
rec = settings_get_record(key);
|
||||
|
||||
if (rec != NULL && strarray_find(rec->choices, value) < 0)
|
||||
return FALSE;
|
||||
|
||||
settings_set_str(key, value);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void settings_set_str(const char *key, const char *value)
|
||||
{
|
||||
iconfig_node_set_str(settings_get_node(key), key, value);
|
||||
@ -343,7 +412,7 @@ void settings_set_bool(const char *key, int value)
|
||||
iconfig_node_set_bool(settings_get_node(key), key, value);
|
||||
}
|
||||
|
||||
int settings_set_time(const char *key, const char *value)
|
||||
gboolean settings_set_time(const char *key, const char *value)
|
||||
{
|
||||
int msecs;
|
||||
|
||||
@ -354,7 +423,7 @@ int settings_set_time(const char *key, const char *value)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int settings_set_level(const char *key, const char *value)
|
||||
gboolean settings_set_level(const char *key, const char *value)
|
||||
{
|
||||
int iserror;
|
||||
|
||||
@ -366,7 +435,7 @@ int settings_set_level(const char *key, const char *value)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int settings_set_size(const char *key, const char *value)
|
||||
gboolean settings_set_size(const char *key, const char *value)
|
||||
{
|
||||
int size;
|
||||
|
||||
@ -683,7 +752,7 @@ static void init_configfile(void)
|
||||
|
||||
if (stat(get_irssi_dir(), &statbuf) != 0) {
|
||||
/* ~/.irssi not found, create it. */
|
||||
if (mkpath(get_irssi_dir(), 0700) != 0) {
|
||||
if (g_mkdir_with_parents(get_irssi_dir(), 0700) != 0) {
|
||||
g_error("Couldn't create %s directory", get_irssi_dir());
|
||||
}
|
||||
} else if (!S_ISDIR(statbuf.st_mode)) {
|
||||
|
@ -8,6 +8,7 @@ typedef enum {
|
||||
SETTING_TYPE_TIME,
|
||||
SETTING_TYPE_LEVEL,
|
||||
SETTING_TYPE_SIZE,
|
||||
SETTING_TYPE_CHOICE,
|
||||
SETTING_TYPE_ANY
|
||||
} SettingType;
|
||||
|
||||
@ -26,6 +27,7 @@ typedef struct {
|
||||
|
||||
SettingType type;
|
||||
SettingValue default_value;
|
||||
char **choices;
|
||||
} SETTINGS_REC;
|
||||
|
||||
/* macros for handling the default Irssi configuration */
|
||||
@ -58,6 +60,7 @@ int settings_get_bool(const char *key);
|
||||
int settings_get_time(const char *key); /* as milliseconds */
|
||||
int settings_get_level(const char *key);
|
||||
int settings_get_size(const char *key); /* as bytes */
|
||||
int settings_get_choice(const char *key);
|
||||
char *settings_get_print(SETTINGS_REC *rec);
|
||||
|
||||
/* Functions to add/remove settings */
|
||||
@ -73,6 +76,8 @@ void settings_add_level_module(const char *module, const char *section,
|
||||
const char *key, const char *def);
|
||||
void settings_add_size_module(const char *module, const char *section,
|
||||
const char *key, const char *def);
|
||||
void settings_add_choice_module(const char *module, const char *section,
|
||||
const char *key, int def, const char *choices);
|
||||
void settings_remove(const char *key);
|
||||
void settings_remove_module(const char *module);
|
||||
|
||||
@ -88,13 +93,16 @@ void settings_remove_module(const char *module);
|
||||
settings_add_level_module(MODULE_NAME, section, key, def)
|
||||
#define settings_add_size(section, key, def) \
|
||||
settings_add_size_module(MODULE_NAME, section, key, def)
|
||||
#define settings_add_choice(section, key, def, choices) \
|
||||
settings_add_choice_module(MODULE_NAME, section, key, def, choices)
|
||||
|
||||
void settings_set_str(const char *key, const char *value);
|
||||
void settings_set_int(const char *key, int value);
|
||||
void settings_set_bool(const char *key, int value);
|
||||
int settings_set_time(const char *key, const char *value);
|
||||
int settings_set_level(const char *key, const char *value);
|
||||
int settings_set_size(const char *key, const char *value);
|
||||
gboolean settings_set_time(const char *key, const char *value);
|
||||
gboolean settings_set_level(const char *key, const char *value);
|
||||
gboolean settings_set_size(const char *key, const char *value);
|
||||
gboolean settings_set_choice(const char *key, const char *value);
|
||||
|
||||
/* Get the type (SETTING_TYPE_xxx) of `key' */
|
||||
SettingType settings_get_type(const char *key);
|
||||
|
@ -25,10 +25,7 @@
|
||||
#include "settings.h"
|
||||
#include "servers.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define ALIGN_RIGHT 0x01
|
||||
#define ALIGN_CUT 0x02
|
||||
#define ALIGN_PAD 0x04
|
||||
#include "utf8.h"
|
||||
|
||||
#define isvarchar(c) \
|
||||
(i_isalnum(c) || (c) == '_')
|
||||
@ -47,7 +44,7 @@ static char *get_argument(char **cmd, char **arglist)
|
||||
arg = 0;
|
||||
max = -1;
|
||||
|
||||
argcount = arglist == NULL ? 0 : strarray_length(arglist);
|
||||
argcount = arglist == NULL ? 0 : g_strv_length(arglist);
|
||||
|
||||
if (**cmd == '*') {
|
||||
/* get all arguments */
|
||||
@ -316,22 +313,28 @@ static int get_alignment_args(char **data, int *align, int *flags, char *pad)
|
||||
}
|
||||
|
||||
/* return the aligned text */
|
||||
static char *get_alignment(const char *text, int align, int flags, char pad)
|
||||
char *get_alignment(const char *text, int align, int flags, char pad)
|
||||
{
|
||||
GString *str;
|
||||
char *ret;
|
||||
int policy;
|
||||
unsigned int cut_bytes;
|
||||
|
||||
g_return_val_if_fail(text != NULL, NULL);
|
||||
|
||||
policy = string_policy(text);
|
||||
|
||||
str = g_string_new(text);
|
||||
|
||||
/* cut */
|
||||
if ((flags & ALIGN_CUT) && align > 0 && str->len > align)
|
||||
g_string_truncate(str, align);
|
||||
if ((flags & ALIGN_CUT) && align > 0 && string_width(text, policy) > align) {
|
||||
string_chars_for_width(text, policy, align, &cut_bytes);
|
||||
g_string_truncate(str, cut_bytes);
|
||||
}
|
||||
|
||||
/* add pad characters */
|
||||
if (flags & ALIGN_PAD) {
|
||||
while (str->len < align) {
|
||||
while (string_width(str->str, policy) < align) {
|
||||
if (flags & ALIGN_RIGHT)
|
||||
g_string_prepend_c(str, pad);
|
||||
else
|
||||
|
@ -9,9 +9,16 @@
|
||||
#define PARSE_FLAG_ESCAPE_THEME 0x08 /* if any arguments/variables contain { or } chars, escape them with % */
|
||||
#define PARSE_FLAG_ONLY_ARGS 0x10 /* expand only arguments ($0 $1 etc.) but no other $variables */
|
||||
|
||||
#define ALIGN_RIGHT 0x01
|
||||
#define ALIGN_CUT 0x02
|
||||
#define ALIGN_PAD 0x04
|
||||
|
||||
typedef char* (*SPECIAL_HISTORY_FUNC)
|
||||
(const char *text, void *item, int *free_ret);
|
||||
|
||||
/* Cut and/or pad text so it takes exactly "align" characters on the screen */
|
||||
char *get_alignment(const char *text, int align, int flags, char pad);
|
||||
|
||||
/* Parse and expand text after '$' character. return value has to be
|
||||
g_free()'d if `free_ret' is TRUE. */
|
||||
char *parse_special(char **cmd, SERVER_REC *server, void *item,
|
||||
|
135
src/core/utf8.c
Normal file
135
src/core/utf8.c
Normal file
@ -0,0 +1,135 @@
|
||||
/* utf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 2002 Timo Sirainen
|
||||
*
|
||||
* Based on GLib code by
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "utf8.h"
|
||||
#include "module.h"
|
||||
|
||||
/* Provide is_utf8(): */
|
||||
#include "recode.h"
|
||||
|
||||
int string_advance(char const **str, int policy)
|
||||
{
|
||||
if (policy == TREAT_STRING_AS_UTF8) {
|
||||
gunichar c;
|
||||
|
||||
c = g_utf8_get_char(*str);
|
||||
*str = g_utf8_next_char(*str);
|
||||
|
||||
return unichar_isprint(c) ? mk_wcwidth(c) : 1;
|
||||
} else {
|
||||
/* Assume TREAT_STRING_AS_BYTES: */
|
||||
*str += 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int string_policy(const char *str)
|
||||
{
|
||||
if (is_utf8()) {
|
||||
if (str == NULL || g_utf8_validate(str, -1, NULL)) {
|
||||
/* No string provided or valid UTF-8 string: treat as UTF-8: */
|
||||
return TREAT_STRING_AS_UTF8;
|
||||
}
|
||||
}
|
||||
return TREAT_STRING_AS_BYTES;
|
||||
}
|
||||
|
||||
int string_length(const char *str, int policy)
|
||||
{
|
||||
g_return_val_if_fail(str != NULL, 0);
|
||||
|
||||
if (policy == -1) {
|
||||
policy = string_policy(str);
|
||||
}
|
||||
|
||||
if (policy == TREAT_STRING_AS_UTF8) {
|
||||
return g_utf8_strlen(str, -1);
|
||||
}
|
||||
else {
|
||||
/* Assume TREAT_STRING_AS_BYTES: */
|
||||
return strlen(str);
|
||||
}
|
||||
}
|
||||
|
||||
int string_width(const char *str, int policy)
|
||||
{
|
||||
int len;
|
||||
|
||||
g_return_val_if_fail(str != NULL, 0);
|
||||
|
||||
if (policy == -1) {
|
||||
policy = string_policy(str);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
while (*str != '\0') {
|
||||
len += string_advance(&str, policy);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int string_chars_for_width(const char *str, int policy, unsigned int n, unsigned int *bytes)
|
||||
{
|
||||
const char *c, *previous_c;
|
||||
int str_width, char_width, char_count;
|
||||
|
||||
g_return_val_if_fail(str != NULL, -1);
|
||||
|
||||
/* Handle the dummy case where n is 0: */
|
||||
if (n == 0) {
|
||||
if (bytes != NULL) {
|
||||
*bytes = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (policy == -1) {
|
||||
policy = string_policy(str);
|
||||
}
|
||||
|
||||
/* Iterate over characters until we reach n: */
|
||||
char_count = 0;
|
||||
str_width = 0;
|
||||
c = str;
|
||||
while (*c != '\0') {
|
||||
previous_c = c;
|
||||
char_width = string_advance(&c, policy);
|
||||
if (str_width + char_width > n) {
|
||||
/* We stepped beyond n, get one step back and stop there: */
|
||||
c = previous_c;
|
||||
break;
|
||||
}
|
||||
++ char_count;
|
||||
str_width += char_width;
|
||||
}
|
||||
/* At this point, we know that char_count characters reach str_width
|
||||
* columns, which is less than or equal to n. */
|
||||
|
||||
/* Optionally provide the equivalent amount of bytes: */
|
||||
if (bytes != NULL) {
|
||||
*bytes = c - str;
|
||||
}
|
||||
return char_count;
|
||||
}
|
56
src/core/utf8.h
Normal file
56
src/core/utf8.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef __UTF8_H
|
||||
#define __UTF8_H
|
||||
|
||||
/* XXX I didn't check the encoding range of big5+. This is standard big5. */
|
||||
#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */
|
||||
#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */
|
||||
#define is_big5_lo(lo) ((is_big5_los(lo) || is_big5_lox(lo)))
|
||||
#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
|
||||
#define is_big5(hi,lo) (is_big5_hi(hi) && is_big5_lo(lo))
|
||||
|
||||
#include <glib.h>
|
||||
typedef guint32 unichar;
|
||||
|
||||
/* Returns width for character (0-2). */
|
||||
int mk_wcwidth(unichar c);
|
||||
|
||||
/* Advance the str pointer one character further; return the number of columns
|
||||
* occupied by the skipped character.
|
||||
*/
|
||||
int string_advance(char const **str, int policy);
|
||||
|
||||
/* TREAT_STRING_AS_BYTES means strings are to be treated using strncpy,
|
||||
* strnlen, etc.
|
||||
* TREAT_STRING_AS_UTF8 means strings are to be treated using g_utf8_*
|
||||
* functions.
|
||||
*/
|
||||
enum str_policy {
|
||||
TREAT_STRING_AS_BYTES,
|
||||
TREAT_STRING_AS_UTF8
|
||||
};
|
||||
|
||||
/* Return how the str string ought to be treated: TREAT_STRING_AS_UTF8 if the
|
||||
* terminal handles UTF-8 and if the string appears to be a valid UTF-8 string;
|
||||
* TREAT_STRING_AS_BYTES otherwise.
|
||||
*/
|
||||
int string_policy(const char *str);
|
||||
|
||||
/* Return the length of the str string according to the given policy; if policy
|
||||
* is -1, this function will call string_policy().
|
||||
*/
|
||||
int string_length(const char *str, int policy);
|
||||
/* Return the screen width of the str string according to the given policy; if
|
||||
* policy is -1, this function will call string_policy().
|
||||
*/
|
||||
int string_width(const char *str, int policy);
|
||||
|
||||
/* Return the amount of characters from str it takes to reach n columns, or -1 if
|
||||
* str is NULL. Optionally return the equivalent amount of bytes.
|
||||
* If policy is -1, this function will call string_policy().
|
||||
*/
|
||||
int string_chars_for_width(const char *str, int policy, unsigned int n, unsigned int *bytes);
|
||||
|
||||
#define unichar_isprint(c) (((c) & ~0x80) >= 32)
|
||||
#define is_utf8_leading(c) (((c) & 0xc0) != 0x80)
|
||||
|
||||
#endif
|
@ -59,7 +59,7 @@
|
||||
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "utf8.h"
|
||||
|
||||
struct interval {
|
||||
int first;
|
@ -24,8 +24,6 @@ libfe_common_core_a_SOURCES = \
|
||||
fe-queries.c \
|
||||
fe-server.c \
|
||||
fe-settings.c \
|
||||
utf8.c \
|
||||
wcwidth.c \
|
||||
formats.c \
|
||||
hilight-text.c \
|
||||
keyboard.c \
|
||||
@ -62,6 +60,3 @@ pkginc_fe_common_core_HEADERS = \
|
||||
window-items.h \
|
||||
windows-layout.h \
|
||||
fe-windows.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
utf8.h
|
||||
|
@ -38,11 +38,18 @@
|
||||
#include "chat-completion.h"
|
||||
#include "window-items.h"
|
||||
|
||||
enum {
|
||||
COMPLETE_MCASE_NEVER = 0,
|
||||
COMPLETE_MCASE_ALWAYS,
|
||||
COMPLETE_MCASE_AUTO,
|
||||
};
|
||||
|
||||
static int keep_privates_count, keep_publics_count;
|
||||
static int completion_lowercase;
|
||||
static char *completion_char, *cmdchars;
|
||||
static GSList *global_lastmsgs;
|
||||
static int completion_auto, completion_strict;
|
||||
static int completion_match_case;
|
||||
|
||||
#define SERVER_LAST_MSG_ADD(server, nick) \
|
||||
last_msg_add(&((MODULE_SERVER_REC *) MODULE_DATA(server))->lastmsgs, \
|
||||
@ -52,6 +59,18 @@ static int completion_auto, completion_strict;
|
||||
last_msg_add(&((MODULE_CHANNEL_REC *) MODULE_DATA(channel))->lastmsgs, \
|
||||
nick, own, keep_publics_count)
|
||||
|
||||
static gboolean contains_uppercase(const char *s1)
|
||||
{
|
||||
const char *ch;
|
||||
|
||||
for (ch = s1; *ch != '\0'; ch++) {
|
||||
if (g_ascii_isupper(*ch))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static LAST_MSG_REC *last_msg_find(GSList *list, const char *nick)
|
||||
{
|
||||
while (list != NULL) {
|
||||
@ -336,7 +355,8 @@ GList *completion_msg(SERVER_REC *win_server,
|
||||
}
|
||||
|
||||
static void complete_from_nicklist(GList **outlist, CHANNEL_REC *channel,
|
||||
const char *nick, const char *suffix)
|
||||
const char *nick, const char *suffix,
|
||||
const int match_case)
|
||||
{
|
||||
MODULE_CHANNEL_REC *mchannel;
|
||||
GSList *tmp;
|
||||
@ -352,8 +372,10 @@ static void complete_from_nicklist(GList **outlist, CHANNEL_REC *channel,
|
||||
for (tmp = mchannel->lastmsgs; tmp != NULL; tmp = tmp->next) {
|
||||
LAST_MSG_REC *rec = tmp->data;
|
||||
|
||||
if (g_ascii_strncasecmp(rec->nick, nick, len) == 0 &&
|
||||
glist_find_icase_string(*outlist, rec->nick) == NULL) {
|
||||
if ((match_case? strncmp(rec->nick, nick, len)
|
||||
: g_ascii_strncasecmp(rec->nick, nick, len)) == 0 &&
|
||||
(match_case? glist_find_string(*outlist, rec->nick)
|
||||
: glist_find_icase_string(*outlist, rec->nick)) == NULL) {
|
||||
str = g_strconcat(rec->nick, suffix, NULL);
|
||||
if (completion_lowercase) ascii_strdown(str);
|
||||
if (rec->own)
|
||||
@ -368,7 +390,8 @@ static void complete_from_nicklist(GList **outlist, CHANNEL_REC *channel,
|
||||
|
||||
static GList *completion_nicks_nonstrict(CHANNEL_REC *channel,
|
||||
const char *nick,
|
||||
const char *suffix)
|
||||
const char *suffix,
|
||||
const int match_case)
|
||||
{
|
||||
GSList *nicks, *tmp;
|
||||
GList *list;
|
||||
@ -404,7 +427,8 @@ static GList *completion_nicks_nonstrict(CHANNEL_REC *channel,
|
||||
*out = '\0';
|
||||
|
||||
/* add to list if 'cleaned' nick matches */
|
||||
if (g_ascii_strncasecmp(str, nick, len) == 0) {
|
||||
if ((match_case? strncmp(str, nick, len)
|
||||
: g_ascii_strncasecmp(str, nick, len)) == 0) {
|
||||
tnick = g_strconcat(rec->nick, suffix, NULL);
|
||||
if (completion_lowercase)
|
||||
ascii_strdown(tnick);
|
||||
@ -428,7 +452,7 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick,
|
||||
GSList *nicks, *tmp;
|
||||
GList *list;
|
||||
char *str;
|
||||
int len;
|
||||
int len, match_case;
|
||||
|
||||
g_return_val_if_fail(channel != NULL, NULL);
|
||||
g_return_val_if_fail(nick != NULL, NULL);
|
||||
@ -437,9 +461,12 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick,
|
||||
if (suffix != NULL && *suffix == '\0')
|
||||
suffix = NULL;
|
||||
|
||||
match_case = completion_match_case == COMPLETE_MCASE_ALWAYS ||
|
||||
(completion_match_case == COMPLETE_MCASE_AUTO && contains_uppercase(nick));
|
||||
|
||||
/* put first the nicks who have recently said something */
|
||||
list = NULL;
|
||||
complete_from_nicklist(&list, channel, nick, suffix);
|
||||
complete_from_nicklist(&list, channel, nick, suffix, match_case);
|
||||
|
||||
/* and add the rest of the nicks too */
|
||||
len = strlen(nick);
|
||||
@ -447,7 +474,8 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick,
|
||||
for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
|
||||
NICK_REC *rec = tmp->data;
|
||||
|
||||
if (g_ascii_strncasecmp(rec->nick, nick, len) == 0 &&
|
||||
if ((match_case? strncmp(rec->nick, nick, len)
|
||||
: g_ascii_strncasecmp(rec->nick, nick, len)) == 0 &&
|
||||
rec != channel->ownnick) {
|
||||
str = g_strconcat(rec->nick, suffix, NULL);
|
||||
if (completion_lowercase)
|
||||
@ -463,7 +491,7 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick,
|
||||
/* remove non alphanum chars from nick and search again in case
|
||||
list is still NULL ("foo<tab>" would match "_foo_" f.e.) */
|
||||
if (!completion_strict)
|
||||
list = g_list_concat(list, completion_nicks_nonstrict(channel, nick, suffix));
|
||||
list = g_list_concat(list, completion_nicks_nonstrict(channel, nick, suffix, match_case));
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -1130,6 +1158,8 @@ static void read_settings(void)
|
||||
completion_auto = settings_get_bool("completion_auto");
|
||||
completion_strict = settings_get_bool("completion_strict");
|
||||
|
||||
completion_match_case = settings_get_choice("completion_nicks_match_case");
|
||||
|
||||
g_free_not_null(completion_char);
|
||||
completion_char = g_strdup(settings_get_str("completion_char"));
|
||||
|
||||
@ -1150,6 +1180,7 @@ void chat_completion_init(void)
|
||||
settings_add_int("completion", "completion_keep_privates", 10);
|
||||
settings_add_bool("completion", "completion_nicks_lowercase", FALSE);
|
||||
settings_add_bool("completion", "completion_strict", FALSE);
|
||||
settings_add_choice("completion", "completion_nicks_match_case", COMPLETE_MCASE_AUTO, "never;always;auto");
|
||||
|
||||
settings_add_bool("lookandfeel", "expand_escapes", FALSE);
|
||||
|
||||
|
@ -37,8 +37,11 @@ static int last_want_space, last_line_pos;
|
||||
#define isseparator_notspace(c) \
|
||||
((c) == ',')
|
||||
|
||||
#define isseparator_space(c) \
|
||||
((c) == ' ')
|
||||
|
||||
#define isseparator(c) \
|
||||
((c) == ' ' || isseparator_notspace(c))
|
||||
(isseparator_space(c) || isseparator_notspace(c))
|
||||
|
||||
void chat_completion_init(void);
|
||||
void chat_completion_deinit(void);
|
||||
@ -153,20 +156,23 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
|
||||
word = NULL;
|
||||
linestart = NULL;
|
||||
} else {
|
||||
char* old_wordstart;
|
||||
|
||||
/* get the word we want to complete */
|
||||
word = get_word_at(line, *pos, &wordstart);
|
||||
old_wordstart = wordstart;
|
||||
|
||||
startpos = (int) (wordstart-line);
|
||||
wordlen = strlen(word);
|
||||
|
||||
/* get the start of line until the word we're completing */
|
||||
if (isseparator(*line)) {
|
||||
/* empty space at the start of line */
|
||||
if (wordstart == line)
|
||||
wordstart += strlen(wordstart);
|
||||
} else {
|
||||
while (wordstart > line && isseparator(wordstart[-1]))
|
||||
/* remove trailing spaces from linestart */
|
||||
while (wordstart > line && isseparator_space(wordstart[-1]))
|
||||
wordstart--;
|
||||
}
|
||||
|
||||
/* unless everything was spaces */
|
||||
if (old_wordstart > line && wordstart == line)
|
||||
wordstart = old_wordstart - 1;
|
||||
|
||||
linestart = g_strndup(line, (int) (wordstart-line));
|
||||
|
||||
/* completions usually add space after the word, that makes
|
||||
@ -175,19 +181,24 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
|
||||
BUT if we start completion with "/msg "<tab>, we don't
|
||||
want to complete the /msg word, but instead complete empty
|
||||
word with /msg being in linestart. */
|
||||
if (!erase && *pos > 0 && line[*pos-1] == ' ' &&
|
||||
(*linestart == '\0' || wordstart[-1] != ' ')) {
|
||||
if (!erase && *pos > 0 && isseparator_space(line[*pos-1]) &&
|
||||
(*linestart == '\0' || !isseparator_space(wordstart[-1]))) {
|
||||
char *old;
|
||||
|
||||
old = linestart;
|
||||
linestart = *linestart == '\0' ?
|
||||
g_strdup(word) :
|
||||
g_strconcat(linestart, " ", word, NULL);
|
||||
g_strdup_printf("%s%c%s",
|
||||
/* do not accidentally duplicate the word separator */
|
||||
line == wordstart - 1 ? "" : linestart,
|
||||
wordstart[-1], word);
|
||||
g_free(old);
|
||||
|
||||
g_free(word);
|
||||
word = g_strdup("");
|
||||
startpos = strlen(linestart)+1;
|
||||
|
||||
startpos = *linestart == '\0' ? 0 :
|
||||
strlen(linestart)+1;
|
||||
wordlen = 0;
|
||||
}
|
||||
|
||||
@ -217,6 +228,11 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i
|
||||
want_space = TRUE;
|
||||
signal_emit("complete word", 5, &complist, window, word, linestart, &want_space);
|
||||
last_want_space = want_space;
|
||||
|
||||
if (complist != NULL) {
|
||||
/* Remove all nulls (from the signal) before doing further processing */
|
||||
complist = g_list_remove_all(g_list_first(complist), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(linestart);
|
||||
@ -329,7 +345,9 @@ GList *filename_complete(const char *path, const char *default_path)
|
||||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
|
||||
continue; /* skip . and .. */
|
||||
|
||||
if (basename[0] != '.')
|
||||
/* Skip the dotfiles unless the user explicitly asked us
|
||||
* to do so. Basename might be './', beware of that */
|
||||
if (basename[0] != '.' || basename[1] == '\0')
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -392,7 +410,8 @@ static GList *completion_get_aliases(const char *alias, char cmdchar)
|
||||
continue;
|
||||
|
||||
if (g_ascii_strncasecmp(node->key, alias, len) == 0) {
|
||||
word = g_strdup_printf("%c%s", cmdchar, node->key);
|
||||
word = cmdchar == '\0' ? g_strdup(node->key) :
|
||||
g_strdup_printf("%c%s", cmdchar, node->key);
|
||||
/* add matching alias to completion list, aliases will
|
||||
be appended after command completions and kept in
|
||||
uppercase to show it's an alias */
|
||||
@ -584,13 +603,19 @@ static void sig_complete_word(GList **list, WINDOW_REC *window,
|
||||
|
||||
/* command completion? */
|
||||
cmdchars = settings_get_str("cmdchars");
|
||||
if (*word != '\0' && *linestart == '\0' && strchr(cmdchars, *word)) {
|
||||
if (*word != '\0' && ((*linestart == '\0' && strchr(cmdchars, *word)) ||
|
||||
(*linestart != '\0' && linestart[1] == '\0' &&
|
||||
strchr(cmdchars, *linestart)))) {
|
||||
gboolean skip = *linestart == '\0' ? TRUE : FALSE;
|
||||
|
||||
/* complete /command */
|
||||
*list = completion_get_commands(word+1, *word);
|
||||
*list = completion_get_commands(word + (skip ? 1 : 0),
|
||||
skip ? *word : '\0');
|
||||
|
||||
/* complete aliases, too */
|
||||
*list = g_list_concat(*list,
|
||||
completion_get_aliases(word+1, *word));
|
||||
completion_get_aliases(word + (skip ? 1 : 0),
|
||||
skip ? *word : '\0'));
|
||||
|
||||
if (*list != NULL) signal_stop();
|
||||
return;
|
||||
@ -686,8 +711,20 @@ static void sig_complete_set(GList **list, WINDOW_REC *window,
|
||||
SETTINGS_REC *rec = settings_get_record(line);
|
||||
if (rec != NULL) {
|
||||
char *value = settings_get_print(rec);
|
||||
|
||||
/* show the current option first */
|
||||
if (value != NULL)
|
||||
*list = g_list_append(*list, value);
|
||||
|
||||
/* show the whole list of valid options */
|
||||
if (rec->type == SETTING_TYPE_CHOICE) {
|
||||
char **tmp;
|
||||
|
||||
for (tmp = rec->choices; *tmp; tmp++) {
|
||||
if (g_ascii_strcasecmp(*tmp, value) != 0)
|
||||
*list = g_list_append(*list, g_strdup(*tmp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "levels.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
#include "special-vars.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#include "chat-protocols.h"
|
||||
#include "chatnets.h"
|
||||
@ -246,9 +248,7 @@ static void cmd_channel(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
|
||||
}
|
||||
}
|
||||
|
||||
/* SYNTAX: CHANNEL ADD [-auto | -noauto] [-bots <masks>] [-botcmd <command>]
|
||||
<channel> <network> [<password>] */
|
||||
static void cmd_channel_add(const char *data)
|
||||
static void cmd_channel_add_modify(const char *data, gboolean add)
|
||||
{
|
||||
GHashTable *optlist;
|
||||
CHATNET_REC *chatnetrec;
|
||||
@ -260,8 +260,9 @@ static void cmd_channel_add(const char *data)
|
||||
"channel add", &optlist, &channel, &chatnet, &password))
|
||||
return;
|
||||
|
||||
if (*chatnet == '\0' || *channel == '\0')
|
||||
if (*chatnet == '\0' || *channel == '\0') {
|
||||
cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
}
|
||||
|
||||
chatnetrec = chatnet_find(chatnet);
|
||||
if (chatnetrec == NULL) {
|
||||
@ -276,6 +277,13 @@ static void cmd_channel_add(const char *data)
|
||||
|
||||
rec = channel_setup_find(channel, chatnet);
|
||||
if (rec == NULL) {
|
||||
if (add == FALSE) {
|
||||
cmd_params_free(free_arg);
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
TXT_CHANSETUP_NOT_FOUND, channel, chatnet);
|
||||
return;
|
||||
}
|
||||
|
||||
rec = CHAT_PROTOCOL(chatnetrec)->create_channel_setup();
|
||||
rec->name = g_strdup(channel);
|
||||
rec->chatnet = g_strdup(chatnet);
|
||||
@ -299,6 +307,18 @@ static void cmd_channel_add(const char *data)
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
||||
/* SYNTAX: CHANNEL ADD|MODIFY [-auto | -noauto] [-bots <masks>] [-botcmd <command>]
|
||||
<channel> <network> [<password>] */
|
||||
static void cmd_channel_add(const char *data)
|
||||
{
|
||||
cmd_channel_add_modify(data, TRUE);
|
||||
}
|
||||
|
||||
static void cmd_channel_modify(const char *data)
|
||||
{
|
||||
cmd_channel_add_modify(data, FALSE);
|
||||
}
|
||||
|
||||
/* SYNTAX: CHANNEL REMOVE <channel> <network> */
|
||||
static void cmd_channel_remove(const char *data)
|
||||
{
|
||||
@ -323,7 +343,7 @@ static void cmd_channel_remove(const char *data)
|
||||
|
||||
static int get_nick_length(void *data)
|
||||
{
|
||||
return strlen(((NICK_REC *) data)->nick);
|
||||
return string_width(((NICK_REC *) data)->nick, -1);
|
||||
}
|
||||
|
||||
static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
@ -333,9 +353,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
GString *str;
|
||||
GSList *tmp;
|
||||
char *format, *stripped, *prefix_format;
|
||||
char *linebuf, nickmode[2] = { 0, 0 };
|
||||
char *aligned_nick, nickmode[2] = { 0, 0 };
|
||||
int *columns, cols, rows, last_col_rows, col, row, max_width;
|
||||
int item_extra, linebuf_size, formatnum;
|
||||
int item_extra, formatnum;
|
||||
|
||||
window = window_find_closest(channel->server, channel->visible_name,
|
||||
MSGLEVEL_CLIENTCRAP);
|
||||
@ -394,7 +414,6 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
last_col_rows = rows;
|
||||
|
||||
str = g_string_new(prefix_format);
|
||||
linebuf_size = max_width+1; linebuf = g_malloc(linebuf_size);
|
||||
|
||||
col = 0; row = 0;
|
||||
for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
|
||||
@ -405,13 +424,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
else
|
||||
nickmode[0] = ' ';
|
||||
|
||||
if (linebuf_size < columns[col]-item_extra+1) {
|
||||
linebuf_size = (columns[col]-item_extra+1)*2;
|
||||
linebuf = g_realloc(linebuf, linebuf_size);
|
||||
}
|
||||
memset(linebuf, ' ', columns[col]-item_extra);
|
||||
linebuf[columns[col]-item_extra] = '\0';
|
||||
memcpy(linebuf, rec->nick, strlen(rec->nick));
|
||||
aligned_nick = get_alignment(rec->nick,
|
||||
columns[col]-item_extra,
|
||||
ALIGN_PAD, ' ');
|
||||
|
||||
formatnum = rec->op ? TXT_NAMES_NICK_OP :
|
||||
rec->halfop ? TXT_NAMES_NICK_HALFOP :
|
||||
@ -420,8 +435,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
format = format_get_text(MODULE_NAME, NULL,
|
||||
channel->server,
|
||||
channel->visible_name,
|
||||
formatnum, nickmode, linebuf);
|
||||
formatnum, nickmode, aligned_nick);
|
||||
g_string_append(str, format);
|
||||
g_free(aligned_nick);
|
||||
g_free(format);
|
||||
|
||||
if (++col == cols) {
|
||||
@ -446,7 +462,6 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
g_string_free(str, TRUE);
|
||||
g_free_not_null(columns);
|
||||
g_free_not_null(prefix_format);
|
||||
g_free(linebuf);
|
||||
}
|
||||
|
||||
void fe_channels_nicklist(CHANNEL_REC *channel, int flags)
|
||||
@ -622,12 +637,14 @@ void fe_channels_init(void)
|
||||
command_bind("join", NULL, (SIGNAL_FUNC) cmd_join);
|
||||
command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel);
|
||||
command_bind("channel add", NULL, (SIGNAL_FUNC) cmd_channel_add);
|
||||
command_bind("channel modify", NULL, (SIGNAL_FUNC) cmd_channel_modify);
|
||||
command_bind("channel remove", NULL, (SIGNAL_FUNC) cmd_channel_remove);
|
||||
command_bind("channel list", NULL, (SIGNAL_FUNC) cmd_channel_list);
|
||||
command_bind("names", NULL, (SIGNAL_FUNC) cmd_names);
|
||||
command_bind("cycle", NULL, (SIGNAL_FUNC) cmd_cycle);
|
||||
|
||||
command_set_options("channel add", "auto noauto -bots -botcmd");
|
||||
command_set_options("channel modify", "auto noauto -bots -botcmd");
|
||||
command_set_options("names", "count ops halfops voices normal");
|
||||
command_set_options("join", "invite window");
|
||||
}
|
||||
@ -643,6 +660,7 @@ void fe_channels_deinit(void)
|
||||
command_unbind("join", (SIGNAL_FUNC) cmd_join);
|
||||
command_unbind("channel", (SIGNAL_FUNC) cmd_channel);
|
||||
command_unbind("channel add", (SIGNAL_FUNC) cmd_channel_add);
|
||||
command_unbind("channel modify", (SIGNAL_FUNC) cmd_channel_modify);
|
||||
command_unbind("channel remove", (SIGNAL_FUNC) cmd_channel_remove);
|
||||
command_unbind("channel list", (SIGNAL_FUNC) cmd_channel_list);
|
||||
command_unbind("names", (SIGNAL_FUNC) cmd_names);
|
||||
|
@ -459,15 +459,24 @@ gboolean strarray_find_dest(char **array, const TEXT_DEST_REC *dest)
|
||||
{
|
||||
g_return_val_if_fail(array != NULL, FALSE);
|
||||
|
||||
if (strarray_find(array, "*") != -1)
|
||||
return TRUE;
|
||||
|
||||
if (strarray_find(array, dest->target) != -1)
|
||||
return TRUE;
|
||||
|
||||
if (dest->server_tag != NULL) {
|
||||
char *tagtarget = g_strdup_printf("%s/%s", dest->server_tag, dest->target);
|
||||
char *tagtarget = g_strdup_printf("%s/%s", dest->server_tag, "*");
|
||||
int ret = strarray_find(array, tagtarget);
|
||||
g_free(tagtarget);
|
||||
if (ret != -1)
|
||||
return TRUE;
|
||||
|
||||
tagtarget = g_strdup_printf("%s/%s", dest->server_tag, dest->target);
|
||||
ret = strarray_find(array, tagtarget);
|
||||
g_free(tagtarget);
|
||||
if (ret != -1)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ static int ret_texts[] = {
|
||||
TXT_INVALID_TIME,
|
||||
TXT_INVALID_CHARSET,
|
||||
TXT_EVAL_MAX_RECURSE,
|
||||
TXT_PROGRAM_NOT_FOUND
|
||||
TXT_PROGRAM_NOT_FOUND,
|
||||
TXT_NO_SERVER_DEFINED,
|
||||
};
|
||||
|
||||
int command_hide_output;
|
||||
|
@ -237,22 +237,13 @@ static int signal_name_to_id(const char *name)
|
||||
static int cmd_options_get_signal(const char *cmd,
|
||||
GHashTable *optlist)
|
||||
{
|
||||
GSList *list, *tmp, *next;
|
||||
GList *list;
|
||||
char *signame;
|
||||
int signum;
|
||||
|
||||
/* get all the options, then remove the known ones. there should
|
||||
be only one left - the signal */
|
||||
list = hashtable_get_keys(optlist);
|
||||
if (cmd != NULL) {
|
||||
for (tmp = list; tmp != NULL; tmp = next) {
|
||||
char *option = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (command_have_option(cmd, option))
|
||||
list = g_slist_remove(list, option);
|
||||
}
|
||||
}
|
||||
list = optlist_remove_known(cmd, optlist);
|
||||
|
||||
if (list == NULL)
|
||||
return -1;
|
||||
@ -272,7 +263,7 @@ static int cmd_options_get_signal(const char *cmd,
|
||||
return -2;
|
||||
}
|
||||
|
||||
g_slist_free(list);
|
||||
g_list_free(list);
|
||||
return signum;
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ static void cmd_unignore(const char *data)
|
||||
{
|
||||
IGNORE_REC *rec;
|
||||
GSList *tmp;
|
||||
char *mask;
|
||||
char *mask, *mask_orig;
|
||||
void *free_arg;
|
||||
|
||||
if (!cmd_get_params(data, &free_arg, 1, &mask))
|
||||
@ -224,6 +224,10 @@ static void cmd_unignore(const char *data)
|
||||
if (*mask == '\0')
|
||||
cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
/* Save the mask string here since it might be modified in the code
|
||||
* below and we need it to print meaningful error messages. */
|
||||
mask_orig = mask;
|
||||
|
||||
if (is_numeric(mask, ' ')) {
|
||||
/* with index number */
|
||||
tmp = g_slist_nth(ignores, atoi(mask)-1);
|
||||
@ -248,7 +252,7 @@ static void cmd_unignore(const char *data)
|
||||
ignore_update_rec(rec);
|
||||
} else {
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
TXT_IGNORE_NOT_FOUND, mask);
|
||||
TXT_IGNORE_NOT_FOUND, mask_orig);
|
||||
}
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ static void autolog_open(SERVER_REC *server, const char *server_tag,
|
||||
log_item_add(log, LOG_ITEM_TARGET, target, server_tag);
|
||||
|
||||
dir = g_path_get_dirname(log->real_fname);
|
||||
mkpath(dir, log_dir_create_mode);
|
||||
g_mkdir_with_parents(dir, log_dir_create_mode);
|
||||
g_free(dir);
|
||||
|
||||
log->temp = TRUE;
|
||||
|
@ -175,6 +175,7 @@ static void sig_message_public(SERVER_REC *server, const char *msg,
|
||||
int for_me, print_channel, level;
|
||||
char *nickmode, *color, *freemsg = NULL;
|
||||
HILIGHT_REC *hilight;
|
||||
TEXT_DEST_REC dest;
|
||||
|
||||
/* NOTE: this may return NULL if some channel is just closed with
|
||||
/WINDOW CLOSE and server still sends the few last messages */
|
||||
@ -214,7 +215,6 @@ static void sig_message_public(SERVER_REC *server, const char *msg,
|
||||
if (printnick == NULL)
|
||||
printnick = nick;
|
||||
|
||||
TEXT_DEST_REC dest;
|
||||
format_create_dest(&dest, server, target, level, NULL);
|
||||
dest.address = address;
|
||||
dest.nick = nick;
|
||||
@ -396,8 +396,9 @@ static void sig_message_quit(SERVER_REC *server, const char *nick,
|
||||
count = 0; windows = NULL;
|
||||
chans = g_string_new(NULL);
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *rec;
|
||||
level = MSGLEVEL_QUITS;
|
||||
CHANNEL_REC *rec = tmp->data;
|
||||
rec = tmp->data;
|
||||
|
||||
if (!nicklist_find(rec, nick))
|
||||
continue;
|
||||
|
@ -104,7 +104,7 @@ static SERVER_SETUP_REC *create_server_setup(GHashTable *optlist)
|
||||
return server;
|
||||
}
|
||||
|
||||
static void cmd_server_add(const char *data)
|
||||
static void cmd_server_add_modify(const char *data, gboolean add)
|
||||
{
|
||||
GHashTable *optlist;
|
||||
SERVER_SETUP_REC *rec;
|
||||
@ -124,6 +124,13 @@ static void cmd_server_add(const char *data)
|
||||
rec = server_setup_find(addr, port, chatnet);
|
||||
|
||||
if (rec == NULL) {
|
||||
if (add == FALSE) {
|
||||
cmd_params_free(free_arg);
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
TXT_SETUPSERVER_NOT_FOUND, addr, port);
|
||||
return;
|
||||
}
|
||||
|
||||
rec = create_server_setup(optlist);
|
||||
if (rec == NULL) {
|
||||
cmd_params_free(free_arg);
|
||||
@ -205,6 +212,16 @@ static void cmd_server_add(const char *data)
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
||||
static void cmd_server_add(const char *data)
|
||||
{
|
||||
cmd_server_add_modify(data, TRUE);
|
||||
}
|
||||
|
||||
static void cmd_server_modify(const char *data)
|
||||
{
|
||||
cmd_server_add_modify(data, FALSE);
|
||||
}
|
||||
|
||||
/* SYNTAX: SERVER REMOVE <address> [<port>] [<network>] */
|
||||
static void cmd_server_remove(const char *data)
|
||||
{
|
||||
@ -388,10 +405,12 @@ void fe_server_init(void)
|
||||
command_bind("server", NULL, (SIGNAL_FUNC) cmd_server);
|
||||
command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
|
||||
command_bind("server add", NULL, (SIGNAL_FUNC) cmd_server_add);
|
||||
command_bind("server modify", NULL, (SIGNAL_FUNC) cmd_server_modify);
|
||||
command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove);
|
||||
command_bind_first("server", NULL, (SIGNAL_FUNC) server_command);
|
||||
command_bind_first("disconnect", NULL, (SIGNAL_FUNC) server_command);
|
||||
command_set_options("server add", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd");
|
||||
command_set_options("server modify", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd");
|
||||
|
||||
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
|
||||
signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting);
|
||||
@ -412,6 +431,7 @@ void fe_server_deinit(void)
|
||||
command_unbind("server", (SIGNAL_FUNC) cmd_server);
|
||||
command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect);
|
||||
command_unbind("server add", (SIGNAL_FUNC) cmd_server_add);
|
||||
command_unbind("server modify", (SIGNAL_FUNC) cmd_server_modify);
|
||||
command_unbind("server remove", (SIGNAL_FUNC) cmd_server_remove);
|
||||
command_unbind("server", (SIGNAL_FUNC) server_command);
|
||||
command_unbind("disconnect", (SIGNAL_FUNC) server_command);
|
||||
|
@ -67,6 +67,7 @@ static void set_print_pattern(const char *pattern)
|
||||
static void set_boolean(const char *key, const char *value)
|
||||
{
|
||||
char *stripped_value;
|
||||
|
||||
stripped_value = g_strdup(value);
|
||||
g_strstrip(stripped_value);
|
||||
|
||||
@ -99,6 +100,24 @@ static void set_int(const char *key, const char *value)
|
||||
settings_set_int(key, (int)longval);
|
||||
}
|
||||
|
||||
static void set_choice(const char *key, const char *value)
|
||||
{
|
||||
char *stripped_value;
|
||||
|
||||
stripped_value = g_strdup(value);
|
||||
g_strstrip(stripped_value);
|
||||
|
||||
if (settings_set_choice(key, stripped_value) == FALSE) {
|
||||
SETTINGS_REC *rec = settings_get_record(key);
|
||||
char *msg = g_strjoinv(", ", rec->choices);
|
||||
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_INVALID_CHOICE, msg);
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
g_free(stripped_value);
|
||||
}
|
||||
|
||||
/* SYNTAX: SET [-clear | -default] [<key> [<value>]] */
|
||||
static void cmd_set(char *data)
|
||||
{
|
||||
@ -142,6 +161,12 @@ static void cmd_set(char *data)
|
||||
else
|
||||
set_int(key, value);
|
||||
break;
|
||||
case SETTING_TYPE_CHOICE:
|
||||
if (clear || set_default)
|
||||
settings_set_choice(key, rec->choices[rec->default_value.v_int]);
|
||||
else
|
||||
set_choice(key, value);
|
||||
break;
|
||||
case SETTING_TYPE_STRING:
|
||||
settings_set_str(key, clear ? "" :
|
||||
set_default ? rec->default_value.v_string :
|
||||
|
@ -422,33 +422,17 @@ void format_create_dest_tag(TEXT_DEST_REC *dest, void *server,
|
||||
window_find_closest(server, target, level);
|
||||
}
|
||||
|
||||
static int advance (char const **str, gboolean utf8)
|
||||
{
|
||||
if (utf8) {
|
||||
gunichar c;
|
||||
|
||||
c = g_utf8_get_char(*str);
|
||||
*str = g_utf8_next_char(*str);
|
||||
|
||||
return unichar_isprint(c) ? mk_wcwidth(c) : 1;
|
||||
} else {
|
||||
*str += 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return length of text part in string (ie. without % codes) */
|
||||
int format_get_length(const char *str)
|
||||
{
|
||||
GString *tmp;
|
||||
int len;
|
||||
gboolean utf8;
|
||||
int utf8;
|
||||
int adv = 0;
|
||||
|
||||
g_return_val_if_fail(str != NULL, 0);
|
||||
|
||||
utf8 = is_utf8() && g_utf8_validate(str, -1, NULL);
|
||||
utf8 = string_policy(str);
|
||||
|
||||
tmp = g_string_new(NULL);
|
||||
len = 0;
|
||||
@ -467,7 +451,7 @@ int format_get_length(const char *str)
|
||||
len++;
|
||||
}
|
||||
|
||||
len += advance(&str, utf8);
|
||||
len += string_advance(&str, utf8);
|
||||
}
|
||||
|
||||
g_string_free(tmp, TRUE);
|
||||
@ -482,12 +466,12 @@ int format_real_length(const char *str, int len)
|
||||
GString *tmp;
|
||||
const char *start;
|
||||
const char *oldstr;
|
||||
gboolean utf8;
|
||||
int utf8;
|
||||
int adv = 0;
|
||||
g_return_val_if_fail(str != NULL, 0);
|
||||
g_return_val_if_fail(len >= 0, 0);
|
||||
|
||||
utf8 = is_utf8() && g_utf8_validate(str, -1, NULL);
|
||||
utf8 = string_policy(str);
|
||||
|
||||
start = str;
|
||||
tmp = g_string_new(NULL);
|
||||
@ -509,7 +493,7 @@ int format_real_length(const char *str, int len)
|
||||
}
|
||||
|
||||
oldstr = str;
|
||||
len -= advance(&str, utf8);
|
||||
len -= string_advance(&str, utf8);
|
||||
if (len < 0)
|
||||
str = oldstr;
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ static void hilight_add_config(HILIGHT_REC *rec)
|
||||
if (rec->nickmask) iconfig_node_set_bool(node, "mask", TRUE);
|
||||
if (rec->fullword) iconfig_node_set_bool(node, "fullword", TRUE);
|
||||
if (rec->regexp) iconfig_node_set_bool(node, "regexp", TRUE);
|
||||
if (rec->case_sensitive) iconfig_node_set_bool(node, "matchcase", TRUE);
|
||||
if (rec->servertag) iconfig_node_set_str(node, "servertag", rec->servertag);
|
||||
|
||||
if (rec->channels != NULL && *rec->channels != NULL) {
|
||||
@ -121,8 +122,11 @@ static void hilight_init_rec(HILIGHT_REC *rec)
|
||||
{
|
||||
#ifdef HAVE_REGEX_H
|
||||
if (rec->regexp_compiled) regfree(&rec->preg);
|
||||
rec->regexp_compiled = !rec->regexp ? FALSE :
|
||||
regcomp(&rec->preg, rec->text, REG_EXTENDED|REG_ICASE) == 0;
|
||||
if (!rec->regexp)
|
||||
rec->regexp_compiled = FALSE;
|
||||
else
|
||||
rec->regexp_compiled = regcomp(&rec->preg, rec->text,
|
||||
rec->case_sensitive ? REG_EXTENDED : (REG_EXTENDED|REG_ICASE)) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -174,7 +178,7 @@ static HILIGHT_REC *hilight_find(const char *text, char **channels)
|
||||
if (channels == NULL || rec->channels == NULL)
|
||||
continue; /* other doesn't have channels */
|
||||
|
||||
if (strarray_length(channels) != strarray_length(rec->channels))
|
||||
if (g_strv_length(channels) != g_strv_length(rec->channels))
|
||||
continue; /* different amount of channels */
|
||||
|
||||
/* check that channels match */
|
||||
@ -209,10 +213,16 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text,
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (rec->case_sensitive) {
|
||||
match = rec->fullword ?
|
||||
strstr_full(text, rec->text) :
|
||||
strstr(text, rec->text);
|
||||
} else {
|
||||
match = rec->fullword ?
|
||||
stristr_full(text, rec->text) :
|
||||
stristr(text, rec->text);
|
||||
}
|
||||
if (match != NULL) {
|
||||
if (match_beg != NULL && match_end != NULL) {
|
||||
*match_beg = (int) (match-text);
|
||||
@ -464,6 +474,7 @@ static void read_hilight_config(void)
|
||||
rec->priority = config_node_get_int(node, "priority", 0);
|
||||
rec->nick = config_node_get_bool(node, "nick", TRUE);
|
||||
rec->word = config_node_get_bool(node, "word", TRUE);
|
||||
rec->case_sensitive = config_node_get_bool(node, "matchcase", FALSE);
|
||||
|
||||
rec->nickmask = config_node_get_bool(node, "mask", FALSE);
|
||||
rec->fullword = config_node_get_bool(node, "fullword", FALSE);
|
||||
@ -495,6 +506,7 @@ static void hilight_print(int index, HILIGHT_REC *rec)
|
||||
|
||||
if (rec->nickmask) g_string_append(options, "-mask ");
|
||||
if (rec->fullword) g_string_append(options, "-full ");
|
||||
if (rec->case_sensitive) g_string_append(options, "-matchcase ");
|
||||
if (rec->regexp) {
|
||||
g_string_append(options, "-regexp ");
|
||||
#ifdef HAVE_REGEX_H
|
||||
@ -543,7 +555,7 @@ static void cmd_hilight_show(void)
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_HILIGHT_FOOTER);
|
||||
}
|
||||
|
||||
/* SYNTAX: HILIGHT [-nick | -word | -line] [-mask | -full | -regexp]
|
||||
/* SYNTAX: HILIGHT [-nick | -word | -line] [-mask | -full | -matchcase | -regexp]
|
||||
[-color <color>] [-actcolor <color>] [-level <level>]
|
||||
[-network <network>] [-channels <channels>] <text> */
|
||||
static void cmd_hilight(const char *data)
|
||||
@ -611,6 +623,7 @@ static void cmd_hilight(const char *data)
|
||||
rec->nickmask = g_hash_table_lookup(optlist, "mask") != NULL;
|
||||
rec->fullword = g_hash_table_lookup(optlist, "full") != NULL;
|
||||
rec->regexp = g_hash_table_lookup(optlist, "regexp") != NULL;
|
||||
rec->case_sensitive = g_hash_table_lookup(optlist, "matchcase") != NULL;
|
||||
|
||||
if (colorarg != NULL) {
|
||||
g_free_and_null(rec->color);
|
||||
@ -717,7 +730,7 @@ void hilight_text_init(void)
|
||||
|
||||
command_bind("hilight", NULL, (SIGNAL_FUNC) cmd_hilight);
|
||||
command_bind("dehilight", NULL, (SIGNAL_FUNC) cmd_dehilight);
|
||||
command_set_options("hilight", "-color -actcolor -level -priority -network -channels nick word line mask full regexp");
|
||||
command_set_options("hilight", "-color -actcolor -level -priority -network -channels nick word line mask full regexp matchcase");
|
||||
}
|
||||
|
||||
void hilight_text_deinit(void)
|
||||
|
@ -23,6 +23,7 @@ struct _HILIGHT_REC {
|
||||
unsigned int nickmask:1; /* `text' is a nick mask */
|
||||
unsigned int fullword:1; /* match `text' only for full words */
|
||||
unsigned int regexp:1; /* `text' is a regular expression */
|
||||
unsigned int case_sensitive:1;/* `text' must match case */
|
||||
#ifdef HAVE_REGEX_H
|
||||
unsigned int regexp_compiled:1; /* should always be TRUE, unless regexp is invalid */
|
||||
regex_t preg;
|
||||
|
@ -221,8 +221,10 @@ FORMAT_REC fecommon_core_formats[] = {
|
||||
{ "invalid_level", "Invalid message level", 0 },
|
||||
{ "invalid_size", "Invalid size", 0 },
|
||||
{ "invalid_charset", "Invalid charset: $0", 1, { 0 } },
|
||||
{ "invalid_choice", "Invalid choice, must be one of $0", 1, { 0 } },
|
||||
{ "eval_max_recurse", "/eval hit maximum recursion limit", 0 },
|
||||
{ "program_not_found", "Could not find file or file is not executable", 0 },
|
||||
{ "no_server_defined", "No servers defined for this network, see /help server for how to add one", 0 },
|
||||
|
||||
/* ---- */
|
||||
{ NULL, "Themes", 0 },
|
||||
|
@ -190,8 +190,10 @@ enum {
|
||||
TXT_INVALID_LEVEL,
|
||||
TXT_INVALID_SIZE,
|
||||
TXT_INVALID_CHARSET,
|
||||
TXT_INVALID_CHOICE,
|
||||
TXT_EVAL_MAX_RECURSE,
|
||||
TXT_PROGRAM_NOT_FOUND,
|
||||
TXT_NO_SERVER_DEFINED,
|
||||
|
||||
TXT_FILL_11,
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#define MODULE_NAME "fe-common/core"
|
||||
|
||||
typedef guint32 unichar;
|
||||
#include "utf8.h"
|
||||
typedef struct {
|
||||
time_t time;
|
||||
char *nick;
|
||||
|
@ -365,9 +365,9 @@ char *theme_format_expand_get(THEME_REC *theme, const char **format)
|
||||
GString *str;
|
||||
char *ret;
|
||||
theme_rm_col dummy, reset;
|
||||
int braces = 1; /* we start with one brace opened */
|
||||
dummy.m[0] = '\0';
|
||||
strcpy(reset.m, "n");
|
||||
int braces = 1; /* we start with one brace opened */
|
||||
|
||||
str = g_string_new(NULL);
|
||||
while (**format != '\0' && braces != 0) {
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* utf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 2002 Timo Sirainen
|
||||
*
|
||||
* Based on GLib code by
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
@ -1,17 +0,0 @@
|
||||
#ifndef __UTF8_H
|
||||
#define __UTF8_H
|
||||
|
||||
/* XXX I didn't check the encoding range of big5+. This is standard big5. */
|
||||
#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */
|
||||
#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */
|
||||
#define is_big5_lo(lo) ((is_big5_los(lo) || is_big5_lox(lo)))
|
||||
#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
|
||||
#define is_big5(hi,lo) (is_big5_hi(hi) && is_big5_lo(lo))
|
||||
|
||||
/* Returns width for character (0-2). */
|
||||
int mk_wcwidth(unichar c);
|
||||
|
||||
#define unichar_isprint(c) (((c) & ~0x80) >= 32)
|
||||
#define is_utf8_leading(c) (((c) & 0xc0) != 0x80)
|
||||
|
||||
#endif
|
@ -50,7 +50,8 @@ const char *get_visible_target(IRC_SERVER_REC *server, const char *target)
|
||||
|
||||
return target;
|
||||
}
|
||||
/* SYNTAX: SERVER ADD [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>] [-ssl_pass <password>]
|
||||
|
||||
/* SYNTAX: SERVER ADD|MODIFY [-4 | -6] [-ssl] [-ssl_cert <cert>] [-ssl_pkey <pkey>] [-ssl_pass <password>]
|
||||
[-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
|
||||
[-ssl_ciphers <list>]
|
||||
[-auto | -noauto] [-network <network>] [-host <hostname>]
|
||||
|
@ -88,14 +88,7 @@ static void cmd_network_list(void)
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETWORK_FOOTER);
|
||||
}
|
||||
|
||||
/* SYNTAX: NETWORK ADD [-nick <nick>] [-user <user>] [-realname <name>]
|
||||
[-host <host>] [-usermode <mode>] [-autosendcmd <cmd>]
|
||||
[-querychans <count>] [-whois <count>] [-msgs <count>]
|
||||
[-kicks <count>] [-modes <count>] [-cmdspeed <ms>]
|
||||
[-cmdmax <count>] [-sasl_mechanism <mechanism>]
|
||||
[-sasl_username <username>] [-sasl_password <password>]
|
||||
<name> */
|
||||
static void cmd_network_add(const char *data)
|
||||
static void cmd_network_add_modify(const char *data, gboolean add)
|
||||
{
|
||||
GHashTable *optlist;
|
||||
char *name, *value;
|
||||
@ -105,10 +98,18 @@ static void cmd_network_add(const char *data)
|
||||
if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
|
||||
"network add", &optlist, &name))
|
||||
return;
|
||||
|
||||
if (*name == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
|
||||
|
||||
rec = ircnet_find(name);
|
||||
if (rec == NULL) {
|
||||
if (add == FALSE) {
|
||||
cmd_params_free(free_arg);
|
||||
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
IRCTXT_NETWORK_NOT_FOUND, name);
|
||||
return;
|
||||
}
|
||||
|
||||
rec = g_new0(IRC_CHATNET_REC, 1);
|
||||
rec->name = g_strdup(name);
|
||||
} else {
|
||||
@ -174,6 +175,23 @@ static void cmd_network_add(const char *data)
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
||||
/* SYNTAX: NETWORK ADD|MODIFY [-nick <nick>] [-user <user>] [-realname <name>]
|
||||
[-host <host>] [-usermode <mode>] [-autosendcmd <cmd>]
|
||||
[-querychans <count>] [-whois <count>] [-msgs <count>]
|
||||
[-kicks <count>] [-modes <count>] [-cmdspeed <ms>]
|
||||
[-cmdmax <count>] [-sasl_mechanism <mechanism>]
|
||||
[-sasl_username <username>] [-sasl_password <password>]
|
||||
<name> */
|
||||
static void cmd_network_add(const char *data)
|
||||
{
|
||||
cmd_network_add_modify(data, TRUE);
|
||||
}
|
||||
|
||||
static void cmd_network_modify(const char *data)
|
||||
{
|
||||
cmd_network_add_modify(data, FALSE);
|
||||
}
|
||||
|
||||
/* SYNTAX: NETWORK REMOVE <network> */
|
||||
static void cmd_network_remove(const char *data)
|
||||
{
|
||||
@ -206,10 +224,13 @@ void fe_ircnet_init(void)
|
||||
command_bind("network", NULL, (SIGNAL_FUNC) cmd_network);
|
||||
command_bind("network list", NULL, (SIGNAL_FUNC) cmd_network_list);
|
||||
command_bind("network add", NULL, (SIGNAL_FUNC) cmd_network_add);
|
||||
command_bind("network modify", NULL, (SIGNAL_FUNC) cmd_network_modify);
|
||||
command_bind("network remove", NULL, (SIGNAL_FUNC) cmd_network_remove);
|
||||
|
||||
command_set_options("network add", "-kicks -msgs -modes -whois -cmdspeed "
|
||||
"-cmdmax -nick -user -realname -host -autosendcmd -querychans -usermode -sasl_mechanism -sasl_username -sasl_password");
|
||||
command_set_options("network modify", "-kicks -msgs -modes -whois -cmdspeed "
|
||||
"-cmdmax -nick -user -realname -host -autosendcmd -querychans -usermode -sasl_mechanism -sasl_username -sasl_password");
|
||||
}
|
||||
|
||||
void fe_ircnet_deinit(void)
|
||||
@ -218,5 +239,6 @@ void fe_ircnet_deinit(void)
|
||||
command_unbind("network", (SIGNAL_FUNC) cmd_network);
|
||||
command_unbind("network list", (SIGNAL_FUNC) cmd_network_list);
|
||||
command_unbind("network add", (SIGNAL_FUNC) cmd_network_add);
|
||||
command_unbind("network modify", (SIGNAL_FUNC) cmd_network_modify);
|
||||
command_unbind("network remove", (SIGNAL_FUNC) cmd_network_remove);
|
||||
}
|
||||
|
@ -4,8 +4,7 @@ AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/core/ \
|
||||
-I$(top_srcdir)/src/fe-common/core/ \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(CURSES_INCLUDEDIR)
|
||||
$(GLIB_CFLAGS)
|
||||
|
||||
irssi_DEPENDENCIES = \
|
||||
@COMMON_LIBS@ \
|
||||
@ -22,25 +21,11 @@ irssi_LDADD = \
|
||||
@PROG_LIBS@ \
|
||||
@TEXTUI_LIBS@
|
||||
|
||||
tparm_sources = \
|
||||
tparm.c
|
||||
|
||||
terminfo_sources = \
|
||||
term-terminfo.c \
|
||||
terminfo-core.c
|
||||
|
||||
curses_sources = \
|
||||
term-curses.c
|
||||
|
||||
if NEED_TPARM
|
||||
use_tparm_sources = $(tparm_sources)
|
||||
endif
|
||||
|
||||
if USE_CURSES
|
||||
use_term_sources = $(curses_sources)
|
||||
else
|
||||
use_term_sources = $(terminfo_sources)
|
||||
endif
|
||||
|
||||
irssi_SOURCES = \
|
||||
gui-entry.c \
|
||||
@ -56,8 +41,6 @@ irssi_SOURCES = \
|
||||
statusbar-config.c \
|
||||
statusbar-items.c \
|
||||
term.c \
|
||||
term-dummy.c \
|
||||
$(use_tparm_sources) \
|
||||
$(use_term_sources) \
|
||||
textbuffer.c \
|
||||
textbuffer-commands.c \
|
||||
@ -85,6 +68,4 @@ noinst_HEADERS = \
|
||||
module-formats.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(tparm_sources) \
|
||||
$(terminfo_sources) \
|
||||
$(curses_sources)
|
||||
$(terminfo_sources)
|
||||
|
@ -32,6 +32,8 @@
|
||||
#undef i_tolower
|
||||
#undef i_isalnum
|
||||
|
||||
#define KILL_RING_MAX 10
|
||||
|
||||
static unichar i_toupper(unichar c)
|
||||
{
|
||||
if (term_type == TERM_TYPE_UTF8)
|
||||
@ -82,11 +84,22 @@ GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
|
||||
|
||||
void gui_entry_destroy(GUI_ENTRY_REC *entry)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
g_return_if_fail(entry != NULL);
|
||||
|
||||
if (active_entry == entry)
|
||||
gui_entry_set_active(NULL);
|
||||
|
||||
for (tmp = entry->kill_ring; tmp != NULL; tmp = tmp->next) {
|
||||
GUI_ENTRY_CUTBUFFER_REC *rec = tmp->data;
|
||||
if (rec != NULL) {
|
||||
g_free(rec->cutbuffer);
|
||||
g_free(rec);
|
||||
}
|
||||
}
|
||||
g_slist_free(entry->kill_ring);
|
||||
|
||||
g_free(entry->text);
|
||||
g_free(entry->prompt);
|
||||
g_free(entry);
|
||||
@ -353,22 +366,8 @@ static int scrlen_str(const char *str)
|
||||
char *stripped;
|
||||
g_return_val_if_fail(str != NULL, 0);
|
||||
|
||||
str = stripped = strip_codes(str);
|
||||
if (is_utf8() && g_utf8_validate(str, -1, NULL)) {
|
||||
|
||||
while (*str != '\0') {
|
||||
gunichar c;
|
||||
|
||||
c = g_utf8_get_char(str);
|
||||
str = g_utf8_next_char(str);
|
||||
|
||||
len += unichar_isprint(c) ? mk_wcwidth(c) : 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
len = strlen(str);
|
||||
}
|
||||
|
||||
stripped = strip_codes(str);
|
||||
len = string_width(stripped, -1);
|
||||
g_free(stripped);
|
||||
return len;
|
||||
}
|
||||
@ -541,28 +540,51 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
|
||||
|
||||
char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
|
||||
{
|
||||
GUI_ENTRY_CUTBUFFER_REC *tmp;
|
||||
char *buf;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail(entry != NULL, NULL);
|
||||
|
||||
if (entry->cutbuffer == NULL)
|
||||
if (entry->kill_ring == NULL || entry->kill_ring->data == NULL)
|
||||
return NULL;
|
||||
|
||||
tmp = entry->kill_ring->data;
|
||||
|
||||
if (tmp->cutbuffer == NULL)
|
||||
return NULL;
|
||||
|
||||
if (entry->utf8)
|
||||
buf = g_ucs4_to_utf8(entry->cutbuffer, -1, NULL, NULL, NULL);
|
||||
buf = g_ucs4_to_utf8(tmp->cutbuffer, -1, NULL, NULL, NULL);
|
||||
else {
|
||||
buf = g_malloc(entry->cutbuffer_len*6 + 1);
|
||||
buf = g_malloc(tmp->cutbuffer_len*6 + 1);
|
||||
if (term_type == TERM_TYPE_BIG5)
|
||||
unichars_to_big5(entry->cutbuffer, buf);
|
||||
unichars_to_big5(tmp->cutbuffer, buf);
|
||||
else
|
||||
for (i = 0; i <= entry->cutbuffer_len; i++)
|
||||
buf[i] = entry->cutbuffer[i];
|
||||
for (i = 0; i <= tmp->cutbuffer_len; i++)
|
||||
buf[i] = tmp->cutbuffer[i];
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer)
|
||||
char *gui_entry_get_next_cutbuffer(GUI_ENTRY_REC *entry)
|
||||
{
|
||||
GUI_ENTRY_CUTBUFFER_REC *tmp;
|
||||
|
||||
g_return_val_if_fail(entry != NULL, NULL);
|
||||
|
||||
if (entry->kill_ring == NULL)
|
||||
return NULL;
|
||||
|
||||
tmp = entry->kill_ring->data;
|
||||
|
||||
entry->kill_ring = g_slist_remove(entry->kill_ring, tmp);
|
||||
entry->kill_ring = g_slist_append(entry->kill_ring, tmp);
|
||||
|
||||
return gui_entry_get_cutbuffer(entry);
|
||||
}
|
||||
|
||||
void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer)
|
||||
{
|
||||
int newpos, size = 0;
|
||||
|
||||
@ -573,7 +595,41 @@ void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer)
|
||||
gui_entry_erase(entry, size, update_cutbuffer);
|
||||
}
|
||||
|
||||
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer)
|
||||
static GUI_ENTRY_CUTBUFFER_REC *get_cutbuffer_rec(GUI_ENTRY_REC *entry, CUTBUFFER_UPDATE_OP update_cutbuffer)
|
||||
{
|
||||
GUI_ENTRY_CUTBUFFER_REC *tmp;
|
||||
|
||||
g_return_val_if_fail(entry != NULL, NULL);
|
||||
|
||||
if (entry->kill_ring == NULL) {
|
||||
/* no kill ring exists */
|
||||
entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL);
|
||||
} else {
|
||||
tmp = entry->kill_ring->data;
|
||||
|
||||
if (tmp != NULL && tmp->cutbuffer_len > 0
|
||||
&& (!entry->previous_append_next_kill
|
||||
|| update_cutbuffer == CUTBUFFER_UPDATE_REPLACE)) {
|
||||
/* a cutbuffer exists and should be replaced */
|
||||
entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_slist_length(entry->kill_ring) > KILL_RING_MAX) {
|
||||
GUI_ENTRY_CUTBUFFER_REC *rec = g_slist_last(entry->kill_ring)->data;
|
||||
entry->kill_ring = g_slist_remove(entry->kill_ring, rec);
|
||||
if (rec != NULL) g_free(rec->cutbuffer);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
if (entry->kill_ring->data == NULL) {
|
||||
entry->kill_ring->data = g_new0(GUI_ENTRY_CUTBUFFER_REC, 1);
|
||||
}
|
||||
|
||||
return entry->kill_ring->data;
|
||||
}
|
||||
|
||||
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer)
|
||||
{
|
||||
size_t w = 0;
|
||||
|
||||
@ -582,17 +638,59 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer)
|
||||
if (size == 0 || entry->pos < size)
|
||||
return;
|
||||
|
||||
if (update_cutbuffer) {
|
||||
/* put erased text to cutbuffer */
|
||||
if (entry->cutbuffer_len < size) {
|
||||
g_free(entry->cutbuffer);
|
||||
entry->cutbuffer = g_new(unichar, size+1);
|
||||
if (update_cutbuffer != CUTBUFFER_UPDATE_NOOP) {
|
||||
int cutbuffer_new_size;
|
||||
unichar *tmpcutbuffer;
|
||||
GUI_ENTRY_CUTBUFFER_REC *tmp = get_cutbuffer_rec(entry, update_cutbuffer);
|
||||
|
||||
if (tmp->cutbuffer_len == 0) {
|
||||
update_cutbuffer = CUTBUFFER_UPDATE_REPLACE;
|
||||
}
|
||||
|
||||
entry->cutbuffer_len = size;
|
||||
entry->cutbuffer[size] = '\0';
|
||||
memcpy(entry->cutbuffer, entry->text + entry->pos - size,
|
||||
cutbuffer_new_size = tmp->cutbuffer_len + size;
|
||||
tmpcutbuffer = tmp->cutbuffer;
|
||||
entry->append_next_kill = TRUE;
|
||||
switch (update_cutbuffer) {
|
||||
case CUTBUFFER_UPDATE_APPEND:
|
||||
tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1);
|
||||
memcpy(tmp->cutbuffer, tmpcutbuffer,
|
||||
tmp->cutbuffer_len * sizeof(unichar));
|
||||
memcpy(tmp->cutbuffer + tmp->cutbuffer_len,
|
||||
entry->text + entry->pos - size, size * sizeof(unichar));
|
||||
|
||||
tmp->cutbuffer_len = cutbuffer_new_size;
|
||||
tmp->cutbuffer[cutbuffer_new_size] = '\0';
|
||||
g_free(tmpcutbuffer);
|
||||
break;
|
||||
|
||||
case CUTBUFFER_UPDATE_PREPEND:
|
||||
tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1);
|
||||
memcpy(tmp->cutbuffer, entry->text + entry->pos - size,
|
||||
size * sizeof(unichar));
|
||||
memcpy(tmp->cutbuffer + size, tmpcutbuffer,
|
||||
tmp->cutbuffer_len * sizeof(unichar));
|
||||
|
||||
tmp->cutbuffer_len = cutbuffer_new_size;
|
||||
tmp->cutbuffer[cutbuffer_new_size] = '\0';
|
||||
g_free(tmpcutbuffer);
|
||||
break;
|
||||
|
||||
case CUTBUFFER_UPDATE_REPLACE:
|
||||
/* put erased text to cutbuffer */
|
||||
if (tmp->cutbuffer_len < size) {
|
||||
g_free(tmp->cutbuffer);
|
||||
tmp->cutbuffer = g_new(unichar, size+1);
|
||||
}
|
||||
|
||||
tmp->cutbuffer_len = size;
|
||||
tmp->cutbuffer[size] = '\0';
|
||||
memcpy(tmp->cutbuffer, entry->text + entry->pos - size, size * sizeof(unichar));
|
||||
break;
|
||||
|
||||
case CUTBUFFER_UPDATE_NOOP:
|
||||
/* cannot happen, handled in "if" */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->utf8)
|
||||
@ -629,7 +727,7 @@ void gui_entry_erase_cell(GUI_ENTRY_REC *entry)
|
||||
gui_entry_draw(entry);
|
||||
}
|
||||
|
||||
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
|
||||
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op)
|
||||
{
|
||||
int to;
|
||||
|
||||
@ -652,10 +750,10 @@ void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space)
|
||||
}
|
||||
if (to > 0) to++;
|
||||
|
||||
gui_entry_erase(entry, entry->pos-to, TRUE);
|
||||
gui_entry_erase(entry, entry->pos-to, cutbuffer_op);
|
||||
}
|
||||
|
||||
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
|
||||
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op)
|
||||
{
|
||||
int to, size;
|
||||
|
||||
@ -678,7 +776,7 @@ void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
|
||||
|
||||
size = to-entry->pos;
|
||||
entry->pos = to;
|
||||
gui_entry_erase(entry, size, TRUE);
|
||||
gui_entry_erase(entry, size, cutbuffer_op);
|
||||
}
|
||||
|
||||
void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
|
||||
|
@ -1,12 +1,16 @@
|
||||
#ifndef __GUI_ENTRY_H
|
||||
#define __GUI_ENTRY_H
|
||||
|
||||
typedef struct {
|
||||
int cutbuffer_len;
|
||||
unichar *cutbuffer;
|
||||
} GUI_ENTRY_CUTBUFFER_REC;
|
||||
|
||||
typedef struct {
|
||||
int text_len, text_alloc; /* as shorts, not chars */
|
||||
unichar *text;
|
||||
|
||||
int cutbuffer_len;
|
||||
unichar *cutbuffer;
|
||||
GSList *kill_ring;
|
||||
|
||||
/* all as shorts, not chars */
|
||||
int xpos, ypos, width; /* entry position in screen */
|
||||
@ -18,8 +22,19 @@ typedef struct {
|
||||
|
||||
int redraw_needed_from;
|
||||
unsigned int utf8:1;
|
||||
|
||||
unsigned int previous_append_next_kill:1;
|
||||
unsigned int append_next_kill:1;
|
||||
unsigned int yank_preceded:1;
|
||||
} GUI_ENTRY_REC;
|
||||
|
||||
typedef enum {
|
||||
CUTBUFFER_UPDATE_NOOP,
|
||||
CUTBUFFER_UPDATE_REPLACE,
|
||||
CUTBUFFER_UPDATE_APPEND,
|
||||
CUTBUFFER_UPDATE_PREPEND
|
||||
} CUTBUFFER_UPDATE_OP;
|
||||
|
||||
extern GUI_ENTRY_REC *active_entry;
|
||||
|
||||
GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8);
|
||||
@ -40,11 +55,12 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str);
|
||||
void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr);
|
||||
|
||||
char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry);
|
||||
void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer);
|
||||
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer);
|
||||
char *gui_entry_get_next_cutbuffer(GUI_ENTRY_REC *entry);
|
||||
void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer);
|
||||
void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer);
|
||||
void gui_entry_erase_cell(GUI_ENTRY_REC *entry);
|
||||
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space);
|
||||
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space);
|
||||
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op);
|
||||
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op);
|
||||
|
||||
void gui_entry_transpose_chars(GUI_ENTRY_REC *entry);
|
||||
void gui_entry_transpose_words(GUI_ENTRY_REC *entry);
|
||||
@ -60,4 +76,5 @@ void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space);
|
||||
|
||||
void gui_entry_redraw(GUI_ENTRY_REC *entry);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -40,6 +40,9 @@
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
/* After LINE_SPLIT_LIMIT characters, the message will be split into multiple lines */
|
||||
#define LINE_SPLIT_LIMIT 400
|
||||
|
||||
typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item);
|
||||
typedef void (*ENTRY_REDIRECT_ENTRY_FUNC) (const char *line, void *data, SERVER_REC *server, WI_ITEM_REC *item);
|
||||
|
||||
@ -70,6 +73,7 @@ static int paste_timeout_id;
|
||||
static int paste_use_bracketed_mode;
|
||||
static int paste_bracketed_mode;
|
||||
static int paste_was_bracketed_mode;
|
||||
static int previous_yank_preceded;
|
||||
|
||||
/* Terminal sequences that surround the input when the terminal has the
|
||||
* bracketed paste mode active. Fror more details see
|
||||
@ -227,7 +231,7 @@ static void paste_buffer_join_lines(GArray *buf)
|
||||
}
|
||||
|
||||
/* all looks fine - now remove the whitespace, but don't let lines
|
||||
get longer than 400 chars */
|
||||
get longer than LINE_SPLIT_LIMIT chars */
|
||||
dest = arr; last_lf = TRUE; last_lf_pos = NULL; line_len = 0;
|
||||
for (i = 0; i < buf->len; i++) {
|
||||
if (last_lf && isblank(arr[i])) {
|
||||
@ -245,7 +249,7 @@ static void paste_buffer_join_lines(GArray *buf)
|
||||
last_lf = TRUE;
|
||||
} else {
|
||||
last_lf = FALSE;
|
||||
if (++line_len >= 400 && last_lf_pos != NULL) {
|
||||
if (++line_len >= LINE_SPLIT_LIMIT && last_lf_pos != NULL) {
|
||||
memmove(last_lf_pos+1, last_lf_pos,
|
||||
(dest - last_lf_pos) * sizeof(unichar));
|
||||
*last_lf_pos = '\n'; last_lf_pos = NULL;
|
||||
@ -357,11 +361,24 @@ static void insert_paste_prompt(void)
|
||||
{
|
||||
char *str;
|
||||
|
||||
/* The actual number of lines that will show up post-line-split */
|
||||
int actual_line_count = paste_line_count;
|
||||
int split_lines = paste_buffer->len / LINE_SPLIT_LIMIT;
|
||||
|
||||
/* in case this prompt is happening due to line-splitting, calculate the
|
||||
number of lines obtained from this. The number isn't entirely accurate;
|
||||
we just choose the greater of the two since the exact value isn't
|
||||
important */
|
||||
if (split_lines > paste_verify_line_count &&
|
||||
split_lines > paste_line_count) {
|
||||
actual_line_count = split_lines;
|
||||
}
|
||||
|
||||
paste_prompt = TRUE;
|
||||
paste_old_prompt = g_strdup(active_entry->prompt);
|
||||
printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
|
||||
TXT_PASTE_WARNING,
|
||||
paste_line_count,
|
||||
actual_line_count,
|
||||
active_win->active == NULL ? "window" :
|
||||
active_win->active->visible_name);
|
||||
|
||||
@ -424,11 +441,20 @@ static void sig_gui_key_pressed(gpointer keyp)
|
||||
gui_entry_insert_char(active_entry, key);
|
||||
ret = 1;
|
||||
} else {
|
||||
previous_yank_preceded = active_entry->yank_preceded;
|
||||
active_entry->yank_preceded = FALSE;
|
||||
active_entry->previous_append_next_kill = active_entry->append_next_kill;
|
||||
active_entry->append_next_kill = FALSE;
|
||||
ret = key_pressed(keyboard, str);
|
||||
if (ret < 0) {
|
||||
/* key wasn't used for anything, print it */
|
||||
gui_entry_insert_char(active_entry, key);
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* combo not complete, ignore append_next_kill and yank_preceded */
|
||||
active_entry->append_next_kill = active_entry->previous_append_next_kill;
|
||||
active_entry->yank_preceded = previous_yank_preceded;
|
||||
}
|
||||
}
|
||||
|
||||
/* ret = 0 : some key create multiple characters - we're in the middle
|
||||
@ -547,7 +573,7 @@ static void key_forward_to_space(void)
|
||||
static void key_erase_line(void)
|
||||
{
|
||||
gui_entry_set_pos(active_entry, active_entry->text_len);
|
||||
gui_entry_erase(active_entry, active_entry->text_len, TRUE);
|
||||
gui_entry_erase(active_entry, active_entry->text_len, CUTBUFFER_UPDATE_REPLACE);
|
||||
}
|
||||
|
||||
static void key_erase_to_beg_of_line(void)
|
||||
@ -555,7 +581,7 @@ static void key_erase_to_beg_of_line(void)
|
||||
int pos;
|
||||
|
||||
pos = gui_entry_get_pos(active_entry);
|
||||
gui_entry_erase(active_entry, pos, TRUE);
|
||||
gui_entry_erase(active_entry, pos, CUTBUFFER_UPDATE_PREPEND);
|
||||
}
|
||||
|
||||
static void key_erase_to_end_of_line(void)
|
||||
@ -564,7 +590,7 @@ static void key_erase_to_end_of_line(void)
|
||||
|
||||
pos = gui_entry_get_pos(active_entry);
|
||||
gui_entry_set_pos(active_entry, active_entry->text_len);
|
||||
gui_entry_erase(active_entry, active_entry->text_len - pos, TRUE);
|
||||
gui_entry_erase(active_entry, active_entry->text_len - pos, CUTBUFFER_UPDATE_APPEND);
|
||||
}
|
||||
|
||||
static void key_yank_from_cutbuffer(void)
|
||||
@ -574,6 +600,35 @@ static void key_yank_from_cutbuffer(void)
|
||||
cutbuffer = gui_entry_get_cutbuffer(active_entry);
|
||||
if (cutbuffer != NULL) {
|
||||
gui_entry_insert_text(active_entry, cutbuffer);
|
||||
active_entry->yank_preceded = TRUE;
|
||||
g_free(cutbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void key_yank_next_cutbuffer(void)
|
||||
{
|
||||
GUI_ENTRY_CUTBUFFER_REC *rec;
|
||||
guint length = 0;
|
||||
char *cutbuffer;
|
||||
|
||||
if (!previous_yank_preceded) {
|
||||
if (settings_get_bool("bell_beeps")) {
|
||||
signal_emit("beep", 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (active_entry->kill_ring == NULL)
|
||||
return;
|
||||
|
||||
rec = active_entry->kill_ring->data;
|
||||
if (rec != NULL) length = rec->cutbuffer_len;
|
||||
|
||||
cutbuffer = gui_entry_get_next_cutbuffer(active_entry);
|
||||
if (cutbuffer != NULL) {
|
||||
gui_entry_erase(active_entry, length, CUTBUFFER_UPDATE_NOOP);
|
||||
gui_entry_insert_text(active_entry, cutbuffer);
|
||||
active_entry->yank_preceded = TRUE;
|
||||
g_free(cutbuffer);
|
||||
}
|
||||
}
|
||||
@ -611,34 +666,44 @@ static void key_delete_character(void)
|
||||
|
||||
static void key_backspace(void)
|
||||
{
|
||||
gui_entry_erase(active_entry, 1, FALSE);
|
||||
gui_entry_erase(active_entry, 1, CUTBUFFER_UPDATE_NOOP);
|
||||
}
|
||||
|
||||
static void key_delete_previous_word(void)
|
||||
{
|
||||
gui_entry_erase_word(active_entry, FALSE);
|
||||
gui_entry_erase_word(active_entry, FALSE, CUTBUFFER_UPDATE_PREPEND);
|
||||
}
|
||||
|
||||
static void key_delete_next_word(void)
|
||||
{
|
||||
gui_entry_erase_next_word(active_entry, FALSE);
|
||||
gui_entry_erase_next_word(active_entry, FALSE, CUTBUFFER_UPDATE_APPEND);
|
||||
}
|
||||
|
||||
static void key_delete_to_previous_space(void)
|
||||
{
|
||||
gui_entry_erase_word(active_entry, TRUE);
|
||||
gui_entry_erase_word(active_entry, TRUE, CUTBUFFER_UPDATE_PREPEND);
|
||||
}
|
||||
|
||||
static void key_delete_to_next_space(void)
|
||||
{
|
||||
gui_entry_erase_next_word(active_entry, TRUE);
|
||||
gui_entry_erase_next_word(active_entry, TRUE, CUTBUFFER_UPDATE_APPEND);
|
||||
}
|
||||
|
||||
static void key_append_next_kill(void)
|
||||
{
|
||||
active_entry->append_next_kill = TRUE;
|
||||
}
|
||||
|
||||
static gboolean paste_timeout(gpointer data)
|
||||
{
|
||||
int split_lines;
|
||||
paste_was_bracketed_mode = paste_bracketed_mode;
|
||||
|
||||
if (paste_line_count == 0) {
|
||||
/* number of lines after splitting extra-long messages */
|
||||
split_lines = paste_buffer->len / LINE_SPLIT_LIMIT;
|
||||
|
||||
/* Take into account the fact that a line may be split every LINE_SPLIT_LIMIT characters */
|
||||
if (paste_line_count == 0 && split_lines <= paste_verify_line_count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < paste_buffer->len; i++) {
|
||||
@ -647,7 +712,8 @@ static gboolean paste_timeout(gpointer data)
|
||||
}
|
||||
g_array_set_size(paste_buffer, 0);
|
||||
} else if (paste_verify_line_count > 0 &&
|
||||
paste_line_count >= paste_verify_line_count &&
|
||||
(paste_line_count >= paste_verify_line_count ||
|
||||
split_lines > paste_verify_line_count) &&
|
||||
active_win->active != NULL)
|
||||
insert_paste_prompt();
|
||||
else
|
||||
@ -1170,6 +1236,8 @@ void gui_readline_init(void)
|
||||
key_bind("erase_to_beg_of_line", "Erase everything before the cursor", NULL, NULL, (SIGNAL_FUNC) key_erase_to_beg_of_line);
|
||||
key_bind("erase_to_end_of_line", "Erase everything after the cursor", "^K", NULL, (SIGNAL_FUNC) key_erase_to_end_of_line);
|
||||
key_bind("yank_from_cutbuffer", "\"Undelete\", paste the last deleted text", "^Y", NULL, (SIGNAL_FUNC) key_yank_from_cutbuffer);
|
||||
key_bind("yank_next_cutbuffer", "Revert to the previous last deleted text", NULL, NULL, (SIGNAL_FUNC) key_yank_next_cutbuffer);
|
||||
key_bind("append_next_kill", "Append next deletion", NULL, NULL, (SIGNAL_FUNC) key_append_next_kill);
|
||||
key_bind("transpose_characters", "Swap current and previous character", "^T", NULL, (SIGNAL_FUNC) key_transpose_characters);
|
||||
key_bind("transpose_words", "Swap current and previous word", NULL, NULL, (SIGNAL_FUNC) key_transpose_words);
|
||||
key_bind("capitalize_word", "Capitalize the current word", NULL, NULL, (SIGNAL_FUNC) key_capitalize_word);
|
||||
@ -1259,6 +1327,8 @@ void gui_readline_deinit(void)
|
||||
key_unbind("erase_to_beg_of_line", (SIGNAL_FUNC) key_erase_to_beg_of_line);
|
||||
key_unbind("erase_to_end_of_line", (SIGNAL_FUNC) key_erase_to_end_of_line);
|
||||
key_unbind("yank_from_cutbuffer", (SIGNAL_FUNC) key_yank_from_cutbuffer);
|
||||
key_unbind("yank_next_cutbuffer", (SIGNAL_FUNC) key_yank_next_cutbuffer);
|
||||
key_unbind("append_next_kill", (SIGNAL_FUNC) key_append_next_kill);
|
||||
key_unbind("transpose_characters", (SIGNAL_FUNC) key_transpose_characters);
|
||||
key_unbind("transpose_words", (SIGNAL_FUNC) key_transpose_words);
|
||||
|
||||
|
@ -74,10 +74,7 @@ void mainwindow_activity_deinit(void);
|
||||
void mainwindows_layout_init(void);
|
||||
void mainwindows_layout_deinit(void);
|
||||
|
||||
void term_dummy_init(void);
|
||||
void term_dummy_deinit(void);
|
||||
|
||||
static int dirty, full_redraw, dummy;
|
||||
static int dirty, full_redraw;
|
||||
|
||||
static GMainLoop *main_loop;
|
||||
int quitting;
|
||||
@ -122,7 +119,7 @@ void irssi_set_dirty(void)
|
||||
|
||||
static void dirty_check(void)
|
||||
{
|
||||
if (!dirty || dummy)
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
term_resize_dirty();
|
||||
@ -171,9 +168,6 @@ static void textui_finish_init(void)
|
||||
{
|
||||
quitting = FALSE;
|
||||
|
||||
if (dummy)
|
||||
term_dummy_init();
|
||||
else {
|
||||
term_refresh_freeze();
|
||||
textbuffer_init();
|
||||
textbuffer_view_init();
|
||||
@ -189,9 +183,7 @@ static void textui_finish_init(void)
|
||||
statusbar_init();
|
||||
term_refresh_thaw();
|
||||
|
||||
/* don't check settings with dummy mode */
|
||||
settings_check();
|
||||
}
|
||||
|
||||
module_register("core", "fe-text");
|
||||
|
||||
@ -233,9 +225,6 @@ static void textui_deinit(void)
|
||||
dirty_check(); /* one last time to print any quit messages */
|
||||
signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
|
||||
|
||||
if (dummy)
|
||||
term_dummy_deinit();
|
||||
else {
|
||||
lastlog_deinit();
|
||||
statusbar_deinit();
|
||||
gui_printtext_deinit();
|
||||
@ -251,7 +240,6 @@ static void textui_deinit(void)
|
||||
|
||||
term_refresh_thaw();
|
||||
term_deinit();
|
||||
}
|
||||
|
||||
theme_unregister();
|
||||
|
||||
@ -276,7 +264,6 @@ int main(int argc, char **argv)
|
||||
{
|
||||
static int version = 0;
|
||||
static GOptionEntry options[] = {
|
||||
{ "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, "Use the dummy terminal mode", NULL },
|
||||
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display irssi version", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
@ -295,7 +282,6 @@ int main(int argc, char **argv)
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
dummy = FALSE;
|
||||
quitting = FALSE;
|
||||
core_preinit(argv[0]);
|
||||
|
||||
@ -319,9 +305,8 @@ int main(int argc, char **argv)
|
||||
loglev = g_log_set_always_fatal(G_LOG_FATAL_MASK | G_LOG_LEVEL_CRITICAL);
|
||||
textui_init();
|
||||
|
||||
if (!dummy && !term_init()) {
|
||||
fprintf(stderr, "Can't initialize screen handling, quitting.\n");
|
||||
fprintf(stderr, "You can still use the dummy mode with -d parameter\n");
|
||||
if (!term_init()) {
|
||||
fprintf(stderr, "Can't initialize screen handling.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -332,9 +317,9 @@ int main(int argc, char **argv)
|
||||
/* Does the same as g_main_run(main_loop), except we
|
||||
can call our dirty-checker after each iteration */
|
||||
while (!quitting) {
|
||||
if (!dummy) term_refresh_freeze();
|
||||
term_refresh_freeze();
|
||||
g_main_iteration(TRUE);
|
||||
if (!dummy) term_refresh_thaw();
|
||||
term_refresh_thaw();
|
||||
|
||||
if (reload_config) {
|
||||
/* SIGHUP received, do /RELOAD */
|
||||
|
@ -39,21 +39,10 @@
|
||||
Returns -1 if unknown option was given. */
|
||||
int cmd_options_get_level(const char *cmd, GHashTable *optlist)
|
||||
{
|
||||
GSList *list, *tmp, *next;
|
||||
GList *list;
|
||||
int level, retlevel;
|
||||
|
||||
/* get all the options, then remove the known ones. there should
|
||||
be only one left - the server tag. */
|
||||
list = hashtable_get_keys(optlist);
|
||||
if (cmd != NULL) {
|
||||
for (tmp = list; tmp != NULL; tmp = next) {
|
||||
char *option = tmp->data;
|
||||
next = tmp->next;
|
||||
|
||||
if (command_have_option(cmd, option))
|
||||
list = g_slist_remove(list, option);
|
||||
}
|
||||
}
|
||||
list = optlist_remove_known(cmd, optlist);
|
||||
|
||||
retlevel = 0;
|
||||
while (list != NULL) {
|
||||
@ -68,7 +57,7 @@ int cmd_options_get_level(const char *cmd, GHashTable *optlist)
|
||||
}
|
||||
|
||||
retlevel |= level;
|
||||
list = g_slist_remove(list, list->data);
|
||||
list = g_list_remove(list, list->data);
|
||||
}
|
||||
|
||||
return retlevel;
|
||||
|
@ -289,6 +289,10 @@ static void sig_statusbar_more_updated(void)
|
||||
{
|
||||
int visible;
|
||||
|
||||
/* no active window, for example during /window hide */
|
||||
if (active_win == NULL)
|
||||
return;
|
||||
|
||||
visible = g_slist_find(more_visible, WINDOW_MAIN(active_win)) != NULL;
|
||||
if (WINDOW_GUI(active_win)->view->more_text != visible)
|
||||
statusbar_items_redraw("more");
|
||||
|
@ -671,8 +671,8 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only,
|
||||
WI_ITEM_REC *wiitem;
|
||||
char *tmpstr, *tmpstr2;
|
||||
theme_rm_col reset;
|
||||
strcpy(reset.m, "n");
|
||||
int len;
|
||||
strcpy(reset.m, "n");
|
||||
|
||||
if (str == NULL)
|
||||
str = statusbar_item_get_value(item);
|
||||
|
@ -1,415 +0,0 @@
|
||||
/*
|
||||
term-curses.c : irssi
|
||||
|
||||
Copyright (C) 1999-2001 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "term.h"
|
||||
#include "mainwindows.h"
|
||||
|
||||
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
|
||||
# include <ncurses.h>
|
||||
#else
|
||||
# include <curses.h>
|
||||
#endif
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef COLOR_PAIRS
|
||||
# define COLOR_PAIRS 64
|
||||
#endif
|
||||
|
||||
#if defined (TIOCGWINSZ) && defined (HAVE_CURSES_RESIZETERM)
|
||||
# define USE_RESIZE_TERM
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_VDISABLE
|
||||
# define _POSIX_VDISABLE 0
|
||||
#endif
|
||||
|
||||
struct _TERM_WINDOW {
|
||||
int x, y;
|
||||
int width, height;
|
||||
WINDOW *win;
|
||||
};
|
||||
|
||||
TERM_WINDOW *root_window;
|
||||
|
||||
static int curs_x, curs_y;
|
||||
static int freeze_refresh;
|
||||
static struct termios old_tio;
|
||||
|
||||
static int init_curses(void)
|
||||
{
|
||||
char ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
int num;
|
||||
struct termios tio;
|
||||
|
||||
if (!initscr())
|
||||
return FALSE;
|
||||
|
||||
cbreak(); noecho(); idlok(stdscr, 1);
|
||||
#ifdef HAVE_CURSES_IDCOK
|
||||
/*idcok(stdscr, 1); - disabled currently, causes redrawing problems with NetBSD */
|
||||
#endif
|
||||
intrflush(stdscr, FALSE); nodelay(stdscr, TRUE);
|
||||
|
||||
/* Disable INTR, QUIT, VDSUSP and SUSP keys */
|
||||
if (tcgetattr(0, &old_tio) == 0) {
|
||||
memcpy(&tio, &old_tio, sizeof(tio));
|
||||
tio.c_cc[VINTR] = _POSIX_VDISABLE;
|
||||
tio.c_cc[VQUIT] = _POSIX_VDISABLE;
|
||||
#ifdef VDSUSP
|
||||
tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
|
||||
#endif
|
||||
#ifdef VSUSP
|
||||
tio.c_cc[VSUSP] = _POSIX_VDISABLE;
|
||||
#endif
|
||||
tcsetattr(0, TCSADRAIN, &tio);
|
||||
}
|
||||
|
||||
if (has_colors())
|
||||
start_color();
|
||||
else if (term_use_colors)
|
||||
term_use_colors = FALSE;
|
||||
|
||||
#ifdef HAVE_NCURSES_USE_DEFAULT_COLORS
|
||||
/* this lets us to use the "default" background color for colors <= 7 so
|
||||
background pixmaps etc. show up right */
|
||||
use_default_colors();
|
||||
|
||||
for (num = 1; num < COLOR_PAIRS; num++)
|
||||
init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]);
|
||||
|
||||
init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more
|
||||
people want dark grey than white on white.. */
|
||||
#else
|
||||
for (num = 1; num < COLOR_PAIRS; num++)
|
||||
init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]);
|
||||
init_pair(63, 0, 0);
|
||||
#endif
|
||||
|
||||
clear();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int term_init_int(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = init_curses();
|
||||
if (!ret) return 0;
|
||||
|
||||
curs_x = curs_y = 0;
|
||||
freeze_refresh = 0;
|
||||
|
||||
root_window = g_new0(TERM_WINDOW, 1);
|
||||
root_window->win = stdscr;
|
||||
|
||||
term_width = COLS;
|
||||
term_height = LINES;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void term_deinit_int(void)
|
||||
{
|
||||
tcsetattr(0, TCSADRAIN, &old_tio);
|
||||
|
||||
endwin();
|
||||
g_free_and_null(root_window);
|
||||
}
|
||||
|
||||
int term_init(void)
|
||||
{
|
||||
if (!term_init_int())
|
||||
return FALSE;
|
||||
|
||||
settings_add_int("lookandfeel", "default_color", 7);
|
||||
term_common_init();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void term_deinit(void)
|
||||
{
|
||||
term_common_deinit();
|
||||
term_deinit_int();
|
||||
}
|
||||
|
||||
/* Resize terminal - if width or height is negative,
|
||||
the new size is unknown and should be figured out somehow */
|
||||
void term_resize(int width, int height)
|
||||
{
|
||||
#ifdef HAVE_CURSES_RESIZETERM
|
||||
if (width < 0 || height < 0) {
|
||||
#endif
|
||||
term_deinit_int();
|
||||
term_init_int();
|
||||
#ifdef HAVE_CURSES_RESIZETERM
|
||||
} else if (term_width != width || term_height != height) {
|
||||
term_width = width;
|
||||
term_height = height;
|
||||
resizeterm(term_height, term_width);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void term_resize_final(int width, int height)
|
||||
{
|
||||
#ifdef HAVE_CURSES_RESIZETERM
|
||||
if (width < 0 || height < 0)
|
||||
mainwindows_recreate();
|
||||
#else
|
||||
mainwindows_recreate();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns TRUE if terminal has colors */
|
||||
int term_has_colors(void)
|
||||
{
|
||||
return has_colors();
|
||||
}
|
||||
|
||||
/* Force the colors on any way you can */
|
||||
void term_force_colors(int set)
|
||||
{
|
||||
/* don't do anything with curses */
|
||||
}
|
||||
|
||||
/* Clear screen */
|
||||
void term_clear(void)
|
||||
{
|
||||
term_set_color(root_window, 0);
|
||||
clear();
|
||||
}
|
||||
|
||||
/* Beep */
|
||||
void term_beep(void)
|
||||
{
|
||||
beep();
|
||||
}
|
||||
|
||||
/* Create a new window in terminal */
|
||||
TERM_WINDOW *term_window_create(int x, int y, int width, int height)
|
||||
{
|
||||
TERM_WINDOW *window;
|
||||
|
||||
window = g_new0(TERM_WINDOW, 1);
|
||||
window->x = x; window->y = y;
|
||||
window->width = width; window->height = height;
|
||||
window->win = newwin(height, width, y, x);
|
||||
if (window->win == NULL)
|
||||
g_error("newwin() failed: %d,%d %d,%d", x, y, width, height);
|
||||
idlok(window->win, 1);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/* Destroy a terminal window */
|
||||
void term_window_destroy(TERM_WINDOW *window)
|
||||
{
|
||||
delwin(window->win);
|
||||
g_free(window);
|
||||
}
|
||||
|
||||
/* Move/resize a window */
|
||||
void term_window_move(TERM_WINDOW *window, int x, int y,
|
||||
int width, int height)
|
||||
{
|
||||
/* some checks to make sure the window is visible in screen,
|
||||
otherwise curses could get nasty and not show our window anymore. */
|
||||
if (width < 1) width = 1;
|
||||
if (height < 1) height = 1;
|
||||
if (x+width > term_width) x = term_width-width;
|
||||
if (y+height > term_height) y = term_height-height;
|
||||
|
||||
#ifdef HAVE_CURSES_WRESIZE
|
||||
if (window->width != width || window->height != height)
|
||||
wresize(window->win, height, width);
|
||||
if (window->x != x || window->y != y)
|
||||
mvwin(window->win, y, x);
|
||||
#else
|
||||
if (window->width != width || window->height != height ||
|
||||
window->x != x || window->y != y) {
|
||||
delwin(window->win);
|
||||
window->win = newwin(height, width, y, x);
|
||||
idlok(window->win, 1);
|
||||
}
|
||||
#endif
|
||||
window->x = x; window->y = y;
|
||||
window->width = width; window->height = height;
|
||||
}
|
||||
|
||||
/* Clear window */
|
||||
void term_window_clear(TERM_WINDOW *window)
|
||||
{
|
||||
werase(window->win);
|
||||
}
|
||||
|
||||
/* Scroll window up/down */
|
||||
void term_window_scroll(TERM_WINDOW *window, int count)
|
||||
{
|
||||
scrollok(window->win, TRUE);
|
||||
wscrl(window->win, count);
|
||||
scrollok(window->win, FALSE);
|
||||
}
|
||||
|
||||
static int get_attr(int color)
|
||||
{
|
||||
int attr;
|
||||
|
||||
if ((color & FG_MASK) >> 4)
|
||||
color = (color & ~FG_MASK) | term_color256map[color & FG_MASK];
|
||||
if ((color & BG_MASK) >> (BG_SHIFT + 4))
|
||||
color = (color & ~BG_MASK) | (term_color256map[(color & BG_MASK) >> BG_SHIFT] << BG_SHIFT);
|
||||
if (!term_use_colors)
|
||||
attr = (color & (0x7 << BG_SHIFT)) ? A_REVERSE : 0;
|
||||
else if ((color & ((0xf << BG_SHIFT) | 0xf)) == 8 || (color & (FG_MASK | BG_MASK | ATTR_RESETFG)) == 0)
|
||||
attr = COLOR_PAIR(63);
|
||||
else if ((color & ((0x7 << BG_SHIFT) | 0x7)) == 0)
|
||||
attr = A_NORMAL;
|
||||
else {
|
||||
if (color & ATTR_RESETFG) {
|
||||
color &= ~FG_MASK;
|
||||
color |= settings_get_int("default_color");
|
||||
}
|
||||
attr = COLOR_PAIR((color&0x7) | ((color&(0x7<<BG_SHIFT))>>BG_SHIFT<<3));
|
||||
}
|
||||
|
||||
if ((color & 0x8) || (color & ATTR_BOLD)) attr |= A_BOLD;
|
||||
if (color & ATTR_BLINK) attr |= A_BLINK;
|
||||
|
||||
if (color & ATTR_UNDERLINE) attr |= A_UNDERLINE;
|
||||
if (color & ATTR_REVERSE) attr |= A_REVERSE;
|
||||
#ifdef A_ITALIC
|
||||
if (color & ATTR_ITALIC) attr |= A_ITALIC;
|
||||
#endif
|
||||
return attr;
|
||||
}
|
||||
|
||||
/* Change active color */
|
||||
void term_set_color(TERM_WINDOW *window, int col)
|
||||
{
|
||||
wattrset(window->win, get_attr(col));
|
||||
wbkgdset(window->win, ' ' | get_attr(col));
|
||||
}
|
||||
|
||||
void term_move(TERM_WINDOW *window, int x, int y)
|
||||
{
|
||||
wmove(window->win, y, x);
|
||||
}
|
||||
|
||||
void term_addch(TERM_WINDOW *window, char chr)
|
||||
{
|
||||
waddch(window->win, chr);
|
||||
}
|
||||
|
||||
void term_add_unichar(TERM_WINDOW *window, unichar chr)
|
||||
{
|
||||
#ifdef WIDEC_CURSES
|
||||
cchar_t wch;
|
||||
wchar_t temp[2];
|
||||
temp[0] = chr;
|
||||
temp[1] = 0;
|
||||
if (setcchar(&wch, temp, A_NORMAL, 0, NULL) == OK)
|
||||
wadd_wch(window->win, &wch);
|
||||
else
|
||||
#endif
|
||||
waddch(window->win, chr);
|
||||
}
|
||||
|
||||
void term_addstr(TERM_WINDOW *window, const char *str)
|
||||
{
|
||||
waddstr(window->win, (const char *) str);
|
||||
}
|
||||
|
||||
void term_clrtoeol(TERM_WINDOW *window)
|
||||
{
|
||||
wclrtoeol(window->win);
|
||||
}
|
||||
|
||||
void term_move_cursor(int x, int y)
|
||||
{
|
||||
curs_x = x;
|
||||
curs_y = y;
|
||||
}
|
||||
|
||||
void term_refresh_freeze(void)
|
||||
{
|
||||
freeze_refresh++;
|
||||
}
|
||||
|
||||
void term_refresh_thaw(void)
|
||||
{
|
||||
if (freeze_refresh > 0) {
|
||||
freeze_refresh--;
|
||||
if (freeze_refresh == 0) term_refresh(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void term_refresh(TERM_WINDOW *window)
|
||||
{
|
||||
if (window != NULL)
|
||||
wnoutrefresh(window->win);
|
||||
|
||||
if (freeze_refresh == 0) {
|
||||
move(curs_y, curs_x);
|
||||
wnoutrefresh(stdscr);
|
||||
doupdate();
|
||||
}
|
||||
}
|
||||
|
||||
void term_stop(void)
|
||||
{
|
||||
term_deinit_int();
|
||||
kill(getpid(), SIGTSTP);
|
||||
term_init_int();
|
||||
irssi_redraw();
|
||||
}
|
||||
|
||||
void term_set_input_type(int type)
|
||||
{
|
||||
}
|
||||
|
||||
void term_gets(GArray *buffer, int *line_count)
|
||||
{
|
||||
#ifdef WIDEC_CURSES
|
||||
wint_t key;
|
||||
#else
|
||||
int key;
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
#ifdef WIDEC_CURSES
|
||||
if (get_wch(&key) == ERR)
|
||||
#else
|
||||
if ((key = getch()) == ERR)
|
||||
#endif
|
||||
break;
|
||||
#ifdef KEY_RESIZE
|
||||
if (key == KEY_RESIZE)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
g_array_append_val(buffer, key);
|
||||
if (key == '\r' || key == '\n')
|
||||
(*line_count)++;
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
term-dummy.c : irssi
|
||||
|
||||
Copyright (C) 2001 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "fe-windows.h"
|
||||
|
||||
static int newline;
|
||||
|
||||
static GIOChannel *stdin_channel;
|
||||
static int readtag;
|
||||
static GString *input;
|
||||
|
||||
static void sig_gui_printtext(WINDOW_REC *window, void *fgcolor,
|
||||
void *bgcolor, void *pflags,
|
||||
char *str, void *level)
|
||||
{
|
||||
if (newline) {
|
||||
newline = FALSE;
|
||||
printf("\r");
|
||||
}
|
||||
|
||||
printf("%s", str);
|
||||
}
|
||||
|
||||
static void sig_gui_printtext_finished(WINDOW_REC *window)
|
||||
{
|
||||
printf("\n");
|
||||
newline = TRUE;
|
||||
}
|
||||
|
||||
static void sig_window_created(WINDOW_REC *window)
|
||||
{
|
||||
window->width = 80;
|
||||
window->height = 25;
|
||||
}
|
||||
|
||||
static void readline(void)
|
||||
{
|
||||
unsigned char buffer[128];
|
||||
char *p;
|
||||
int ret, i;
|
||||
|
||||
ret = read(0, buffer, sizeof(buffer));
|
||||
if (ret == 0 || (ret == -1 && errno != EINTR)) {
|
||||
/* lost terminal */
|
||||
signal_emit("command quit", 1, "Lost terminal");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ret; i++)
|
||||
g_string_append_c(input, buffer[i]);
|
||||
|
||||
p = strchr(input->str, '\n');
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
signal_emit("send command", 3, input->str,
|
||||
active_win->active_server, active_win->active);
|
||||
*p = '\n';
|
||||
g_string_erase(input, 0, (int) (p-input->str)+1);
|
||||
}
|
||||
}
|
||||
|
||||
void term_dummy_init(void)
|
||||
{
|
||||
newline = TRUE;
|
||||
input = g_string_new(NULL);
|
||||
|
||||
signal_add("gui print text", (SIGNAL_FUNC) sig_gui_printtext);
|
||||
signal_add("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
|
||||
signal_add("window created", (SIGNAL_FUNC) sig_window_created);
|
||||
|
||||
stdin_channel = g_io_channel_unix_new(0);
|
||||
readtag = g_input_add_full(stdin_channel,
|
||||
G_PRIORITY_HIGH, G_INPUT_READ,
|
||||
(GInputFunction) readline, NULL);
|
||||
g_io_channel_unref(stdin_channel);
|
||||
}
|
||||
|
||||
void term_dummy_deinit(void)
|
||||
{
|
||||
signal_remove("gui print text", (SIGNAL_FUNC) sig_gui_printtext);
|
||||
signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
|
||||
signal_remove("window created", (SIGNAL_FUNC) sig_window_created);
|
||||
|
||||
g_source_remove(readtag);
|
||||
g_string_free(input, TRUE);
|
||||
}
|
@ -611,8 +611,6 @@ void term_stop(void)
|
||||
{
|
||||
terminfo_stop(current_term);
|
||||
kill(getpid(), SIGTSTP);
|
||||
terminfo_cont(current_term);
|
||||
irssi_redraw();
|
||||
}
|
||||
|
||||
static int input_utf8(const unsigned char *buffer, int size, unichar *result)
|
||||
|
@ -27,7 +27,7 @@ typedef struct _TERM_WINDOW TERM_WINDOW;
|
||||
#define TERM_TYPE_UTF8 1
|
||||
#define TERM_TYPE_BIG5 2
|
||||
|
||||
typedef guint32 unichar;
|
||||
#include "utf8.h"
|
||||
|
||||
extern TERM_WINDOW *root_window;
|
||||
extern int term_width, term_height;
|
||||
|
@ -17,7 +17,6 @@ inline static int term_putchar(int c)
|
||||
char *tparm();
|
||||
int tputs();
|
||||
|
||||
#ifdef HAVE_TERMINFO
|
||||
int setupterm();
|
||||
char *tigetstr();
|
||||
int tigetnum();
|
||||
@ -25,15 +24,6 @@ int tigetflag();
|
||||
#define term_getstr(x, buffer) tigetstr(x.ti_name)
|
||||
#define term_getnum(x) tigetnum(x.ti_name);
|
||||
#define term_getflag(x) tigetflag(x.ti_name);
|
||||
#else
|
||||
int tgetent();
|
||||
char *tgetstr();
|
||||
int tgetnum();
|
||||
int tgetflag();
|
||||
#define term_getstr(x, buffer) tgetstr(x.tc_name, &buffer)
|
||||
#define term_getnum(x) tgetnum(x.tc_name)
|
||||
#define term_getflag(x) tgetflag(x.tc_name)
|
||||
#endif
|
||||
|
||||
#define CAP_TYPE_FLAG 0
|
||||
#define CAP_TYPE_INT 1
|
||||
@ -415,9 +405,6 @@ static void term_fill_capabilities(TERM_REC *term)
|
||||
char *sval;
|
||||
void *ptr;
|
||||
|
||||
#ifndef HAVE_TERMINFO
|
||||
char *tptr = term->buffer2;
|
||||
#endif
|
||||
for (i = 0; i < sizeof(tcaps)/sizeof(tcaps[0]); i++) {
|
||||
ptr = G_STRUCT_MEMBER_P(term, tcaps[i].offset);
|
||||
|
||||
@ -583,9 +570,7 @@ void terminfo_stop(TERM_REC *term)
|
||||
static int term_setup(TERM_REC *term)
|
||||
{
|
||||
GString *str;
|
||||
#ifdef HAVE_TERMINFO
|
||||
int err;
|
||||
#endif
|
||||
char *term_env;
|
||||
|
||||
term_env = getenv("TERM");
|
||||
@ -594,18 +579,10 @@ static int term_setup(TERM_REC *term)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TERMINFO
|
||||
if (setupterm(term_env, 1, &err) != 0) {
|
||||
fprintf(stderr, "setupterm() failed for TERM=%s: %d\n", term_env, err);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (tgetent(term->buffer1, term_env) < 1)
|
||||
{
|
||||
fprintf(stderr, "Termcap not found for TERM=%s\n", term_env);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
term_fill_capabilities(term);
|
||||
|
||||
|
@ -1,740 +0,0 @@
|
||||
/*
|
||||
* tparm.c
|
||||
*
|
||||
* By Ross Ridge
|
||||
* Public Domain
|
||||
* 92/02/01 07:30:36
|
||||
*
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MAX_PUSHED
|
||||
#define MAX_PUSHED 32
|
||||
#endif
|
||||
|
||||
#define ARG 1
|
||||
#define NUM 2
|
||||
|
||||
#define INTEGER 1
|
||||
#define STRING 2
|
||||
|
||||
#define MAX_LINE 640
|
||||
|
||||
typedef void* anyptr;
|
||||
|
||||
typedef struct stack_str {
|
||||
int type;
|
||||
int argnum;
|
||||
int value;
|
||||
} stack;
|
||||
|
||||
static stack S[MAX_PUSHED];
|
||||
static stack vars['z'-'a'+1];
|
||||
static int pos = 0;
|
||||
|
||||
static struct arg_str {
|
||||
int type;
|
||||
int integer;
|
||||
char *string;
|
||||
} arg_list[10];
|
||||
|
||||
static int argcnt;
|
||||
|
||||
static va_list tparm_args;
|
||||
|
||||
static int pusharg(int arg)
|
||||
{
|
||||
if (pos == MAX_PUSHED)
|
||||
return 1;
|
||||
S[pos].type = ARG;
|
||||
S[pos++].argnum = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pushnum(int num)
|
||||
{
|
||||
if (pos == MAX_PUSHED)
|
||||
return 1;
|
||||
S[pos].type = NUM;
|
||||
S[pos++].value = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VARARGS2 */
|
||||
static int getarg(int argnum, int type, anyptr p)
|
||||
{
|
||||
while (argcnt < argnum) {
|
||||
arg_list[argcnt].type = INTEGER;
|
||||
arg_list[argcnt++].integer = (int) va_arg(tparm_args, int);
|
||||
}
|
||||
if (argcnt > argnum) {
|
||||
if (arg_list[argnum].type != type)
|
||||
return 1;
|
||||
else if (type == STRING)
|
||||
*(char **)p = arg_list[argnum].string;
|
||||
else
|
||||
*(int *)p = arg_list[argnum].integer;
|
||||
} else {
|
||||
arg_list[argcnt].type = type;
|
||||
if (type == STRING)
|
||||
*(char **)p = arg_list[argcnt++].string
|
||||
= (char *) va_arg(tparm_args, char *);
|
||||
else
|
||||
*(int *)p = arg_list[argcnt++].integer = (int) va_arg(tparm_args, int);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int popstring(char **str)
|
||||
{
|
||||
if (pos-- == 0)
|
||||
return 1;
|
||||
if (S[pos].type != ARG)
|
||||
return 1;
|
||||
return(getarg(S[pos].argnum, STRING, (anyptr) str));
|
||||
}
|
||||
|
||||
static int popnum(int *num)
|
||||
{
|
||||
if (pos-- == 0)
|
||||
return 1;
|
||||
switch (S[pos].type) {
|
||||
case ARG:
|
||||
return (getarg(S[pos].argnum, INTEGER, (anyptr) num));
|
||||
case NUM:
|
||||
*num = S[pos].value;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cvtchar(const char *sp, char *c)
|
||||
{
|
||||
switch(*sp) {
|
||||
case '\\':
|
||||
switch(*++sp) {
|
||||
case '\'':
|
||||
case '$':
|
||||
case '\\':
|
||||
case '%':
|
||||
*c = *sp;
|
||||
return 2;
|
||||
case '\0':
|
||||
*c = '\\';
|
||||
return 1;
|
||||
case '0':
|
||||
if (sp[1] == '0' && sp[2] == '0') {
|
||||
*c = '\0';
|
||||
return 4;
|
||||
}
|
||||
*c = '\200'; /* '\0' ???? */
|
||||
return 2;
|
||||
default:
|
||||
*c = *sp;
|
||||
return 2;
|
||||
}
|
||||
default:
|
||||
*c = *sp;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int termcap;
|
||||
|
||||
/* sigh... this has got to be the ugliest code I've ever written.
|
||||
Trying to handle everything has its cost, I guess.
|
||||
|
||||
It actually isn't to hard to figure out if a given % code is supposed
|
||||
to be interpeted with its termcap or terminfo meaning since almost
|
||||
all terminfo codes are invalid unless something has been pushed on
|
||||
the stack and termcap strings will never push things on the stack
|
||||
(%p isn't used by termcap). So where we have a choice we make the
|
||||
decision by whether or not somthing has been pushed on the stack.
|
||||
The static variable termcap keeps track of this; it starts out set
|
||||
to 1 and is incremented as each argument processed by a termcap % code,
|
||||
however if something is pushed on the stack it's set to 0 and the
|
||||
rest of the % codes are interpeted as terminfo % codes. Another way
|
||||
of putting it is that if termcap equals one we haven't decided either
|
||||
way yet, if it equals zero we're looking for terminfo codes, and if
|
||||
its greater than 1 we're looking for termcap codes.
|
||||
|
||||
Terminfo % codes:
|
||||
|
||||
%% output a '%'
|
||||
%[[:][-+# ][width][.precision]][doxXs]
|
||||
output pop according to the printf format
|
||||
%c output pop as a char
|
||||
%'c' push character constant c.
|
||||
%{n} push decimal constant n.
|
||||
%p[1-9] push parameter [1-9]
|
||||
%g[a-z] push variable [a-z]
|
||||
%P[a-z] put pop in variable [a-z]
|
||||
%l push the length of pop (a string)
|
||||
%+ add pop to pop and push the result
|
||||
%- subtract pop from pop and push the result
|
||||
%* multiply pop and pop and push the result
|
||||
%& bitwise and pop and pop and push the result
|
||||
%| bitwise or pop and pop and push the result
|
||||
%^ bitwise xor pop and pop and push the result
|
||||
%~ push the bitwise not of pop
|
||||
%= compare if pop and pop are equal and push the result
|
||||
%> compare if pop is less than pop and push the result
|
||||
%< compare if pop is greater than pop and push the result
|
||||
%A logical and pop and pop and push the result
|
||||
%O logical or pop and pop and push the result
|
||||
%! push the logical not of pop
|
||||
%? condition %t if_true [%e if_false] %;
|
||||
if condition evaulates as true then evaluate if_true,
|
||||
else evaluate if_false. elseif's can be done:
|
||||
%? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %;
|
||||
%i add one to parameters 1 and 2. (ANSI)
|
||||
|
||||
Termcap Codes:
|
||||
|
||||
%% output a %
|
||||
%. output parameter as a character
|
||||
%d output parameter as a decimal number
|
||||
%2 output parameter in printf format %02d
|
||||
%3 output parameter in printf format %03d
|
||||
%+x add the character x to parameter and output it as a character
|
||||
(UW) %-x subtract parameter FROM the character x and output it as a char
|
||||
(UW) %ax add the character x to parameter
|
||||
(GNU) %a[+*-/=][cp]x
|
||||
GNU arithmetic.
|
||||
(UW) %sx subtract parameter FROM the character x
|
||||
%>xy if parameter > character x then add character y to parameter
|
||||
%B convert to BCD (parameter = (parameter/10)*16 + parameter%16)
|
||||
%D Delta Data encode (parameter = parameter - 2*(parameter%16))
|
||||
%i increment the first two parameters by one
|
||||
%n xor the first two parameters by 0140
|
||||
(GNU) %m xor the first two parameters by 0177
|
||||
%r swap the first two parameters
|
||||
(GNU) %b backup to previous parameter
|
||||
(GNU) %f skip this parameter
|
||||
|
||||
Note the two definitions of %a, the GNU definition is used if the characters
|
||||
after the 'a' are valid, otherwise the UW definition is used.
|
||||
|
||||
(GNU) used by GNU Emacs termcap libraries
|
||||
(UW) used by the University of Waterloo (MFCF) termcap libraries
|
||||
|
||||
*/
|
||||
|
||||
char *tparm(const char *str, ...) {
|
||||
static char OOPS[] = "OOPS";
|
||||
static char buf[MAX_LINE];
|
||||
register const char *sp;
|
||||
register char *dp;
|
||||
register char *fmt;
|
||||
char conv_char;
|
||||
char scan_for;
|
||||
int scan_depth = 0, if_depth;
|
||||
static int i, j;
|
||||
static char *s, c;
|
||||
char fmt_buf[MAX_LINE];
|
||||
char sbuf[MAX_LINE];
|
||||
|
||||
va_start(tparm_args, str);
|
||||
|
||||
sp = str;
|
||||
dp = buf;
|
||||
scan_for = 0;
|
||||
if_depth = 0;
|
||||
argcnt = 0;
|
||||
pos = 0;
|
||||
termcap = 1;
|
||||
while (*sp != '\0') {
|
||||
switch(*sp) {
|
||||
case '\\':
|
||||
if (scan_for) {
|
||||
if (*++sp != '\0')
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
*dp++ = *sp++;
|
||||
if (*sp != '\0')
|
||||
*dp++ = *sp++;
|
||||
break;
|
||||
case '%':
|
||||
sp++;
|
||||
if (scan_for) {
|
||||
if (*sp == scan_for && if_depth == scan_depth) {
|
||||
if (scan_for == ';')
|
||||
if_depth--;
|
||||
scan_for = 0;
|
||||
} else if (*sp == '?')
|
||||
if_depth++;
|
||||
else if (*sp == ';') {
|
||||
if (if_depth == 0)
|
||||
return OOPS;
|
||||
else
|
||||
if_depth--;
|
||||
}
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
fmt = NULL;
|
||||
switch(*sp) {
|
||||
case '%':
|
||||
*dp++ = *sp++;
|
||||
break;
|
||||
case '+':
|
||||
if (!termcap) {
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i += j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
;/* FALLTHROUGH */
|
||||
case 'C':
|
||||
if (*sp == 'C') {
|
||||
if (getarg(termcap - 1, INTEGER, &i))
|
||||
return OOPS;
|
||||
if (i >= 96) {
|
||||
i /= 96;
|
||||
if (i == '$')
|
||||
*dp++ = '\\';
|
||||
*dp++ = i;
|
||||
}
|
||||
}
|
||||
fmt = "%c";
|
||||
/* FALLTHROUGH */
|
||||
case 'a':
|
||||
if (!termcap)
|
||||
return OOPS;
|
||||
if (getarg(termcap - 1, INTEGER, (anyptr) &i))
|
||||
return OOPS;
|
||||
if (*++sp == '\0')
|
||||
return OOPS;
|
||||
if ((sp[1] == 'p' || sp[1] == 'c')
|
||||
&& sp[2] != '\0' && fmt == NULL) {
|
||||
/* GNU aritmitic parameter, what they
|
||||
really need is terminfo. */
|
||||
int val, lc;
|
||||
if (sp[1] == 'p'
|
||||
&& getarg(termcap - 1 + sp[2] - '@',
|
||||
INTEGER, (anyptr) &val))
|
||||
return OOPS;
|
||||
if (sp[1] == 'c') {
|
||||
lc = cvtchar(sp + 2, &c) + 2;
|
||||
/* Mask out 8th bit so \200 can be
|
||||
used for \0 as per GNU doc's */
|
||||
val = c & 0177;
|
||||
} else
|
||||
lc = 2;
|
||||
switch(sp[0]) {
|
||||
case '=':
|
||||
break;
|
||||
case '+':
|
||||
val = i + val;
|
||||
break;
|
||||
case '-':
|
||||
val = i - val;
|
||||
break;
|
||||
case '*':
|
||||
val = i * val;
|
||||
break;
|
||||
case '/':
|
||||
val = i / val;
|
||||
break;
|
||||
default:
|
||||
/* Not really GNU's %a after all... */
|
||||
lc = cvtchar(sp, &c);
|
||||
val = c + i;
|
||||
break;
|
||||
}
|
||||
arg_list[termcap - 1].integer = val;
|
||||
sp += lc;
|
||||
break;
|
||||
}
|
||||
sp += cvtchar(sp, &c);
|
||||
arg_list[termcap - 1].integer = c + i;
|
||||
if (fmt == NULL)
|
||||
break;
|
||||
sp--;
|
||||
/* FALLTHROUGH */
|
||||
case '-':
|
||||
if (!termcap) {
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i -= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
fmt = "%c";
|
||||
/* FALLTHROUGH */
|
||||
case 's':
|
||||
if (termcap && (fmt == NULL || *sp == '-')) {
|
||||
if (getarg(termcap - 1, INTEGER, &i))
|
||||
return OOPS;
|
||||
if (*++sp == '\0')
|
||||
return OOPS;
|
||||
sp += cvtchar(sp, &c);
|
||||
arg_list[termcap - 1].integer = c - i;
|
||||
if (fmt == NULL)
|
||||
break;
|
||||
sp--;
|
||||
}
|
||||
if (!termcap)
|
||||
return OOPS;
|
||||
;/* FALLTHROUGH */
|
||||
case '.':
|
||||
if (termcap && fmt == NULL)
|
||||
fmt = "%c";
|
||||
;/* FALLTHROUGH */
|
||||
case 'd':
|
||||
if (termcap && fmt == NULL)
|
||||
fmt = "%d";
|
||||
;/* FALLTHROUGH */
|
||||
case '2':
|
||||
if (termcap && fmt == NULL)
|
||||
fmt = "%02d";
|
||||
;/* FALLTHROUGH */
|
||||
case '3':
|
||||
if (termcap && fmt == NULL)
|
||||
fmt = "%03d";
|
||||
;/* FALLTHROUGH */
|
||||
case ':': case ' ': case '#': case 'u':
|
||||
case 'x': case 'X': case 'o': case 'c':
|
||||
case '0': case '1': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
if (fmt == NULL) {
|
||||
if (termcap)
|
||||
return OOPS;
|
||||
if (*sp == ':')
|
||||
sp++;
|
||||
fmt = fmt_buf;
|
||||
*fmt++ = '%';
|
||||
while(*sp != 's' && *sp != 'x' && *sp != 'X' && *sp != 'd' && *sp != 'o' && *sp != 'c' && *sp != 'u') {
|
||||
if (*sp == '\0')
|
||||
return OOPS;
|
||||
*fmt++ = *sp++;
|
||||
}
|
||||
*fmt++ = *sp;
|
||||
*fmt = '\0';
|
||||
fmt = fmt_buf;
|
||||
}
|
||||
conv_char = fmt[strlen(fmt) - 1];
|
||||
if (conv_char == 's') {
|
||||
if (popstring(&s))
|
||||
return OOPS;
|
||||
sprintf(sbuf, fmt, s);
|
||||
} else {
|
||||
if (termcap) {
|
||||
if (getarg(termcap++ - 1,
|
||||
INTEGER, &i))
|
||||
return OOPS;
|
||||
} else
|
||||
if (popnum(&i))
|
||||
return OOPS;
|
||||
if (i == 0 && conv_char == 'c')
|
||||
*sbuf = 0;
|
||||
else
|
||||
sprintf(sbuf, fmt, i);
|
||||
}
|
||||
sp++;
|
||||
fmt = sbuf;
|
||||
while(*fmt != '\0') {
|
||||
if (*fmt == '$')
|
||||
*dp++ = '\\';
|
||||
*dp++ = *fmt++;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (!termcap || getarg(1, INTEGER, &i))
|
||||
return OOPS;
|
||||
arg_list[1].integer = arg_list[0].integer;
|
||||
arg_list[0].integer = i;
|
||||
sp++;
|
||||
break;
|
||||
case 'i':
|
||||
if (getarg(1, INTEGER, &i)
|
||||
|| arg_list[0].type != INTEGER)
|
||||
return OOPS;
|
||||
arg_list[1].integer++;
|
||||
arg_list[0].integer++;
|
||||
sp++;
|
||||
break;
|
||||
case 'n':
|
||||
if (!termcap || getarg(1, INTEGER, &i))
|
||||
return OOPS;
|
||||
arg_list[0].integer ^= 0140;
|
||||
arg_list[1].integer ^= 0140;
|
||||
sp++;
|
||||
break;
|
||||
case '>':
|
||||
if (!termcap) {
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i = (i > j);
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
if (getarg(termcap-1, INTEGER, &i))
|
||||
return OOPS;
|
||||
sp += cvtchar(sp, &c);
|
||||
if (i > c) {
|
||||
sp += cvtchar(sp, &c);
|
||||
arg_list[termcap-1].integer += c;
|
||||
} else
|
||||
sp += cvtchar(sp, &c);
|
||||
sp++;
|
||||
break;
|
||||
case 'B':
|
||||
if (!termcap || getarg(termcap-1, INTEGER, &i))
|
||||
return OOPS;
|
||||
arg_list[termcap-1].integer = 16*(i/10)+i%10;
|
||||
sp++;
|
||||
break;
|
||||
case 'D':
|
||||
if (!termcap || getarg(termcap-1, INTEGER, &i))
|
||||
return OOPS;
|
||||
arg_list[termcap-1].integer = i - 2 * (i % 16);
|
||||
sp++;
|
||||
break;
|
||||
case 'p':
|
||||
if (termcap > 1)
|
||||
return OOPS;
|
||||
if (*++sp == '\0')
|
||||
return OOPS;
|
||||
if (*sp == '0')
|
||||
i = 9;
|
||||
else
|
||||
i = *sp - '1';
|
||||
if (i < 0 || i > 9)
|
||||
return OOPS;
|
||||
if (pusharg(i))
|
||||
return OOPS;
|
||||
termcap = 0;
|
||||
sp++;
|
||||
break;
|
||||
case 'P':
|
||||
if (termcap || *++sp == '\0')
|
||||
return OOPS;
|
||||
i = *sp++ - 'a';
|
||||
if (i < 0 || i > 25)
|
||||
return OOPS;
|
||||
if (pos-- == 0)
|
||||
return OOPS;
|
||||
switch(vars[i].type = S[pos].type) {
|
||||
case ARG:
|
||||
vars[i].argnum = S[pos].argnum;
|
||||
break;
|
||||
case NUM:
|
||||
vars[i].value = S[pos].value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (termcap || *++sp == '\0')
|
||||
return OOPS;
|
||||
i = *sp++ - 'a';
|
||||
if (i < 0 || i > 25)
|
||||
return OOPS;
|
||||
switch(vars[i].type) {
|
||||
case ARG:
|
||||
if (pusharg(vars[i].argnum))
|
||||
return OOPS;
|
||||
break;
|
||||
case NUM:
|
||||
if (pushnum(vars[i].value))
|
||||
return OOPS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (termcap > 1)
|
||||
return OOPS;
|
||||
if (*++sp == '\0')
|
||||
return OOPS;
|
||||
sp += cvtchar(sp, &c);
|
||||
if (pushnum(c) || *sp++ != '\'')
|
||||
return OOPS;
|
||||
termcap = 0;
|
||||
break;
|
||||
case '{':
|
||||
if (termcap > 1)
|
||||
return OOPS;
|
||||
i = 0;
|
||||
sp++;
|
||||
while(isdigit((int) (unsigned char) *sp))
|
||||
i = 10 * i + *sp++ - '0';
|
||||
if (*sp++ != '}' || pushnum(i))
|
||||
return OOPS;
|
||||
termcap = 0;
|
||||
break;
|
||||
case 'l':
|
||||
if (termcap || popstring(&s))
|
||||
return OOPS;
|
||||
i = strlen(s);
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '*':
|
||||
if (termcap || popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i *= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '/':
|
||||
if (termcap || popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i /= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case 'm':
|
||||
if (termcap) {
|
||||
if (getarg(1, INTEGER, &i))
|
||||
return OOPS;
|
||||
arg_list[0].integer ^= 0177;
|
||||
arg_list[1].integer ^= 0177;
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i %= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '&':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i &= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '|':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i |= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '^':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i ^= j;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '=':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i = (i == j);
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '<':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i = (i < j);
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case 'A':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i = (i && j);
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case 'O':
|
||||
if (popnum(&j) || popnum(&i))
|
||||
return OOPS;
|
||||
i = (i || j);
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '!':
|
||||
if (popnum(&i))
|
||||
return OOPS;
|
||||
i = !i;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '~':
|
||||
if (popnum(&i))
|
||||
return OOPS;
|
||||
i = ~i;
|
||||
if (pushnum(i))
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case '?':
|
||||
if (termcap > 1)
|
||||
return OOPS;
|
||||
termcap = 0;
|
||||
if_depth++;
|
||||
sp++;
|
||||
break;
|
||||
case 't':
|
||||
if (popnum(&i) || if_depth == 0)
|
||||
return OOPS;
|
||||
if (!i) {
|
||||
scan_for = 'e';
|
||||
scan_depth = if_depth;
|
||||
}
|
||||
sp++;
|
||||
break;
|
||||
case 'e':
|
||||
if (if_depth == 0)
|
||||
return OOPS;
|
||||
scan_for = ';';
|
||||
scan_depth = if_depth;
|
||||
sp++;
|
||||
break;
|
||||
case ';':
|
||||
if (if_depth-- == 0)
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case 'b':
|
||||
if (--termcap < 1)
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
case 'f':
|
||||
if (!termcap++)
|
||||
return OOPS;
|
||||
sp++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (scan_for)
|
||||
sp++;
|
||||
else
|
||||
*dp++ = *sp++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(tparm_args);
|
||||
*dp = '\0';
|
||||
return buf;
|
||||
}
|
@ -24,10 +24,12 @@
|
||||
|
||||
void irc_channels_setup_init(void)
|
||||
{
|
||||
signal_add("channel wholist", (SIGNAL_FUNC) channel_send_autocommands);
|
||||
signal_add("channel wholist", (SIGNAL_FUNC) channel_send_botcommands);
|
||||
signal_add("channel joined", (SIGNAL_FUNC) channel_send_autocommands);
|
||||
}
|
||||
|
||||
void irc_channels_setup_deinit(void)
|
||||
{
|
||||
signal_remove("channel wholist", (SIGNAL_FUNC) channel_send_autocommands);
|
||||
signal_remove("channel wholist", (SIGNAL_FUNC) channel_send_botcommands);
|
||||
signal_remove("channel joined", (SIGNAL_FUNC) channel_send_autocommands);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ NICK_REC *irc_nicklist_insert(IRC_CHANNEL_REC *channel, const char *nick,
|
||||
rec->send_massjoin = send_massjoin;
|
||||
|
||||
if (prefixes != NULL) {
|
||||
strocpy(rec->prefixes, prefixes, sizeof(rec->prefixes));
|
||||
g_strlcpy(rec->prefixes, prefixes, sizeof(rec->prefixes));
|
||||
}
|
||||
|
||||
nicklist_insert(CHANNEL(channel), rec);
|
||||
|
@ -214,7 +214,6 @@ static void server_init(IRC_SERVER_REC *server)
|
||||
{
|
||||
IRC_SERVER_CONNECT_REC *conn;
|
||||
char *address, *ptr, *username, *cmd;
|
||||
GTimeVal now;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
@ -289,9 +288,8 @@ static void server_init(IRC_SERVER_REC *server)
|
||||
|
||||
/* prevent the queue from sending too early, we have a max cut off of 120 secs */
|
||||
/* this will reset to 1 sec after we get the 001 event */
|
||||
g_get_current_time(&now);
|
||||
memcpy(&((IRC_SERVER_REC *)server)->wait_cmd, &now, sizeof(GTimeVal));
|
||||
((IRC_SERVER_REC *)server)->wait_cmd.tv_sec += 120;
|
||||
g_get_current_time(&server->wait_cmd);
|
||||
g_time_val_add(&server->wait_cmd, 120 * G_USEC_PER_SEC);
|
||||
}
|
||||
|
||||
SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
|
||||
@ -537,7 +535,7 @@ void irc_server_send_data(IRC_SERVER_REC *server, const char *data, int len)
|
||||
server->wait_cmd.tv_sec = 0;
|
||||
else {
|
||||
memcpy(&server->wait_cmd, &server->last_cmd, sizeof(GTimeVal));
|
||||
server->wait_cmd.tv_sec += 2 + len/100;
|
||||
g_time_val_add(&server->wait_cmd, (2 + len/100) * G_USEC_PER_SEC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,39 +623,25 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
|
||||
GString *chans, *keys;
|
||||
char *ret;
|
||||
int use_keys;
|
||||
char *rejoin_channels_mode;
|
||||
int rejoin_channels_mode;
|
||||
|
||||
g_return_val_if_fail(server != NULL, FALSE);
|
||||
|
||||
rejoin_channels_mode = g_strdup(settings_get_str("rejoin_channels_on_reconnect"));
|
||||
rejoin_channels_mode = settings_get_choice("rejoin_channels_on_reconnect");
|
||||
|
||||
if (rejoin_channels_mode == NULL ||
|
||||
(g_ascii_strcasecmp(rejoin_channels_mode, "on") != 0 &&
|
||||
g_ascii_strcasecmp(rejoin_channels_mode, "off") != 0 &&
|
||||
g_ascii_strcasecmp(rejoin_channels_mode, "auto") != 0)) {
|
||||
g_warning("Invalid value for 'rejoin_channels_on_reconnect', valid values are 'on', 'off', 'auto', using 'on' as default value.");
|
||||
g_free(rejoin_channels_mode);
|
||||
rejoin_channels_mode = g_strdup("on");
|
||||
}
|
||||
/* do we want to rejoin channels in the first place? */
|
||||
if(rejoin_channels_mode == 0)
|
||||
return g_strdup("");
|
||||
|
||||
chans = g_string_new(NULL);
|
||||
keys = g_string_new(NULL);
|
||||
use_keys = FALSE;
|
||||
|
||||
/* do we want to rejoin channels in the first place? */
|
||||
if(g_ascii_strcasecmp(rejoin_channels_mode, "off") == 0) {
|
||||
g_string_free(chans, TRUE);
|
||||
g_string_free(keys, TRUE);
|
||||
g_free(rejoin_channels_mode);
|
||||
return g_strdup("");
|
||||
}
|
||||
|
||||
/* get currently joined channels */
|
||||
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
|
||||
CHANNEL_REC *channel = tmp->data;
|
||||
CHANNEL_SETUP_REC *setup = channel_setup_find(channel->name, channel->server->connrec->chatnet);
|
||||
if ((setup != NULL && setup->autojoin && g_ascii_strcasecmp(rejoin_channels_mode, "auto") == 0) ||
|
||||
g_ascii_strcasecmp(rejoin_channels_mode, "on") == 0) {
|
||||
if ((setup != NULL && setup->autojoin && rejoin_channels_mode == 2) || rejoin_channels_mode == 1) {
|
||||
g_string_append_printf(chans, "%s,", channel->name);
|
||||
g_string_append_printf(keys, "%s,", channel->key == NULL ? "x" : channel->key);
|
||||
if (channel->key != NULL)
|
||||
@ -670,8 +654,7 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
|
||||
REJOIN_REC *rec = tmp->data;
|
||||
CHANNEL_SETUP_REC *setup = channel_setup_find(rec->channel, server->tag);
|
||||
|
||||
if ((setup != NULL && setup->autojoin && g_ascii_strcasecmp(rejoin_channels_mode, "auto") == 0) ||
|
||||
g_ascii_strcasecmp(rejoin_channels_mode, "on") == 0) {
|
||||
if ((setup != NULL && setup->autojoin && rejoin_channels_mode == 2) || rejoin_channels_mode == 1) {
|
||||
g_string_append_printf(chans, "%s,", rec->channel);
|
||||
g_string_append_printf(keys, "%s,", rec->key == NULL ? "x" :
|
||||
rec->key);
|
||||
@ -689,7 +672,6 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
|
||||
ret = chans->str;
|
||||
g_string_free(chans, FALSE);
|
||||
g_string_free(keys, TRUE);
|
||||
g_free(rejoin_channels_mode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -697,7 +679,6 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
|
||||
static void event_connected(IRC_SERVER_REC *server, const char *data, const char *from)
|
||||
{
|
||||
char *params, *nick;
|
||||
GTimeVal now;
|
||||
|
||||
g_return_if_fail(server != NULL);
|
||||
|
||||
@ -720,8 +701,7 @@ static void event_connected(IRC_SERVER_REC *server, const char *data, const char
|
||||
server->real_connect_time = time(NULL);
|
||||
|
||||
/* let the queue send now that we are identified */
|
||||
g_get_current_time(&now);
|
||||
memcpy(&server->wait_cmd, &now, sizeof(GTimeVal));
|
||||
g_get_current_time(&server->wait_cmd);
|
||||
|
||||
if (server->connrec->usermode != NULL) {
|
||||
/* Send the user mode, before the autosendcmd.
|
||||
@ -1035,7 +1015,7 @@ void irc_server_init_isupport(IRC_SERVER_REC *server)
|
||||
|
||||
void irc_servers_init(void)
|
||||
{
|
||||
settings_add_str("servers", "rejoin_channels_on_reconnect", "on");
|
||||
settings_add_choice("servers", "rejoin_channels_on_reconnect", 1, "off;on;auto");
|
||||
settings_add_str("misc", "usermode", DEFAULT_USER_MODE);
|
||||
settings_add_str("misc", "split_line_start", "");
|
||||
settings_add_str("misc", "split_line_end", "");
|
||||
|
@ -619,7 +619,7 @@ static void ctcp_msg_dcc_chat(IRC_SERVER_REC *server, const char *data,
|
||||
/* CHAT <unused> <address> <port> */
|
||||
/* CHAT <unused> <address> 0 <id> (DCC CHAT passive protocol) */
|
||||
params = g_strsplit(data, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
paramcount = g_strv_length(params);
|
||||
|
||||
if (paramcount < 3) {
|
||||
g_strfreev(params);
|
||||
|
@ -423,7 +423,7 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data,
|
||||
/* SEND <file name> <address> <port> <size> [...] */
|
||||
/* SEND <file name> <address> 0 <size> <id> (DCC SEND passive protocol) */
|
||||
params = g_strsplit(data, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
paramcount = g_strv_length(params);
|
||||
|
||||
if (paramcount < 4) {
|
||||
signal_emit("dcc error ctcp", 5, "SEND", data,
|
||||
@ -473,7 +473,7 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data,
|
||||
net_ip2host(&temp_dcc->addr, temp_dcc->addrstr);
|
||||
else {
|
||||
/* with IPv6, show it to us as it was sent */
|
||||
strocpy(temp_dcc->addrstr, address,
|
||||
g_strlcpy(temp_dcc->addrstr, address,
|
||||
sizeof(temp_dcc->addrstr));
|
||||
}
|
||||
|
||||
@ -508,7 +508,7 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data,
|
||||
net_ip2host(&dcc->addr, dcc->addrstr);
|
||||
else {
|
||||
/* with IPv6, show it to us as it was sent */
|
||||
strocpy(dcc->addrstr, address, sizeof(dcc->addrstr));
|
||||
g_strlcpy(dcc->addrstr, address, sizeof(dcc->addrstr));
|
||||
}
|
||||
dcc->port = port;
|
||||
dcc->size = size;
|
||||
@ -526,14 +526,14 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func,
|
||||
{
|
||||
GET_DCC_REC *dcc;
|
||||
GSList *tmp, *next;
|
||||
char *nick, *fname;
|
||||
char *nick, *arg, *fname;
|
||||
void *free_arg;
|
||||
int found;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
|
||||
&nick, &fname))
|
||||
if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST |
|
||||
PARAM_FLAG_STRIP_TRAILING_WS, &nick, &arg))
|
||||
return;
|
||||
|
||||
if (*nick == '\0') {
|
||||
@ -548,6 +548,8 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func,
|
||||
return;
|
||||
}
|
||||
|
||||
fname = cmd_get_quoted_param(&arg);
|
||||
|
||||
found = FALSE;
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = next) {
|
||||
GET_DCC_REC *dcc = tmp->data;
|
||||
|
@ -88,7 +88,7 @@ static int dcc_ctcp_resume_parse(int type, const char *data, const char *nick,
|
||||
/* RESUME|ACCEPT <file name> <port> <size> */
|
||||
/* RESUME|ACCEPT <file name> 0 <size> <id> (passive protocol) */
|
||||
params = g_strsplit(data, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
paramcount = g_strv_length(params);
|
||||
|
||||
if (paramcount < 3)
|
||||
return 0;
|
||||
|
@ -245,7 +245,7 @@ static void dcc_server_msg(SERVER_DCC_REC *dcc, const char *msg)
|
||||
|
||||
/* 120 clientnickname filesize filename */
|
||||
params = g_strsplit(msg, " ", -1);
|
||||
paramcount = strarray_length(params);
|
||||
paramcount = g_strv_length(params);
|
||||
|
||||
if (paramcount < 3) {
|
||||
g_strfreev(params);
|
||||
|
@ -490,7 +490,7 @@ static void event_no_such_nick(IRC_SERVER_REC *server, char *data)
|
||||
static void cmd_dcc_close(char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp, *next;
|
||||
char *typestr, *nick, *arg;
|
||||
char *typestr, *nick, *arg, *fname;
|
||||
void *free_arg;
|
||||
int found, type;
|
||||
|
||||
@ -510,13 +510,15 @@ static void cmd_dcc_close(char *data, IRC_SERVER_REC *server)
|
||||
return;
|
||||
}
|
||||
|
||||
fname = cmd_get_quoted_param(&arg);
|
||||
|
||||
found = FALSE;
|
||||
for (tmp = dcc_conns; tmp != NULL; tmp = next) {
|
||||
DCC_REC *dcc = tmp->data;
|
||||
|
||||
next = tmp->next;
|
||||
if (dcc->type == type && g_ascii_strcasecmp(dcc->nick, nick) == 0 &&
|
||||
(*arg == '\0' || g_strcmp0(dcc->arg, arg) == 0)) {
|
||||
(*fname == '\0' || g_strcmp0(dcc->arg, fname) == 0)) {
|
||||
dcc_reject(dcc, server);
|
||||
found = TRUE;
|
||||
}
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
#include "fe-common/core/printtext.h" /* FIXME: evil. need to do fe-proxy */
|
||||
|
||||
#include <sys/un.h>
|
||||
|
||||
GSList *proxy_listens;
|
||||
GSList *proxy_clients;
|
||||
|
||||
@ -39,6 +41,66 @@ static int ignore_next;
|
||||
|
||||
static int enabled = FALSE;
|
||||
|
||||
static int is_all_digits(const char *s)
|
||||
{
|
||||
return strspn(s, "0123456789") == strlen(s);
|
||||
}
|
||||
|
||||
static GIOChannel *net_listen_unix(const char *path)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
int saved_errno, handle;
|
||||
|
||||
g_return_val_if_fail(path != NULL, NULL);
|
||||
|
||||
handle = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (handle == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fcntl(handle, F_SETFL, O_NONBLOCK);
|
||||
|
||||
memset(&sa, '\0', sizeof sa);
|
||||
sa.sun_family = AF_UNIX;
|
||||
strncpy(sa.sun_path, path, sizeof sa.sun_path - 1);
|
||||
if (bind(handle, (struct sockaddr *)&sa, sizeof sa) == -1) {
|
||||
saved_errno = errno;
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
if (listen(handle, 1) == -1) {
|
||||
saved_errno = errno;
|
||||
goto error_unlink;
|
||||
}
|
||||
|
||||
return g_io_channel_new(handle);
|
||||
|
||||
error_unlink:
|
||||
unlink(sa.sun_path);
|
||||
error_close:
|
||||
close(handle);
|
||||
errno = saved_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GIOChannel *net_accept_unix(GIOChannel *handle)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
int ret;
|
||||
socklen_t addrlen;
|
||||
|
||||
g_return_val_if_fail(handle != NULL, NULL);
|
||||
|
||||
addrlen = sizeof sa;
|
||||
ret = accept(g_io_channel_unix_get_fd(handle), (struct sockaddr *)&sa, &addrlen);
|
||||
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
fcntl(ret, F_SETFL, O_NONBLOCK);
|
||||
return g_io_channel_new(ret);
|
||||
}
|
||||
|
||||
static void remove_client(CLIENT_REC *rec)
|
||||
{
|
||||
g_return_if_fail(rec != NULL);
|
||||
@ -48,13 +110,13 @@ static void remove_client(CLIENT_REC *rec)
|
||||
|
||||
signal_emit("proxy client disconnected", 1, rec);
|
||||
printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
"Proxy: Client %s:%d disconnected", rec->host, rec->port);
|
||||
"Proxy: Client %s disconnected", rec->addr);
|
||||
|
||||
g_free(rec->proxy_address);
|
||||
net_sendbuffer_destroy(rec->handle, TRUE);
|
||||
g_source_remove(rec->recv_tag);
|
||||
g_free_not_null(rec->nick);
|
||||
g_free_not_null(rec->host);
|
||||
g_free_not_null(rec->addr);
|
||||
g_free(rec);
|
||||
}
|
||||
|
||||
@ -108,14 +170,44 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
|
||||
|
||||
password = settings_get_str("irssiproxy_password");
|
||||
|
||||
if (password != NULL && g_strcmp0(cmd, "PASS") == 0) {
|
||||
if (g_strcmp0(password, args) == 0)
|
||||
client->pass_sent = TRUE;
|
||||
else {
|
||||
if (g_strcmp0(cmd, "PASS") == 0) {
|
||||
const char *args_pass;
|
||||
|
||||
if (!client->multiplex) {
|
||||
args_pass = args;
|
||||
} else {
|
||||
IRC_SERVER_REC *server;
|
||||
char *tag;
|
||||
const char *tag_end;
|
||||
|
||||
if ((tag_end = strchr(args, ':')) != NULL) {
|
||||
args_pass = tag_end + 1;
|
||||
} else {
|
||||
tag_end = args + strlen(args);
|
||||
args_pass = "";
|
||||
}
|
||||
|
||||
tag = g_strndup(args, tag_end - args);
|
||||
server = IRC_SERVER(server_find_chatnet(tag));
|
||||
g_free(tag);
|
||||
|
||||
if (!server) {
|
||||
/* an invalid network was specified */
|
||||
remove_client(client);
|
||||
return;
|
||||
}
|
||||
|
||||
client->server = server;
|
||||
g_free(client->proxy_address);
|
||||
client->proxy_address = g_strdup_printf("%.*s.proxy", (int)(tag_end - args), args);
|
||||
}
|
||||
|
||||
if (g_strcmp0(password, args_pass) != 0) {
|
||||
/* wrong password! */
|
||||
remove_client(client);
|
||||
return;
|
||||
}
|
||||
client->pass_sent = TRUE;
|
||||
} else if (g_strcmp0(cmd, "NICK") == 0) {
|
||||
g_free_not_null(client->nick);
|
||||
client->nick = g_strdup(args);
|
||||
@ -124,14 +216,14 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
|
||||
}
|
||||
|
||||
if (client->nick != NULL && client->user_sent) {
|
||||
if (*password != '\0' && !client->pass_sent) {
|
||||
if ((*password != '\0' || client->multiplex) && !client->pass_sent) {
|
||||
/* client didn't send us PASS, kill it */
|
||||
remove_client(client);
|
||||
} else {
|
||||
signal_emit("proxy client connected", 1, client);
|
||||
printtext(client->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
"Proxy: Client %s:%d connected",
|
||||
client->host, client->port);
|
||||
"Proxy: Client %s connected",
|
||||
client->addr);
|
||||
client->connected = TRUE;
|
||||
proxy_dump_data(client);
|
||||
}
|
||||
@ -176,9 +268,9 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
|
||||
client->want_ctcp = 1;
|
||||
for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) {
|
||||
CLIENT_REC *rec = tmp->data;
|
||||
if ((g_ascii_strcasecmp(client->listen->ircnet,rec->listen->ircnet) == 0) &&
|
||||
if (g_ascii_strcasecmp(client->listen->ircnet, rec->listen->ircnet) == 0 &&
|
||||
/* kludgy way to check if the clients aren't the same */
|
||||
(client->recv_tag != rec->recv_tag)) {
|
||||
client->recv_tag != rec->recv_tag) {
|
||||
if (rec->want_ctcp == 1)
|
||||
proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n",
|
||||
rec->proxy_address, rec->nick, rec->listen->ircnet);
|
||||
@ -187,7 +279,7 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
|
||||
|
||||
}
|
||||
proxy_outdata(client, ":%s NOTICE %s :You're now receiving CTCPs sent to %s\r\n",
|
||||
client->proxy_address, client->nick,client->listen->ircnet);
|
||||
client->proxy_address, client->nick, client->listen->ircnet);
|
||||
} else if (g_ascii_strcasecmp(args, "CTCP OFF") == 0) {
|
||||
/* client wants proxy to handle all ctcps */
|
||||
client->want_ctcp = 0;
|
||||
@ -340,21 +432,35 @@ static void sig_listen(LISTEN_REC *listen)
|
||||
GIOChannel *handle;
|
||||
char host[MAX_IP_LEN];
|
||||
int port;
|
||||
char *addr;
|
||||
|
||||
g_return_if_fail(listen != NULL);
|
||||
|
||||
/* accept connection */
|
||||
if (listen->port) {
|
||||
handle = net_accept(listen->handle, &ip, &port);
|
||||
if (handle == NULL)
|
||||
return;
|
||||
net_ip2host(&ip, host);
|
||||
addr = g_strdup_printf("%s:%d", host, port);
|
||||
} else {
|
||||
/* no port => this is a unix socket */
|
||||
handle = net_accept_unix(listen->handle);
|
||||
if (handle == NULL)
|
||||
return;
|
||||
addr = g_strdup("(local)");
|
||||
}
|
||||
|
||||
sendbuf = net_sendbuffer_create(handle, 0);
|
||||
rec = g_new0(CLIENT_REC, 1);
|
||||
rec->listen = listen;
|
||||
rec->handle = sendbuf;
|
||||
rec->host = g_strdup(host);
|
||||
rec->port = port;
|
||||
if (g_strcmp0(listen->ircnet, "*") == 0) {
|
||||
rec->addr = addr;
|
||||
if (g_strcmp0(listen->ircnet, "?") == 0) {
|
||||
rec->multiplex = TRUE;
|
||||
rec->proxy_address = g_strdup("multiplex.proxy");
|
||||
rec->server = NULL;
|
||||
} else if (g_strcmp0(listen->ircnet, "*") == 0) {
|
||||
rec->proxy_address = g_strdup("irc.proxy");
|
||||
rec->server = servers == NULL ? NULL : IRC_SERVER(servers->data);
|
||||
} else {
|
||||
@ -366,12 +472,12 @@ static void sig_listen(LISTEN_REC *listen)
|
||||
(GInputFunction) sig_listen_client, rec);
|
||||
|
||||
proxy_clients = g_slist_prepend(proxy_clients, rec);
|
||||
rec->listen->clients = g_slist_prepend(rec->listen->clients, rec);
|
||||
listen->clients = g_slist_prepend(listen->clients, rec);
|
||||
|
||||
signal_emit("proxy client connecting", 1, rec);
|
||||
printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
"Proxy: New client %s:%d on port %d (%s)",
|
||||
rec->host, rec->port, listen->port, listen->ircnet);
|
||||
"Proxy: New client %s on port %s (%s)",
|
||||
rec->addr, listen->port_or_path, listen->ircnet);
|
||||
}
|
||||
|
||||
static void sig_incoming(IRC_SERVER_REC *server, const char *line)
|
||||
@ -567,14 +673,19 @@ static void sig_message_own_action(IRC_SERVER_REC *server, const char *msg,
|
||||
proxy_outserver_all(server, "PRIVMSG %s :\001ACTION %s\001", target, msg);
|
||||
}
|
||||
|
||||
static LISTEN_REC *find_listen(const char *ircnet, int port)
|
||||
static LISTEN_REC *find_listen(const char *ircnet, int port, const char *port_or_path)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
for (tmp = proxy_listens; tmp != NULL; tmp = tmp->next) {
|
||||
LISTEN_REC *rec = tmp->data;
|
||||
|
||||
if (rec->port == port &&
|
||||
if ((port
|
||||
? /* a tcp port */
|
||||
rec->port == port
|
||||
: /* a unix socket path */
|
||||
g_strcmp0(rec->port_or_path, port_or_path) == 0
|
||||
) &&
|
||||
g_ascii_strcasecmp(rec->ircnet, ircnet) == 0)
|
||||
return rec;
|
||||
}
|
||||
@ -582,14 +693,19 @@ static LISTEN_REC *find_listen(const char *ircnet, int port)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_listen(const char *ircnet, int port)
|
||||
static void add_listen(const char *ircnet, int port, const char *port_or_path)
|
||||
{
|
||||
LISTEN_REC *rec;
|
||||
IPADDR ip4, ip6, *my_ip;
|
||||
GIOChannel *handle;
|
||||
|
||||
if (port <= 0 || *ircnet == '\0')
|
||||
if (*port_or_path == '\0' || port < 0 || *ircnet == '\0')
|
||||
return;
|
||||
|
||||
if (port == 0) {
|
||||
/* listening on a unix socket */
|
||||
handle = net_listen_unix(port_or_path);
|
||||
} else {
|
||||
/* bind to specific host/ip? */
|
||||
my_ip = NULL;
|
||||
if (*settings_get_str("irssiproxy_bind") != '\0') {
|
||||
@ -604,22 +720,22 @@ static void add_listen(const char *ircnet, int port)
|
||||
my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 ||
|
||||
settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4;
|
||||
}
|
||||
handle = net_listen(my_ip, &port);
|
||||
}
|
||||
|
||||
rec = g_new0(LISTEN_REC, 1);
|
||||
rec->ircnet = g_strdup(ircnet);
|
||||
rec->port = port;
|
||||
|
||||
rec->handle = net_listen(my_ip, &rec->port);
|
||||
|
||||
if (rec->handle == NULL) {
|
||||
if (handle == NULL) {
|
||||
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
||||
"Proxy: Listen in port %d failed: %s",
|
||||
rec->port, g_strerror(errno));
|
||||
g_free(rec->ircnet);
|
||||
g_free(rec);
|
||||
"Proxy: Listen in port %s failed: %s",
|
||||
port_or_path, g_strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
rec = g_new0(LISTEN_REC, 1);
|
||||
rec->handle = handle;
|
||||
rec->ircnet = g_strdup(ircnet);
|
||||
rec->port = port;
|
||||
rec->port_or_path = g_strdup(port_or_path);
|
||||
|
||||
rec->tag = g_input_add(rec->handle, G_INPUT_READ,
|
||||
(GInputFunction) sig_listen, rec);
|
||||
|
||||
@ -633,8 +749,13 @@ static void remove_listen(LISTEN_REC *rec)
|
||||
while (rec->clients != NULL)
|
||||
remove_client(rec->clients->data);
|
||||
|
||||
/* remove unix socket because bind wants to (re)create it */
|
||||
if (rec->port == 0)
|
||||
unlink(rec->port_or_path);
|
||||
|
||||
net_disconnect(rec->handle);
|
||||
g_source_remove(rec->tag);
|
||||
g_free(rec->port_or_path);
|
||||
g_free(rec->ircnet);
|
||||
g_free(rec);
|
||||
}
|
||||
@ -644,7 +765,7 @@ static void read_settings(void)
|
||||
LISTEN_REC *rec;
|
||||
GSList *remove_listens = NULL;
|
||||
GSList *add_listens = NULL;
|
||||
char **ports, **tmp, *ircnet, *port;
|
||||
char **ports, **tmp, *ircnet, *port_or_path;
|
||||
int portnum;
|
||||
|
||||
remove_listens = g_slist_copy(proxy_listens);
|
||||
@ -652,20 +773,25 @@ static void read_settings(void)
|
||||
ports = g_strsplit(settings_get_str("irssiproxy_ports"), " ", -1);
|
||||
for (tmp = ports; *tmp != NULL; tmp++) {
|
||||
ircnet = *tmp;
|
||||
port = strchr(ircnet, '=');
|
||||
if (port == NULL)
|
||||
port_or_path = strchr(ircnet, '=');
|
||||
if (port_or_path == NULL)
|
||||
continue;
|
||||
|
||||
*port++ = '\0';
|
||||
portnum = atoi(port);
|
||||
*port_or_path++ = '\0';
|
||||
if (is_all_digits(port_or_path)) {
|
||||
portnum = atoi(port_or_path);
|
||||
if (portnum <= 0)
|
||||
continue;
|
||||
} else {
|
||||
portnum = 0;
|
||||
}
|
||||
|
||||
rec = find_listen(ircnet, portnum);
|
||||
rec = find_listen(ircnet, portnum, port_or_path);
|
||||
if (rec == NULL) {
|
||||
rec = g_new0(LISTEN_REC, 1);
|
||||
rec->ircnet = ircnet; /* borrow */
|
||||
rec->port = portnum;
|
||||
rec->port_or_path = port_or_path; /* borrow */
|
||||
add_listens = g_slist_prepend(add_listens, rec);
|
||||
} else {
|
||||
/* remove from the list of listens to remove == keep it */
|
||||
@ -680,7 +806,7 @@ static void read_settings(void)
|
||||
|
||||
while (add_listens != NULL) {
|
||||
rec = add_listens->data;
|
||||
add_listen(rec->ircnet, rec->port);
|
||||
add_listen(rec->ircnet, rec->port, rec->port_or_path);
|
||||
add_listens = g_slist_remove(add_listens, rec);
|
||||
g_free(rec);
|
||||
}
|
||||
|
@ -28,13 +28,14 @@
|
||||
/* SYNTAX: IRSSIPROXY STATUS */
|
||||
static void cmd_irssiproxy_status(const char *data, IRC_SERVER_REC *server)
|
||||
{
|
||||
GSList *tmp;
|
||||
|
||||
if (!settings_get_bool("irssiproxy")) {
|
||||
printtext(server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
"Proxy is currently disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
GSList *tmp;
|
||||
|
||||
printtext(server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
"Proxy: Currently connected clients: %d",
|
||||
@ -44,10 +45,10 @@ static void cmd_irssiproxy_status(const char *data, IRC_SERVER_REC *server)
|
||||
CLIENT_REC *rec = tmp->data;
|
||||
|
||||
printtext(server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||
" %s:%d connect%s to %d (%s)",
|
||||
rec->host, rec->port,
|
||||
" %s connect%s to %s (%s)",
|
||||
rec->addr,
|
||||
rec->connected ? "ed" : "ing",
|
||||
rec->listen->port, rec->listen->ircnet);
|
||||
rec->listen->port_or_path, rec->listen->ircnet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,17 +9,18 @@
|
||||
|
||||
typedef struct {
|
||||
int port;
|
||||
char *port_or_path;
|
||||
char *ircnet;
|
||||
|
||||
int tag;
|
||||
GIOChannel *handle;
|
||||
|
||||
GSList *clients;
|
||||
|
||||
} LISTEN_REC;
|
||||
|
||||
typedef struct {
|
||||
char *nick, *host;
|
||||
int port;
|
||||
char *nick, *addr;
|
||||
NET_SENDBUF_REC *handle;
|
||||
int recv_tag;
|
||||
char *proxy_address;
|
||||
@ -29,6 +30,7 @@ typedef struct {
|
||||
unsigned int user_sent:1;
|
||||
unsigned int connected:1;
|
||||
unsigned int want_ctcp:1;
|
||||
unsigned int multiplex:1;
|
||||
} CLIENT_REC;
|
||||
|
||||
#endif
|
||||
|
@ -117,16 +117,26 @@ textui_sources = \
|
||||
EXTRA_DIST = \
|
||||
get-signals.pl \
|
||||
irssi-core.pl \
|
||||
Makefile_silent.pm \
|
||||
$(common_sources) \
|
||||
$(irc_sources) \
|
||||
$(ui_sources) \
|
||||
$(textui_sources)
|
||||
|
||||
am_v_pl__show_gen = $(am__v_pl__show_gen_$(V))
|
||||
am_v_pl__hide_gen = $(am__v_pl__hide_gen_$(V))
|
||||
am__v_pl__show_gen_ = $(am__v_pl__show_gen_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_pl__hide_gen_ = $(am__v_pl__hide_gen_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_pl__show_gen_0 = echo " GEN " $$dir ;
|
||||
am__v_pl__hide_gen_0 = > /dev/null
|
||||
am__v_pl__show_gen_1 =
|
||||
am__v_pl__hide_gen_1 =
|
||||
|
||||
all-local:
|
||||
for dir in $(perl_dirs); do \
|
||||
$(AM_V_GEN)for dir in $(perl_dirs); do \
|
||||
cd $$dir && \
|
||||
if [ ! -f Makefile ]; then \
|
||||
$(perlpath) Makefile.PL $(PERL_MM_PARAMS); \
|
||||
$(am_v_pl__show_gen)$(perlpath) Makefile.PL $(PERL_MM_PARAMS) $(am_v_pl__hide_gen); \
|
||||
fi && \
|
||||
($(MAKE) CC="$(CC)" CCFLAGS="$(PERL_CFLAGS) $(CFLAGS)" $(PERL_EXTRA_OPTS) || \
|
||||
$(MAKE) CC="$(CC)" CCFLAGS="$(PERL_CFLAGS) $(CFLAGS)" $(PERL_EXTRA_OPTS)) && \
|
||||
|
76
src/perl/Makefile_silent.pm
Normal file
76
src/perl/Makefile_silent.pm
Normal file
@ -0,0 +1,76 @@
|
||||
push @ExtUtils::MakeMaker::Overridable, qw(pm_to_blib);
|
||||
my $verb = $AM_DEFAULT_VERBOSITY;
|
||||
{ package MY;
|
||||
sub _center {
|
||||
my $z = shift;
|
||||
(length $z == 2 ? " $z " : length $z == 4 ? " $z " : " $z ").' '
|
||||
}
|
||||
sub _silent_cmd {
|
||||
my $z = shift;
|
||||
$z =~ s{\t(?:- ?)?\K(?=\$\((?|(CC)CMD|(XS)UBPPRUN|(LD|MV|CHMOD)|(RM)_R?F|(CP)_NONEMPTY|FULL_(AR)\)))}{\$(PL_AM_V_$1)}g;
|
||||
$z
|
||||
}
|
||||
sub c_o { _silent_cmd(shift->SUPER::c_o(@_)) }
|
||||
sub xs_c { _silent_cmd(shift->SUPER::xs_c(@_)) }
|
||||
sub xs_o { _silent_cmd(shift->SUPER::xs_o(@_)) }
|
||||
sub dynamic_lib { _silent_cmd(shift->SUPER::dynamic_lib(@_)) }
|
||||
sub static_lib { _silent_cmd(shift->SUPER::static_lib(@_)) }
|
||||
sub dynamic_bs {
|
||||
my $ret = shift->SUPER::dynamic_bs(@_);
|
||||
$ret =~ s{Running Mkbootstrap for}{\$(PL_AM_V_BS_Text)}g;
|
||||
_silent_cmd($ret)
|
||||
}
|
||||
sub pm_to_blib {
|
||||
my $ret = shift->SUPER::pm_to_blib(@_);
|
||||
$ret =~ s{^(\t(?:- ?)?)(?:\$\(NOECHO\) ?)?(.*-e ['"]pm_to_blib(.*\\\n)*.*)$}{$1\$(PL_AM_V_BLIB)$2\$(PL_AM_V_BLIB_Hide)}mg;
|
||||
$ret
|
||||
}
|
||||
sub post_constants {
|
||||
my $ret = shift->SUPER::post_constants(@_);
|
||||
my @terse = qw(cc xs ld chmod cp ar blib);
|
||||
my @silent = qw(mv rm);
|
||||
my @special = qw(BLIB_Hide);
|
||||
|
||||
#default verbosity from command line parameter
|
||||
$ret .= "
|
||||
AM_DEFAULT_VERBOSITY = @{[$verb ? 1 : 0]}
|
||||
";
|
||||
#default options forward
|
||||
$ret .= "
|
||||
PL_AM_V_${_} = \$(pl_am__v_${_}_\$(V))
|
||||
pl_am__v_${_}_ = \$(pl_am__v_${_}_\$(AM_DEFAULT_VERBOSITY))
|
||||
" for @special, map uc, @terse, @silent;
|
||||
|
||||
#quoted plain text needs extra quotes
|
||||
$ret .= "
|
||||
PL_AM_V_BS_Text = \"\$(pl_am__v_BS_Text_\$(V))\"
|
||||
pl_am__v_BS_Text_ = \$(pl_am__v_BS_Text_\$(AM_DEFAULT_VERBOSITY))
|
||||
"
|
||||
#hide pm_to_blib output
|
||||
. "
|
||||
pl_am__v_BLIB_Hide_0 = \$(DEV_NULL)
|
||||
pl_am__v_BLIB_Hide_1 =
|
||||
"
|
||||
#text for Mkbootstrap
|
||||
. "
|
||||
pl_am__v_BS_Text_0 = \"@{[_center('BS')]}\"
|
||||
pl_am__v_BS_Text_1 = \"Running Mkbootstrap for\"
|
||||
";
|
||||
#"terse" output
|
||||
$ret .= "
|
||||
pl_am__v_${_}_0 = \$(NOECHO)echo \"@{[_center($_)]}\" \$\@;
|
||||
" for map uc, @terse;
|
||||
|
||||
#no output
|
||||
$ret .= "
|
||||
pl_am__v_${_}_0 = \$(NOECHO)
|
||||
" for map uc, @silent;
|
||||
|
||||
#in verbose mode the "terse" echo expands to nothing
|
||||
$ret .= "
|
||||
pl_am__v_${_}_1 =
|
||||
" for map uc, @terse, @silent;
|
||||
$ret
|
||||
}
|
||||
}
|
||||
1;
|
@ -74,15 +74,20 @@ static char *perl_expando_event(PerlExpando *rec, SERVER_REC *server,
|
||||
|
||||
ret = NULL;
|
||||
if (SvTRUE(ERRSV)) {
|
||||
PERL_SCRIPT_REC *script = rec->script;
|
||||
|
||||
(void) POPs;
|
||||
/* call putback before emitting script error signal as that
|
||||
* could manipulate the perl stack. */
|
||||
PUTBACK;
|
||||
/* make sure we don't get back here */
|
||||
if (rec->script != NULL)
|
||||
script_unregister_expandos(rec->script);
|
||||
if (script != NULL)
|
||||
script_unregister_expandos(script);
|
||||
/* rec has been freed now */
|
||||
|
||||
signal_emit("script error", 2, rec->script, SvPV_nolen(ERRSV));
|
||||
char *error = g_strdup(SvPV_nolen(ERRSV));
|
||||
signal_emit("script error", 2, script, error);
|
||||
g_free(error);
|
||||
} else if (retcount > 0) {
|
||||
ret = g_strdup(POPp);
|
||||
*free_ret = TRUE;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use ExtUtils::MakeMaker;
|
||||
use ExtUtils::MakeMaker;our $AM_DEFAULT_VERBOSITY='@AM_DEFAULT_VERBOSITY@';require "../Makefile_silent.pm";
|
||||
|
||||
WriteMakefile('NAME' => 'Irssi',
|
||||
'LIBS' => '',
|
||||
|
@ -149,14 +149,14 @@ static void perl_notifylist_fill_hash(HV *hv, NOTIFYLIST_REC *notify)
|
||||
static void perl_client_fill_hash(HV *hv, CLIENT_REC *client)
|
||||
{
|
||||
(void) hv_store(hv, "nick", 4, new_pv(client->nick), 0);
|
||||
(void) hv_store(hv, "host", 4, new_pv(client->host), 0);
|
||||
(void) hv_store(hv, "port", 4, newSViv(client->port), 0);
|
||||
(void) hv_store(hv, "addr", 4, new_pv(client->addr), 0);
|
||||
(void) hv_store(hv, "proxy_address", 13, new_pv(client->proxy_address), 0);
|
||||
(void) hv_store(hv, "server", 6, iobject_bless(client->server), 0);
|
||||
(void) hv_store(hv, "pass_sent", 9, newSViv(client->pass_sent), 0);
|
||||
(void) hv_store(hv, "user_sent", 9, newSViv(client->user_sent), 0);
|
||||
(void) hv_store(hv, "connected", 9, newSViv(client->connected), 0);
|
||||
(void) hv_store(hv, "want_ctcp", 9, newSViv(client->want_ctcp), 0);
|
||||
(void) hv_store(hv, "multiplex", 9, newSViv(client->multiplex), 0);
|
||||
(void) hv_store(hv, "ircnet", 6, new_pv(client->listen->ircnet), 0);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use ExtUtils::MakeMaker;
|
||||
use ExtUtils::MakeMaker;our $AM_DEFAULT_VERBOSITY='@AM_DEFAULT_VERBOSITY@';require "../Makefile_silent.pm";
|
||||
|
||||
WriteMakefile('NAME' => 'Irssi::Irc',
|
||||
'LIBS' => '',
|
||||
|
@ -393,7 +393,7 @@ int perl_get_api_version(void)
|
||||
return IRSSI_PERL_API_VERSION;
|
||||
}
|
||||
|
||||
static void perl_scripts_autorun(void)
|
||||
void perl_scripts_autorun(void)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
|
@ -16,6 +16,8 @@ extern GSList *perl_scripts;
|
||||
void perl_scripts_init(void);
|
||||
/* Destroy all perl scripts and deinitialize perl interpreter */
|
||||
void perl_scripts_deinit(void);
|
||||
/* Load all the scripts in the autorun/ folder */
|
||||
void perl_scripts_autorun(void);
|
||||
|
||||
/* Load a perl script, path must be a full path. */
|
||||
PERL_SCRIPT_REC *perl_script_load_file(const char *path);
|
||||
|
@ -119,8 +119,20 @@ static void cmd_script_unload(const char *data)
|
||||
|
||||
static void cmd_script_reset(const char *data)
|
||||
{
|
||||
void *free_arg;
|
||||
GHashTable *optlist;
|
||||
|
||||
if (!cmd_get_params(data, &free_arg, 0 | PARAM_FLAG_OPTIONS,
|
||||
"script reset", &optlist))
|
||||
return;
|
||||
|
||||
perl_scripts_deinit();
|
||||
perl_scripts_init();
|
||||
|
||||
if (g_hash_table_lookup(optlist, "autorun") != NULL)
|
||||
perl_scripts_autorun();
|
||||
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
||||
static void cmd_script_list(void)
|
||||
@ -251,6 +263,7 @@ void fe_perl_init(void)
|
||||
command_bind("script list", NULL, (SIGNAL_FUNC) cmd_script_list);
|
||||
command_bind("load", NULL, (SIGNAL_FUNC) cmd_load);
|
||||
command_set_options("script exec", "permanent");
|
||||
command_set_options("script reset", "autorun");
|
||||
|
||||
signal_add("script error", (SIGNAL_FUNC) sig_script_error);
|
||||
signal_add("complete command script load", (SIGNAL_FUNC) sig_complete_load);
|
||||
|
@ -433,7 +433,8 @@ static void perl_signal_remove_list_one(GSList **siglist, PERL_SIGNAL_REC *rec)
|
||||
}
|
||||
|
||||
#define sv_func_cmp(f1, f2) \
|
||||
(f1 == f2 || (SvPOK(f1) && SvPOK(f2) && \
|
||||
((SvROK(f1) && SvROK(f2) && SvRV(f1) == SvRV(f2)) || \
|
||||
(SvPOK(f1) && SvPOK(f2) && \
|
||||
g_strcmp0(SvPV_nolen(f1), SvPV_nolen(f2)) == 0))
|
||||
|
||||
static void perl_signal_remove_list(GSList **list, SV *func)
|
||||
|
@ -1,4 +1,4 @@
|
||||
use ExtUtils::MakeMaker;
|
||||
use ExtUtils::MakeMaker;our $AM_DEFAULT_VERBOSITY='@AM_DEFAULT_VERBOSITY@';require "../Makefile_silent.pm";
|
||||
|
||||
WriteMakefile('NAME' => 'Irssi::TextUI',
|
||||
'LIBS' => '',
|
||||
|
@ -77,7 +77,10 @@ static void perl_statusbar_event(char *function, SBAR_ITEM_REC *item,
|
||||
/* make sure we don't get back here */
|
||||
script_unregister_statusbars(script);
|
||||
}
|
||||
signal_emit("script error", 2, script, SvPV_nolen(ERRSV));
|
||||
|
||||
char *error = g_strdup(SvPV_nolen(ERRSV));
|
||||
signal_emit("script error", 2, script, error);
|
||||
g_free(error);
|
||||
} else {
|
||||
/* min_size and max_size can be changed, move them to SBAR_ITEM_REC */
|
||||
hv = hvref(item_sv);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user