summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorailin-nemui <ailin-nemui@users.noreply.github.com>2016-09-21 15:59:33 +0200
committerailin-nemui <ailin-nemui@users.noreply.github.com>2016-09-21 15:59:33 +0200
commitac73255483a42851db6a54ae4f0d5040e94608a2 (patch)
tree23c38bc6224171640d44be3269053948dd1a92e8
parent13f4026ae0f0d5422f3163576d4c2eff8754176a (diff)
parentd9b4cb34dccd7fb77e1d222333f3018ff947899c (diff)
downloadirssi-ac73255483a42851db6a54ae4f0d5040e94608a2.zip
Merge branch 'master' into integrate/0.8.20
-rw-r--r--.gitattributes3
-rw-r--r--.travis.yml30
-rw-r--r--AUTHORS2
-rw-r--r--INSTALL26
-rw-r--r--NEWS24
-rw-r--r--acconfig.h31
-rw-r--r--configure.ac170
-rw-r--r--docs/help/in/channel.in2
-rw-r--r--docs/help/in/dcc.in4
-rw-r--r--docs/help/in/hilight.in1
-rw-r--r--docs/help/in/network.in2
-rw-r--r--docs/help/in/script.in2
-rw-r--r--docs/help/in/server.in2
-rw-r--r--docs/irssi.13
-rw-r--r--docs/proxy.txt12
-rw-r--r--docs/startup-HOWTO.html17
-rw-r--r--m4/curses.m4298
-rw-r--r--src/common.h2
-rw-r--r--src/core/Makefile.am3
-rw-r--r--src/core/channels.c31
-rw-r--r--src/core/channels.h1
-rw-r--r--src/core/chat-commands.c11
-rw-r--r--src/core/commands.h3
-rw-r--r--src/core/ignore.c2
-rw-r--r--src/core/log.c2
-rw-r--r--src/core/misc.c143
-rw-r--r--src/core/misc.h14
-rw-r--r--src/core/network.c124
-rw-r--r--src/core/network.h12
-rw-r--r--src/core/rawlog.c7
-rw-r--r--src/core/servers-reconnect.c1
-rw-r--r--src/core/servers-setup.c4
-rw-r--r--src/core/servers.c16
-rw-r--r--src/core/settings.c95
-rw-r--r--src/core/settings.h14
-rw-r--r--src/core/special-vars.c23
-rw-r--r--src/core/special-vars.h7
-rw-r--r--src/core/utf8.c135
-rw-r--r--src/core/utf8.h56
-rw-r--r--src/core/wcwidth.c (renamed from src/fe-common/core/wcwidth.c)2
-rw-r--r--src/fe-common/core/Makefile.am5
-rw-r--r--src/fe-common/core/chat-completion.c49
-rw-r--r--src/fe-common/core/completion.c77
-rw-r--r--src/fe-common/core/fe-channels.c118
-rw-r--r--src/fe-common/core/fe-common-core.c11
-rw-r--r--src/fe-common/core/fe-core-commands.c3
-rw-r--r--src/fe-common/core/fe-exec.c15
-rw-r--r--src/fe-common/core/fe-ignore.c8
-rw-r--r--src/fe-common/core/fe-log.c2
-rw-r--r--src/fe-common/core/fe-messages.c5
-rw-r--r--src/fe-common/core/fe-server.c24
-rw-r--r--src/fe-common/core/fe-settings.c27
-rw-r--r--src/fe-common/core/formats.c28
-rw-r--r--src/fe-common/core/hilight-text.c149
-rw-r--r--src/fe-common/core/hilight-text.h1
-rw-r--r--src/fe-common/core/module-formats.c2
-rw-r--r--src/fe-common/core/module-formats.h2
-rw-r--r--src/fe-common/core/module.h2
-rw-r--r--src/fe-common/core/themes.c2
-rw-r--r--src/fe-common/core/utf8.c26
-rw-r--r--src/fe-common/core/utf8.h17
-rw-r--r--src/fe-common/irc/fe-irc-server.c13
-rw-r--r--src/fe-common/irc/fe-ircnet.c40
-rw-r--r--src/fe-text/Makefile.am23
-rw-r--r--src/fe-text/gui-entry.c172
-rw-r--r--src/fe-text/gui-entry.h29
-rw-r--r--src/fe-text/gui-readline.c100
-rw-r--r--src/fe-text/irssi.c89
-rw-r--r--src/fe-text/lastlog.c17
-rw-r--r--src/fe-text/statusbar-items.c4
-rw-r--r--src/fe-text/statusbar.c2
-rw-r--r--src/fe-text/term-curses.c415
-rw-r--r--src/fe-text/term-dummy.c106
-rw-r--r--src/fe-text/term-terminfo.c2
-rw-r--r--src/fe-text/term.h2
-rw-r--r--src/fe-text/terminfo-core.c23
-rw-r--r--src/fe-text/tparm.c740
-rw-r--r--src/irc/core/irc-channels-setup.c6
-rw-r--r--src/irc/core/irc-nicklist.c2
-rw-r--r--src/irc/core/irc-servers.c44
-rw-r--r--src/irc/dcc/dcc-chat.c2
-rw-r--r--src/irc/dcc/dcc-get.c16
-rw-r--r--src/irc/dcc/dcc-resume.c2
-rw-r--r--src/irc/dcc/dcc-server.c2
-rw-r--r--src/irc/dcc/dcc.c6
-rw-r--r--src/irc/proxy/listen.c316
-rw-r--r--src/irc/proxy/proxy.c9
-rw-r--r--src/irc/proxy/proxy.h6
-rw-r--r--src/perl/Makefile.am14
-rw-r--r--src/perl/Makefile_silent.pm76
-rw-r--r--src/perl/common/Expando.xs11
-rw-r--r--src/perl/common/Makefile.PL.in2
-rw-r--r--src/perl/irc/Irc.xs4
-rw-r--r--src/perl/irc/Makefile.PL.in2
-rw-r--r--src/perl/perl-core.c2
-rw-r--r--src/perl/perl-core.h2
-rw-r--r--src/perl/perl-fe.c13
-rw-r--r--src/perl/perl-signals.c5
-rw-r--r--src/perl/textui/Makefile.PL.in2
-rw-r--r--src/perl/textui/Statusbar.xs5
-rw-r--r--src/perl/ui/Makefile.PL.in2
101 files changed, 1622 insertions, 2616 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..e1ae7d9d
--- /dev/null
+++ b/.gitattributes
@@ -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
diff --git a/.travis.yml b/.travis.yml
index 46f58766..804dc58c 100644
--- a/.travis.yml
+++ b/.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
diff --git a/AUTHORS b/AUTHORS
index 7ded5017..eea359cc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -97,3 +97,5 @@ Other patches (grep for "patch" in ChangeLog) by:
Paul Johnson
KindOne
Fabian Kurz
+ Todd Pratt
+ xavierog
diff --git a/INSTALL b/INSTALL
index a83a6c76..5e6e2be0 100644
--- a/INSTALL
+++ b/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:
diff --git a/NEWS b/NEWS
index 265827b3..a76771e7 100644
--- a/NEWS
+++ b/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)
diff --git a/acconfig.h b/acconfig.h
deleted file mode 100644
index 9ace70d8..00000000
--- a/acconfig.h
+++ /dev/null
@@ -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
diff --git a/configure.ac b/configure.ac
index 458c8aa9..ee03eb82 100644
--- a/configure.ac
+++ b/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
-
- 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
- ])
- 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
+if test "x$want_textui" != "xno"; then
+
+ 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"
+ ])
+
+ TEXTUI_LIBS="$LIBS"
AC_SUBST(TEXTUI_LIBS)
+ LIBS="$TEXTUI_NO_LIBS"
- if test "x$want_termcap" = "xyes"; then
- AC_CHECK_FUNC(tparm,, need_tparm=yes)
- else
- AC_DEFINE(HAVE_TERMINFO)
- fi
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.
+ $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
- 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;'`
- rm -f Makefile.test
+ 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
diff --git a/docs/help/in/channel.in b/docs/help/in/channel.in
index 01bea3c1..86e824c2 100644
--- a/docs/help/in/channel.in
+++ b/docs/help/in/channel.in
@@ -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
diff --git a/docs/help/in/dcc.in b/docs/help/in/dcc.in
index dac31e58..18a77ee9 100644
--- a/docs/help/in/dcc.in
+++ b/docs/help/in/dcc.in
@@ -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
diff --git a/docs/help/in/hilight.in b/docs/help/in/hilight.in
index cd91560b..0726e5e7 100644
--- a/docs/help/in/hilight.in
+++ b/docs/help/in/hilight.in
@@ -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.
diff --git a/docs/help/in/network.in b/docs/help/in/network.in
index 2918f6ae..ba08ef69 100644
--- a/docs/help/in/network.in
+++ b/docs/help/in/network.in
@@ -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
diff --git a/docs/help/in/script.in b/docs/help/in/script.in
index 6e94ef7f..e90135ad 100644
--- a/docs/help/in/script.in
+++ b/docs/help/in/script.in
@@ -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.
diff --git a/docs/help/in/server.in b/docs/help/in/server.in
index e407b6a9..68a62e2d 100644
--- a/docs/help/in/server.in
+++ b/docs/help/in/server.in
@@ -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
diff --git a/docs/irssi.1 b/docs/irssi.1
index f38b639e..e1fab0d8 100644
--- a/docs/irssi.1
+++ b/docs/irssi.1
@@ -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
diff --git a/docs/proxy.txt b/docs/proxy.txt
index e6360a82..224d24e3 100644
--- a/docs/proxy.txt
+++ b/docs/proxy.txt
@@ -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:
diff --git a/docs/startup-HOWTO.html b/docs/startup-HOWTO.html
index 12128c59..07a9f47c 100644
--- a/docs/startup-HOWTO.html
+++ b/docs/startup-HOWTO.html
@@ -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>
diff --git a/m4/curses.m4 b/m4/curses.m4
deleted file mode 100644
index 41c0e6c8..00000000
--- a/m4/curses.m4
+++ /dev/null
@@ -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
-])
-
diff --git a/src/common.h b/src/common.h
index 729049ab..0a7b72f0 100644
--- a/src/common.h
+++ b/src/common.h
@@ -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
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index fc32e17e..af323234 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -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)
diff --git a/src/core/channels.c b/src/core/channels.c
index 9af8b844..9c3b92ba 100644
--- a/src/core/channels.c
+++ b/src/core/channels.c
@@ -233,23 +233,46 @@ static int match_nick_flags(SERVER_REC *server, NICK_REC *nick, char flag)
void channel_send_autocommands(CHANNEL_REC *channel)
{
CHANNEL_SETUP_REC *rec;
- NICK_REC *nick;
- char **bots, **bot;
g_return_if_fail(IS_CHANNEL(channel));
if (channel->session_rejoin)
- return;
+ 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);
- return;
}
+}
+
+void channel_send_botcommands(CHANNEL_REC *channel)
+{
+ CHANNEL_SETUP_REC *rec;
+ NICK_REC *nick;
+ char **bots, **bot;
+
+ 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;
+
+ /* 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);
diff --git a/src/core/channels.h b/src/core/channels.h
index 0839d69b..bd136fe2 100644
--- a/src/core/channels.h
+++ b/src/core/channels.h
@@ -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);
diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c
index 8e881679..a9404fa3 100644
--- a/src/core/chat-commands.c
+++ b/src/core/chat-commands.c
@@ -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);
@@ -117,8 +124,8 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
if (g_hash_table_lookup(optlist, "!") != NULL)
conn->no_autojoin_channels = TRUE;
- if (g_hash_table_lookup(optlist, "noautosendcmd") != NULL)
- conn->no_autosendcmd = TRUE;
+ if (g_hash_table_lookup(optlist, "noautosendcmd") != NULL)
+ conn->no_autosendcmd = TRUE;
if (g_hash_table_lookup(optlist, "noproxy") != NULL)
g_free_and_null(conn->proxy);
diff --git a/src/core/commands.h b/src/core/commands.h
index 72105ad3..93d6276b 100644
--- a/src/core/commands.h
+++ b/src/core/commands.h
@@ -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' */
diff --git a/src/core/ignore.c b/src/core/ignore.c
index 8d5a27c2..2047dc9d 100644
--- a/src/core/ignore.c
+++ b/src/core/ignore.c
@@ -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 */
diff --git a/src/core/log.c b/src/core/log.c
index 8306d2df..6af1effc 100644
--- a/src/core/log.c
+++ b/src/core/log.c
@@ -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);
}
diff --git a/src/core/misc.c b/src/core/misc.c
index aaa470f5..bc9f504e 100644
--- a/src/core/misc.c
+++ b/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;
diff --git a/src/core/misc.h b/src/core/misc.h
index 7e78d3b9..c095e131 100644
--- a/src/core/misc.h
+++ b/src/core/misc.h
@@ -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);
diff --git a/src/core/network.c b/src/core/network.c
index c3ad4e23..3e1b7c70 100644
--- a/src/core/network.c
+++ b/src/core/network.c
@@ -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 */
diff --git a/src/core/network.h b/src/core/network.h
index 73ac8dee..03f3b813 100644
--- a/src/core/network.h
+++ b/src/core/network.h
@@ -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);
diff --git a/src/core/rawlog.c b/src/core/rawlog.c
index 875c0ef2..5927e730 100644
--- a/src/core/rawlog.c
+++ b/src/core/rawlog.c
@@ -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);
}
diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c
index f419035b..58c9dd09 100644
--- a/src/core/servers-reconnect.c
+++ b/src/core/servers-reconnect.c
@@ -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);
diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c
index 4a048282..0cecfece 100644
--- a/src/core/servers-setup.c
+++ b/src/core/servers-setup.c
@@ -321,8 +321,8 @@ 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)
- return rec;
+ /* If rec is NULL the chatnet has no url to connect to */
+ return rec;
}
chatrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
diff --git a/src/core/servers.c b/src/core/servers.c
index 3342304e..d6297c4d 100644
--- a/src/core/servers.c
+++ b/src/core/servers.c
@@ -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;
}
diff --git a/src/core/settings.c b/src/core/settings.c
index 8e493124..e65ceb2c 100644
--- a/src/core/settings.c
+++ b/src/core/settings.c
@@ -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)) {
diff --git a/src/core/settings.h b/src/core/settings.h
index 6f2cf129..d174f250 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -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);
diff --git a/src/core/special-vars.c b/src/core/special-vars.c
index 4dcc3d2f..6ca080fc 100644
--- a/src/core/special-vars.c
+++ b/src/core/special-vars.c
@@ -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
@@ -340,7 +343,7 @@ static char *get_alignment(const char *text, int align, int flags, char pad)
}
ret = str->str;
- g_string_free(str, FALSE);
+ g_string_free(str, FALSE);
return ret;
}
diff --git a/src/core/special-vars.h b/src/core/special-vars.h
index 11262dad..300dae0e 100644
--- a/src/core/special-vars.h
+++ b/src/core/special-vars.h
@@ -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,
diff --git a/src/core/utf8.c b/src/core/utf8.c
new file mode 100644
index 00000000..c53d8816
--- /dev/null
+++ b/src/core/utf8.c
@@ -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;
+}
diff --git a/src/core/utf8.h b/src/core/utf8.h
new file mode 100644
index 00000000..5bb53193
--- /dev/null
+++ b/src/core/utf8.h
@@ -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
diff --git a/src/fe-common/core/wcwidth.c b/src/core/wcwidth.c
index 80d20fa1..711c4646 100644
--- a/src/fe-common/core/wcwidth.c
+++ b/src/core/wcwidth.c
@@ -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;
diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am
index e755b510..63f91fa6 100644
--- a/src/fe-common/core/Makefile.am
+++ b/src/fe-common/core/Makefile.am
@@ -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
diff --git a/src/fe-common/core/chat-completion.c b/src/fe-common/core/chat-completion.c
index c37c77cd..3e144602 100644
--- a/src/fe-common/core/chat-completion.c
+++ b/src/fe-common/core/chat-completion.c
@@ -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);
diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c
index 4461de92..76dfbb79 100644
--- a/src/fe-common/core/completion.c
+++ b/src/fe-common/core/completion.c
@@ -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]))
- wordstart--;
- }
+ /* 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;
+ 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));
+ }
+ }
}
}
diff --git a/src/fe-common/core/fe-channels.c b/src/fe-common/core/fe-channels.c
index 046d641a..00aac885 100644
--- a/src/fe-common/core/fe-channels.c
+++ b/src/fe-common/core/fe-channels.c
@@ -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;
@@ -257,18 +257,19 @@ static void cmd_channel_add(const char *data)
void *free_arg;
if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_OPTIONS,
- "channel add", &optlist, &channel, &chatnet, &password))
+ "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) {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
- TXT_UNKNOWN_CHATNET, chatnet);
+ TXT_UNKNOWN_CHATNET, chatnet);
cmd_params_free(free_arg);
- return;
+ return;
}
botarg = g_hash_table_lookup(optlist, "bots");
@@ -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,40 +343,40 @@ 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)
{
- WINDOW_REC *window;
+ WINDOW_REC *window;
TEXT_DEST_REC dest;
GString *str;
GSList *tmp;
- char *format, *stripped, *prefix_format;
- char *linebuf, nickmode[2] = { 0, 0 };
+ char *format, *stripped, *prefix_format;
+ 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);
- max_width = window->width;
+ MSGLEVEL_CLIENTCRAP);
+ max_width = window->width;
- /* get the length of item extra stuff ("[ ] ") */
+ /* get the length of item extra stuff ("[ ] ") */
format = format_get_text(MODULE_NAME, NULL,
- channel->server, channel->visible_name,
- TXT_NAMES_NICK, " ", "");
+ channel->server, channel->visible_name,
+ TXT_NAMES_NICK, " ", "");
stripped = strip_codes(format);
item_extra = strlen(stripped);
- g_free(stripped);
+ g_free(stripped);
g_free(format);
if (settings_get_int("names_max_width") > 0 &&
settings_get_int("names_max_width") < max_width)
max_width = settings_get_int("names_max_width");
- /* remove width of the timestamp from max_width */
+ /* remove width of the timestamp from max_width */
format_create_dest(&dest, channel->server, channel->visible_name,
- MSGLEVEL_CLIENTCRAP, NULL);
+ MSGLEVEL_CLIENTCRAP, NULL);
format = format_get_line_start(current_theme, &dest, time(NULL));
if (format != NULL) {
stripped = strip_codes(format);
@@ -365,11 +385,11 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
g_free(format);
}
- /* remove width of the prefix from max_width */
+ /* remove width of the prefix from max_width */
prefix_format = format_get_text(MODULE_NAME, NULL,
- channel->server, channel->visible_name,
- TXT_NAMES_PREFIX,
- channel->visible_name);
+ channel->server, channel->visible_name,
+ TXT_NAMES_PREFIX,
+ channel->visible_name);
if (prefix_format != NULL) {
stripped = strip_codes(prefix_format);
max_width -= strlen(stripped);
@@ -384,19 +404,18 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
/* calculate columns */
cols = get_max_column_count(nicklist, get_nick_length, max_width,
- settings_get_int("names_max_columns"),
- item_extra, 3, &columns, &rows);
+ settings_get_int("names_max_columns"),
+ item_extra, 3, &columns, &rows);
nicklist = columns_sort_list(nicklist, rows);
- /* rows in last column */
+ /* rows in last column */
last_col_rows = rows-(cols*rows-g_slist_length(nicklist));
if (last_col_rows == 0)
- last_col_rows = rows;
+ last_col_rows = rows;
str = g_string_new(prefix_format);
- linebuf_size = max_width+1; linebuf = g_malloc(linebuf_size);
- col = 0; row = 0;
+ col = 0; row = 0;
for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
NICK_REC *rec = tmp->data;
@@ -405,48 +424,44 @@ 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));
-
- formatnum = rec->op ? TXT_NAMES_NICK_OP :
- rec->halfop ? TXT_NAMES_NICK_HALFOP :
- rec->voice ? TXT_NAMES_NICK_VOICE :
- TXT_NAMES_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 :
+ rec->voice ? TXT_NAMES_NICK_VOICE :
+ TXT_NAMES_NICK;
format = format_get_text(MODULE_NAME, NULL,
- channel->server,
- channel->visible_name,
- formatnum, nickmode, linebuf);
+ channel->server,
+ channel->visible_name,
+ formatnum, nickmode, aligned_nick);
g_string_append(str, format);
+ g_free(aligned_nick);
g_free(format);
if (++col == cols) {
printtext(channel->server, channel->visible_name,
- MSGLEVEL_CLIENTCRAP, "%s", str->str);
+ MSGLEVEL_CLIENTCRAP, "%s", str->str);
g_string_truncate(str, 0);
if (prefix_format != NULL)
- g_string_assign(str, prefix_format);
+ g_string_assign(str, prefix_format);
col = 0; row++;
if (row == last_col_rows)
- cols--;
+ cols--;
}
}
if (str->len > strlen(prefix_format)) {
printtext(channel->server, channel->visible_name,
- MSGLEVEL_CLIENTCRAP, "%s", str->str);
+ MSGLEVEL_CLIENTCRAP, "%s", str->str);
}
g_slist_free(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);
diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c
index ee7f9424..1b2ab1e2 100644
--- a/src/fe-common/core/fe-common-core.c
+++ b/src/fe-common/core/fe-common-core.c
@@ -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;
}
diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c
index 7b1d7b94..97a246ec 100644
--- a/src/fe-common/core/fe-core-commands.c
+++ b/src/fe-common/core/fe-core-commands.c
@@ -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;
diff --git a/src/fe-common/core/fe-exec.c b/src/fe-common/core/fe-exec.c
index b5f289ce..36990866 100644
--- a/src/fe-common/core/fe-exec.c
+++ b/src/fe-common/core/fe-exec.c
@@ -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;
}
diff --git a/src/fe-common/core/fe-ignore.c b/src/fe-common/core/fe-ignore.c
index a809ac91..52b11e6b 100644
--- a/src/fe-common/core/fe-ignore.c
+++ b/src/fe-common/core/fe-ignore.c
@@ -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);
}
diff --git a/src/fe-common/core/fe-log.c b/src/fe-common/core/fe-log.c
index f2c4c014..5bc5c4e1 100644
--- a/src/fe-common/core/fe-log.c
+++ b/src/fe-common/core/fe-log.c
@@ -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;
diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c
index 8ad83753..487a5754 100644
--- a/src/fe-common/core/fe-messages.c
+++ b/src/fe-common/core/fe-messages.c
@@ -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;
diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c
index 429e6dac..468cb707 100644
--- a/src/fe-common/core/fe-server.c
+++ b/src/fe-common/core/fe-server.c
@@ -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;
@@ -113,7 +113,7 @@ static void cmd_server_add(const char *data)
int port;
if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_OPTIONS,
- "server add", &optlist, &addr, &portstr, &password))
+ "server add", &optlist, &addr, &portstr, &password))
return;
if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
@@ -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);
diff --git a/src/fe-common/core/fe-settings.c b/src/fe-common/core/fe-settings.c
index b689cbf9..abbd45a8 100644
--- a/src/fe-common/core/fe-settings.c
+++ b/src/fe-common/core/fe-settings.c
@@ -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);
@@ -79,7 +80,7 @@ static void set_boolean(const char *key, const char *value)
else
printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE);
- g_free(stripped_value);
+ g_free(stripped_value);
}
static void set_int(const char *key, const char *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 :
diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c
index d9a51201..9aa7698d 100644
--- a/src/fe-common/core/formats.c
+++ b/src/fe-common/core/formats.c
@@ -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;
}
diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c
index b746f636..4691a708 100644
--- a/src/fe-common/core/hilight-text.c
+++ b/src/fe-common/core/hilight-text.c
@@ -49,7 +49,7 @@ static void reset_level_cache(void)
HILIGHT_REC *rec = tmp->data;
if (never_hilight_level & rec->level)
- never_hilight_level &= ~rec->level;
+ never_hilight_level &= ~rec->level;
}
}
@@ -68,17 +68,18 @@ static void hilight_add_config(HILIGHT_REC *rec)
node = iconfig_node_traverse("(hilights", TRUE);
node = iconfig_node_section(node, NULL, NODE_TYPE_BLOCK);
- iconfig_node_set_str(node, "text", rec->text);
- if (rec->level > 0) iconfig_node_set_int(node, "level", rec->level);
- if (rec->color) iconfig_node_set_str(node, "color", rec->color);
- if (rec->act_color) iconfig_node_set_str(node, "act_color", rec->act_color);
- if (rec->priority > 0) iconfig_node_set_int(node, "priority", rec->priority);
- iconfig_node_set_bool(node, "nick", rec->nick);
- iconfig_node_set_bool(node, "word", rec->word);
- 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->servertag) iconfig_node_set_str(node, "servertag", rec->servertag);
+ iconfig_node_set_str(node, "text", rec->text);
+ if (rec->level > 0) iconfig_node_set_int(node, "level", rec->level);
+ if (rec->color) iconfig_node_set_str(node, "color", rec->color);
+ if (rec->act_color) iconfig_node_set_str(node, "act_color", rec->act_color);
+ if (rec->priority > 0) iconfig_node_set_int(node, "priority", rec->priority);
+ iconfig_node_set_bool(node, "nick", rec->nick);
+ iconfig_node_set_bool(node, "word", rec->word);
+ 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) {
node = iconfig_node_section(node, "channels", NODE_TYPE_LIST);
@@ -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 */
@@ -191,7 +195,7 @@ static HILIGHT_REC *hilight_find(const char *text, char **channels)
}
static int hilight_match_text(HILIGHT_REC *rec, const char *text,
- int *match_beg, int *match_end)
+ int *match_beg, int *match_end)
{
char *match;
@@ -200,9 +204,9 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text,
regmatch_t rmatch[1];
if (rec->regexp_compiled &&
- regexec(&rec->preg, text, 1, rmatch, 0) == 0) {
+ regexec(&rec->preg, text, 1, rmatch, 0) == 0) {
if (rmatch[0].rm_so > 0 &&
- match_beg != NULL && match_end != NULL) {
+ match_beg != NULL && match_end != NULL) {
*match_beg = rmatch[0].rm_so;
*match_end = rmatch[0].rm_eo;
}
@@ -210,9 +214,15 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text,
}
#endif
} else {
- match = rec->fullword ?
- stristr_full(text, rec->text) :
- stristr(text, rec->text);
+ 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);
@@ -222,7 +232,7 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text,
}
}
- return FALSE;
+ return FALSE;
}
#define hilight_match_level(rec, level) \
@@ -267,14 +277,14 @@ HILIGHT_REC *hilight_match(SERVER_REC *server, const char *channel,
HILIGHT_REC *rec = tmp->data;
if (!rec->nickmask && hilight_match_level(rec, level) &&
- hilight_match_channel(rec, channel) &&
- (rec->servertag == NULL ||
- (server != NULL && g_ascii_strcasecmp(rec->servertag, server->tag) == 0)) &&
- hilight_match_text(rec, str, match_beg, match_end))
+ hilight_match_channel(rec, channel) &&
+ (rec->servertag == NULL ||
+ (server != NULL && g_ascii_strcasecmp(rec->servertag, server->tag) == 0)) &&
+ hilight_match_text(rec, str, match_beg, match_end))
return rec;
}
- return NULL;
+ return NULL;
}
static char *hilight_get_act_color(HILIGHT_REC *rec)
@@ -308,7 +318,7 @@ void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec)
g_free_and_null(dest->hilight_color);
if (rec->act_color != NULL && g_strcmp0(rec->act_color, "%n") == 0)
dest->level |= MSGLEVEL_NO_ACT;
- else
+ else
dest->hilight_color = hilight_get_act_color(rec);
}
@@ -362,29 +372,29 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text,
/* hilight whole line */
char *tmp = strip_codes(text);
newstr = g_strconcat(color, tmp, NULL);
- g_free(tmp);
+ g_free(tmp);
} else {
/* hilight part of the line */
- GString *tmp;
- char *middle;
+ GString *tmp;
+ char *middle;
int pos, color_pos, color_len;
- tmp = g_string_new(NULL);
+ tmp = g_string_new(NULL);
- /* start of the line */
+ /* start of the line */
pos = strip_real_length(text, hilight_start, NULL, NULL);
g_string_append(tmp, text);
- g_string_truncate(tmp, pos);
+ g_string_truncate(tmp, pos);
/* color */
- g_string_append(tmp, color);
+ g_string_append(tmp, color);
/* middle of the line, stripped */
middle = strip_codes(text+pos);
- pos = tmp->len;
+ pos = tmp->len;
g_string_append(tmp, middle);
- g_string_truncate(tmp, pos+hilight_len);
- g_free(middle);
+ g_string_truncate(tmp, pos+hilight_len);
+ g_free(middle);
/* end of the line */
pos = strip_real_length(text, hilight_end,
@@ -398,8 +408,8 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text,
}
g_string_append(tmp, text+pos);
- newstr = tmp->str;
- g_string_free(tmp, FALSE);
+ newstr = tmp->str;
+ g_string_free(tmp, FALSE);
}
signal_emit("print text", 3, dest, newstr, stripped);
@@ -417,7 +427,7 @@ HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel,
HILIGHT_REC *rec;
rec = hilight_match(server, channel, nick, address,
- level, msg, NULL, NULL);
+ level, msg, NULL, NULL);
return (rec == NULL || !rec->nick) ? NULL : rec;
}
@@ -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);
@@ -475,7 +486,7 @@ static void read_hilight_config(void)
if (node != NULL) rec->channels = config_node_get_list(node);
}
- reset_cache();
+ reset_cache();
}
static void hilight_print(int index, HILIGHT_REC *rec)
@@ -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
@@ -519,10 +531,10 @@ static void hilight_print(int index, HILIGHT_REC *rec)
if (levelstr != NULL)
levelstr = g_strconcat(levelstr, " ", NULL);
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
- TXT_HILIGHT_LINE, index, rec->text,
- chans != NULL ? chans : "",
- levelstr != NULL ? levelstr : "",
- options->str);
+ TXT_HILIGHT_LINE, index, rec->text,
+ chans != NULL ? chans : "",
+ levelstr != NULL ? levelstr : "",
+ options->str);
g_free_not_null(chans);
g_free_not_null(levelstr);
g_string_free(options, TRUE);
@@ -543,12 +555,12 @@ 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)
{
- GHashTable *optlist;
+ GHashTable *optlist;
HILIGHT_REC *rec;
char *colorarg, *actcolorarg, *levelarg, *priorityarg, *chanarg, *text, *servertag;
char **channels;
@@ -562,7 +574,7 @@ static void cmd_hilight(const char *data)
}
if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
- PARAM_FLAG_GETREST, "hilight", &optlist, &text))
+ PARAM_FLAG_GETREST, "hilight", &optlist, &text))
return;
chanarg = g_hash_table_lookup(optlist, "channels");
@@ -582,7 +594,7 @@ static void cmd_hilight(const char *data)
rec = g_new0(HILIGHT_REC, 1);
/* default to nick/word hilighting */
- rec->nick = TRUE;
+ rec->nick = TRUE;
rec->word = TRUE;
rec->text = g_strdup(text);
@@ -602,15 +614,16 @@ static void cmd_hilight(const char *data)
if (g_hash_table_lookup(optlist, "word") != NULL) {
rec->word = TRUE;
- rec->nick = FALSE;
+ rec->nick = FALSE;
}
if (g_hash_table_lookup(optlist, "nick") != NULL)
- rec->nick = TRUE;
+ rec->nick = TRUE;
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);
@@ -631,7 +644,7 @@ static void cmd_hilight(const char *data)
hilight_create(rec);
hilight_print(g_slist_index(hilights, rec)+1, rec);
- cmd_params_free(free_arg);
+ cmd_params_free(free_arg);
reset_cache();
}
@@ -649,7 +662,7 @@ static void cmd_dehilight(const char *data)
} else {
/* with mask */
char *chans[2] = { "*", NULL };
- rec = hilight_find(data, chans);
+ rec = hilight_find(data, chans);
}
if (rec == NULL)
@@ -657,20 +670,20 @@ static void cmd_dehilight(const char *data)
else {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_HILIGHT_REMOVED, rec->text);
hilight_remove(rec);
- reset_cache();
+ reset_cache();
}
}
static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel,
- NICK_REC *nick)
+ NICK_REC *nick)
{
GSList *tmp;
HILIGHT_REC *match;
- char *nickmask;
+ char *nickmask;
int len, best_match;
if (nick->host == NULL)
- return; /* don't check until host is known */
+ return; /* don't check until host is known */
nickmask = g_strconcat(nick->nick, "!", nick->host, NULL);
@@ -679,8 +692,8 @@ static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel,
HILIGHT_REC *rec = tmp->data;
if (rec->nickmask &&
- hilight_match_channel(rec, channel->name) &&
- match_wildcards(rec->text, nickmask)) {
+ hilight_match_channel(rec, channel->name) &&
+ match_wildcards(rec->text, nickmask)) {
len = strlen(rec->text);
if (best_match < len) {
best_match = len;
@@ -691,7 +704,7 @@ static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel,
g_free_not_null(nickmask);
if (match != NULL)
- g_hash_table_insert(list, nick, match);
+ g_hash_table_insert(list, nick, match);
}
static void read_settings(void)
@@ -706,28 +719,28 @@ void hilight_text_init(void)
settings_add_str("lookandfeel", "hilight_act_color", "%M");
settings_add_level("lookandfeel", "hilight_level", "PUBLIC DCCMSGS");
- read_settings();
+ read_settings();
nickmatch = nickmatch_init(hilight_nick_cache);
read_hilight_config();
signal_add_first("print text", (SIGNAL_FUNC) sig_print_text);
- signal_add("setup reread", (SIGNAL_FUNC) read_hilight_config);
- signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+ signal_add("setup reread", (SIGNAL_FUNC) read_hilight_config);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
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)
{
hilights_destroy_all();
- nickmatch_deinit(nickmatch);
+ nickmatch_deinit(nickmatch);
signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
- signal_remove("setup reread", (SIGNAL_FUNC) read_hilight_config);
- signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+ signal_remove("setup reread", (SIGNAL_FUNC) read_hilight_config);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
command_unbind("hilight", (SIGNAL_FUNC) cmd_hilight);
command_unbind("dehilight", (SIGNAL_FUNC) cmd_dehilight);
diff --git a/src/fe-common/core/hilight-text.h b/src/fe-common/core/hilight-text.h
index 3c897def..ae05e1ca 100644
--- a/src/fe-common/core/hilight-text.h
+++ b/src/fe-common/core/hilight-text.h
@@ -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;
diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c
index e6d32b6d..5c07f14c 100644
--- a/src/fe-common/core/module-formats.c
+++ b/src/fe-common/core/module-formats.c
@@ -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 },
diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h
index 3f06bb97..2b45ff6b 100644
--- a/src/fe-common/core/module-formats.h
+++ b/src/fe-common/core/module-formats.h
@@ -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,
diff --git a/src/fe-common/core/module.h b/src/fe-common/core/module.h
index 51b61b3e..db712ec7 100644
--- a/src/fe-common/core/module.h
+++ b/src/fe-common/core/module.h
@@ -2,7 +2,7 @@
#define MODULE_NAME "fe-common/core"
-typedef guint32 unichar;
+#include "utf8.h"
typedef struct {
time_t time;
char *nick;
diff --git a/src/fe-common/core/themes.c b/src/fe-common/core/themes.c
index 58e7b557..2b1459be 100644
--- a/src/fe-common/core/themes.c
+++ b/src/fe-common/core/themes.c
@@ -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) {
diff --git a/src/fe-common/core/utf8.c b/src/fe-common/core/utf8.c
deleted file mode 100644
index 2d07ea8e..00000000
--- a/src/fe-common/core/utf8.c
+++ /dev/null
@@ -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"
-
diff --git a/src/fe-common/core/utf8.h b/src/fe-common/core/utf8.h
deleted file mode 100644
index 3c15dc7d..00000000
--- a/src/fe-common/core/utf8.h
+++ /dev/null
@@ -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
diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c
index 2cb99a2f..2e22d6f2 100644
--- a/src/fe-common/irc/fe-irc-server.c
+++ b/src/fe-common/irc/fe-irc-server.c
@@ -50,12 +50,13 @@ 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>]
- [-ssl_verify] [-ssl_cafile <cafile>] [-ssl_capath <capath>]
- [-ssl_ciphers <list>]
- [-auto | -noauto] [-network <network>] [-host <hostname>]
- [-cmdspeed <ms>] [-cmdmax <count>] [-port <port>]
- <address> [<port> [<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>]
+ [-cmdspeed <ms>] [-cmdmax <count>] [-port <port>]
+ <address> [<port> [<password>]] */
/* NOTE: -network replaces the old -ircnet flag. */
static void sig_server_add_fill(IRC_SERVER_SETUP_REC *rec,
GHashTable *optlist)
diff --git a/src/fe-common/irc/fe-ircnet.c b/src/fe-common/irc/fe-ircnet.c
index 4d7037d5..b70a9ea7 100644
--- a/src/fe-common/irc/fe-ircnet.c
+++ b/src/fe-common/irc/fe-ircnet.c
@@ -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;
@@ -103,12 +96,20 @@ static void cmd_network_add(const char *data)
IRC_CHATNET_REC *rec;
if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
- "network add", &optlist, &name))
+ "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);
}
diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am
index b9538e60..bdd3df22 100644
--- a/src/fe-text/Makefile.am
+++ b/src/fe-text/Makefile.am
@@ -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)
diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c
index 306141ec..f05decd2 100644
--- a/src/fe-text/gui-entry.c
+++ b/src/fe-text/gui-entry.c
@@ -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,
- size * sizeof(unichar));
+ 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)
diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h
index 29d8dea2..8777f083 100644
--- a/src/fe-text/gui-entry.h
+++ b/src/fe-text/gui-entry.h
@@ -2,11 +2,15 @@
#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
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c
index af560894..7c71edd7 100644
--- a/src/fe-text/gui-readline.c
+++ b/src/fe-text/gui-readline.c
@@ -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,7 +600,36 @@ static void key_yank_from_cutbuffer(void)
cutbuffer = gui_entry_get_cutbuffer(active_entry);
if (cutbuffer != NULL) {
gui_entry_insert_text(active_entry, cutbuffer);
- g_free(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,8 +712,9 @@ 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 &&
- active_win->active != NULL)
+ (paste_line_count >= paste_verify_line_count ||
+ split_lines > paste_verify_line_count) &&
+ active_win->active != NULL)
insert_paste_prompt();
else
paste_flush(TRUE);
@@ -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);
diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c
index cad271c9..ad79e0c4 100644
--- a/src/fe-text/irssi.c
+++ b/src/fe-text/irssi.c
@@ -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,27 +168,22 @@ static void textui_finish_init(void)
{
quitting = FALSE;
- if (dummy)
- term_dummy_init();
- else {
- term_refresh_freeze();
- textbuffer_init();
- textbuffer_view_init();
- textbuffer_commands_init();
- gui_expandos_init();
- gui_printtext_init();
- gui_readline_init();
- lastlog_init();
- mainwindows_init();
- mainwindow_activity_init();
- mainwindows_layout_init();
- gui_windows_init();
- statusbar_init();
- term_refresh_thaw();
-
- /* don't check settings with dummy mode */
- settings_check();
- }
+ term_refresh_freeze();
+ textbuffer_init();
+ textbuffer_view_init();
+ textbuffer_commands_init();
+ gui_expandos_init();
+ gui_printtext_init();
+ gui_readline_init();
+ lastlog_init();
+ mainwindows_init();
+ mainwindow_activity_init();
+ mainwindows_layout_init();
+ gui_windows_init();
+ statusbar_init();
+ term_refresh_thaw();
+
+ settings_check();
module_register("core", "fe-text");
@@ -233,25 +225,21 @@ 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();
- gui_readline_deinit();
- gui_windows_deinit();
- mainwindows_layout_deinit();
- mainwindow_activity_deinit();
- mainwindows_deinit();
- gui_expandos_deinit();
- textbuffer_commands_deinit();
- textbuffer_view_deinit();
- textbuffer_deinit();
-
- term_refresh_thaw();
- term_deinit();
- }
+ lastlog_deinit();
+ statusbar_deinit();
+ gui_printtext_deinit();
+ gui_readline_deinit();
+ gui_windows_deinit();
+ mainwindows_layout_deinit();
+ mainwindow_activity_deinit();
+ mainwindows_deinit();
+ gui_expandos_deinit();
+ textbuffer_commands_deinit();
+ textbuffer_view_deinit();
+ textbuffer_deinit();
+
+ 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 */
diff --git a/src/fe-text/lastlog.c b/src/fe-text/lastlog.c
index 166d2847..c0b1dde8 100644
--- a/src/fe-text/lastlog.c
+++ b/src/fe-text/lastlog.c
@@ -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;
diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c
index e3e0c2a6..0db4f63a 100644
--- a/src/fe-text/statusbar-items.c
+++ b/src/fe-text/statusbar-items.c
@@ -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");
diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c
index 5448243a..f0dff828 100644
--- a/src/fe-text/statusbar.c
+++ b/src/fe-text/statusbar.c
@@ -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);
diff --git a/src/fe-text/term-curses.c b/src/fe-text/term-curses.c
deleted file mode 100644
index 752edd7f..00000000
--- a/src/fe-text/term-curses.c
+++ /dev/null
@@ -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)++;
- }
-}
diff --git a/src/fe-text/term-dummy.c b/src/fe-text/term-dummy.c
deleted file mode 100644
index 6a56af88..00000000
--- a/src/fe-text/term-dummy.c
+++ /dev/null
@@ -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);
-}
diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c
index 27be904e..b2478c62 100644
--- a/src/fe-text/term-terminfo.c
+++ b/src/fe-text/term-terminfo.c
@@ -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)
diff --git a/src/fe-text/term.h b/src/fe-text/term.h
index 9b726d82..0c7847f6 100644
--- a/src/fe-text/term.h
+++ b/src/fe-text/term.h
@@ -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;
diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c
index 15b00081..9c9179a5 100644
--- a/src/fe-text/terminfo-core.c
+++ b/src/fe-text/terminfo-core.c
@@ -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);
diff --git a/src/fe-text/tparm.c b/src/fe-text/tparm.c
deleted file mode 100644
index 97c790da..00000000
--- a/src/fe-text/tparm.c
+++ /dev/null
@@ -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;
-}
diff --git a/src/irc/core/irc-channels-setup.c b/src/irc/core/irc-channels-setup.c
index 2320352d..bbbc095c 100644
--- a/src/irc/core/irc-channels-setup.c
+++ b/src/irc/core/irc-channels-setup.c
@@ -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);
}
diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c
index bcb9d1f6..b22f3269 100644
--- a/src/irc/core/irc-nicklist.c
+++ b/src/irc/core/irc-nicklist.c
@@ -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);
diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c
index f905a862..8148997b 100644
--- a/src/irc/core/irc-servers.c
+++ b/src/irc/core/irc-servers.c
@@ -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", "");
diff --git a/src/irc/dcc/dcc-chat.c b/src/irc/dcc/dcc-chat.c
index e3dbe72d..ca90b8d8 100644
--- a/src/irc/dcc/dcc-chat.c
+++ b/src/irc/dcc/dcc-chat.c
@@ -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);
diff --git a/src/irc/dcc/dcc-get.c b/src/irc/dcc/dcc-get.c
index a8b1c967..f7a95bb9 100644
--- a/src/irc/dcc/dcc-get.c
+++ b/src/irc/dcc/dcc-get.c
@@ -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,8 +473,8 @@ 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,
- sizeof(temp_dcc->addrstr));
+ g_strlcpy(temp_dcc->addrstr, address,
+ sizeof(temp_dcc->addrstr));
}
/* This new signal is added to let us invoke
@@ -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;
diff --git a/src/irc/dcc/dcc-resume.c b/src/irc/dcc/dcc-resume.c
index 11b28aef..36f84ddf 100644
--- a/src/irc/dcc/dcc-resume.c
+++ b/src/irc/dcc/dcc-resume.c
@@ -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;
diff --git a/src/irc/dcc/dcc-server.c b/src/irc/dcc/dcc-server.c
index 30224ff9..7ae572cd 100644
--- a/src/irc/dcc/dcc-server.c
+++ b/src/irc/dcc/dcc-server.c
@@ -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);
diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c
index 17f6c477..c51f7c7a 100644
--- a/src/irc/dcc/dcc.c
+++ b/src/irc/dcc/dcc.c
@@ -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;
}
diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c
index 5dc9a704..cde4c0be 100644
--- a/src/irc/proxy/listen.c
+++ b/src/irc/proxy/listen.c
@@ -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,18 +110,18 @@ 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);
}
static void proxy_redirect_event(CLIENT_REC *client, const char *command,
- int count, const char *arg, int remote)
+ int count, const char *arg, int remote)
{
char *str;
@@ -67,7 +129,7 @@ static void proxy_redirect_event(CLIENT_REC *client, const char *command,
str = g_strdup_printf("proxy %p", client);
server_redirect_event(client->server, command, count,
- arg, remote, NULL, "", str, NULL);
+ arg, remote, NULL, "", str, NULL);
g_free(str);
}
@@ -94,28 +156,58 @@ static void grab_who(CLIENT_REC *client, const char *channel)
}
proxy_redirect_event(client, "who",
- client->server->one_endofwho ? 1 : count,
- arg->str, -1);
+ client->server->one_endofwho ? 1 : count,
+ arg->str, -1);
g_strfreev(list);
g_string_free(arg, TRUE);
}
static void handle_client_connect_cmd(CLIENT_REC *client,
- const char *cmd, const char *args)
+ const char *cmd, const char *args)
{
const char *password;
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;
+ 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);
}
@@ -139,7 +231,7 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
}
static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
- const char *data)
+ const char *data)
{
GSList *tmp;
if (!client->connected) {
@@ -162,8 +254,8 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
g_ascii_strcasecmp(target, client->proxy_address) == 0 ||
g_ascii_strcasecmp(target, client->nick) == 0) {
proxy_outdata(client, ":%s PONG %s :%s\r\n",
- client->proxy_address,
- client->proxy_address, origin);
+ client->proxy_address,
+ client->proxy_address, origin);
g_free(params);
return;
}
@@ -172,27 +264,27 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
if (g_strcmp0(cmd, "PROXY") == 0) {
if (g_ascii_strcasecmp(args, "CTCP ON") == 0) {
- /* client wants all ctcps */
+ /* client wants all ctcps */
client->want_ctcp = 1;
- for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) {
+ 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) &&
- /* kludgy way to check if the clients aren't the same */
- (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);
- rec->want_ctcp = 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) {
+ 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);
+ rec->want_ctcp = 0;
+ }
}
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 wants proxy to handle all ctcps */
client->want_ctcp = 0;
proxy_outdata(client, ":%s NOTICE %s :Proxy is now handling itself CTCPs sent to %s\r\n",
- client->proxy_address, client->nick, client->listen->ircnet);
+ client->proxy_address, client->nick, client->listen->ircnet);
} else {
signal_emit("proxy client command", 3, client, args, data);
}
@@ -201,11 +293,11 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
if (client->server == NULL || !client->server->connected) {
proxy_outdata(client, ":%s NOTICE %s :Not connected to server\r\n",
- client->proxy_address, client->nick);
- return;
+ client->proxy_address, client->nick);
+ return;
}
- /* check if the command could be redirected */
+ /* check if the command could be redirected */
if (g_strcmp0(cmd, "WHO") == 0)
grab_who(client, args);
else if (g_strcmp0(cmd, "WHOWAS") == 0)
@@ -263,29 +355,29 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
char *params, *target, *msg;
params = event_get_params(args, 2 | PARAM_FLAG_GETREST,
- &target, &msg);
+ &target, &msg);
proxy_outserver_all_except(client, "PRIVMSG %s", args);
ignore_next = TRUE;
if (*msg != '\001' || msg[strlen(msg)-1] != '\001') {
signal_emit(server_ischannel(SERVER(client->server), target) ?
- "message own_public" : "message own_private", 4,
- client->server, msg, target, target);
+ "message own_public" : "message own_private", 4,
+ client->server, msg, target, target);
} else if (strncmp(msg+1, "ACTION ", 7) == 0) {
/* action */
- msg[strlen(msg)-1] = '\0';
+ msg[strlen(msg)-1] = '\0';
signal_emit("message irc own_action", 3,
- client->server, msg+8, target);
+ client->server, msg+8, target);
} else {
- /* CTCP */
+ /* CTCP */
char *p;
msg[strlen(msg)-1] = '\0';
p = strchr(msg, ' ');
- if (p != NULL) *p++ = '\0'; else p = "";
+ if (p != NULL) *p++ = '\0'; else p = "";
signal_emit("message irc own_ctcp", 4,
- client->server, msg+1, p, target);
+ client->server, msg+1, p, target);
}
ignore_next = FALSE;
g_free(params);
@@ -337,24 +429,38 @@ static void sig_listen(LISTEN_REC *listen)
CLIENT_REC *rec;
IPADDR ip;
NET_SENDBUF_REC *sendbuf;
- GIOChannel *handle;
+ GIOChannel *handle;
char host[MAX_IP_LEN];
int port;
+ char *addr;
g_return_if_fail(listen != NULL);
/* accept connection */
- handle = net_accept(listen->handle, &ip, &port);
- if (handle == NULL)
- return;
- net_ip2host(&ip, host);
+ 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 {
@@ -363,15 +469,15 @@ static void sig_listen(LISTEN_REC *listen)
IRC_SERVER(server_find_chatnet(listen->ircnet));
}
rec->recv_tag = g_input_add(handle, G_INPUT_READ,
- (GInputFunction) sig_listen_client, rec);
+ (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)
@@ -460,12 +566,12 @@ static void sig_server_event(IRC_SERVER_REC *server, const char *line,
static void event_connected(IRC_SERVER_REC *server)
{
GSList *tmp;
- const char *chatnet;
+ const char *chatnet;
if (!IS_IRC_SERVER(server))
return;
- chatnet = server->connrec->chatnet;
+ chatnet = server->connrec->chatnet;
for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) {
CLIENT_REC *rec = tmp->data;
@@ -474,7 +580,7 @@ static void event_connected(IRC_SERVER_REC *server)
(chatnet != NULL &&
g_ascii_strcasecmp(chatnet, rec->listen->ircnet) == 0))) {
proxy_outdata(rec, ":%s NOTICE %s :Connected to server\r\n",
- rec->proxy_address, rec->nick);
+ rec->proxy_address, rec->nick);
rec->server = server;
proxy_client_reset_nick(rec);
}
@@ -482,7 +588,7 @@ static void event_connected(IRC_SERVER_REC *server)
}
static void proxy_server_disconnected(CLIENT_REC *client,
- IRC_SERVER_REC *server)
+ IRC_SERVER_REC *server)
{
GSList *tmp;
@@ -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,48 +693,53 @@ 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;
- /* bind to specific host/ip? */
- my_ip = NULL;
- if (*settings_get_str("irssiproxy_bind") != '\0') {
- if (net_gethostbyname(settings_get_str("irssiproxy_bind"),
- &ip4, &ip6) != 0) {
- printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
- "Proxy: can not resolve '%s' - aborting",
- settings_get_str("irssiproxy_bind"));
- 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') {
+ if (net_gethostbyname(settings_get_str("irssiproxy_bind"),
+ &ip4, &ip6) != 0) {
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "Proxy: can not resolve '%s' - aborting",
+ settings_get_str("irssiproxy_bind"));
+ return;
+ }
+
+ my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 ||
+ settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4;
}
+ handle = net_listen(my_ip, &port);
+ }
- my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 ||
- settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4;
+ if (handle == NULL) {
+ printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ "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->handle = net_listen(my_ip, &rec->port);
-
- if (rec->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);
- return;
- }
+ rec->port_or_path = g_strdup(port_or_path);
rec->tag = g_input_add(rec->handle, G_INPUT_READ,
- (GInputFunction) sig_listen, rec);
+ (GInputFunction) sig_listen, rec);
- proxy_listens = g_slist_append(proxy_listens, rec);
+ proxy_listens = g_slist_append(proxy_listens, rec);
}
static void remove_listen(LISTEN_REC *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);
- if (portnum <= 0)
- continue;
+ *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);
}
diff --git a/src/irc/proxy/proxy.c b/src/irc/proxy/proxy.c
index 50a41b21..2875d2c2 100644
--- a/src/irc/proxy/proxy.c
+++ b/src/irc/proxy/proxy.c
@@ -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);
}
}
diff --git a/src/irc/proxy/proxy.h b/src/irc/proxy/proxy.h
index 158b0675..620ea605 100644
--- a/src/irc/proxy/proxy.h
+++ b/src/irc/proxy/proxy.h
@@ -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
diff --git a/src/perl/Makefile.am b/src/perl/Makefile.am
index a09c49a5..427c5492 100644
--- a/src/perl/Makefile.am
+++ b/src/perl/Makefile.am
@@ -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)) && \
diff --git a/src/perl/Makefile_silent.pm b/src/perl/Makefile_silent.pm
new file mode 100644
index 00000000..b5d71d66
--- /dev/null
+++ b/src/perl/Makefile_silent.pm
@@ -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;
diff --git a/src/perl/common/Expando.xs b/src/perl/common/Expando.xs
index e8e8f751..26800b05 100644
--- a/src/perl/common/Expando.xs
+++ b/src/perl/common/Expando.xs
@@ -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;
diff --git a/src/perl/common/Makefile.PL.in b/src/perl/common/Makefile.PL.in
index 4e545e7c..84a80403 100644
--- a/src/perl/common/Makefile.PL.in
+++ b/src/perl/common/Makefile.PL.in
@@ -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' => '',
diff --git a/src/perl/irc/Irc.xs b/src/perl/irc/Irc.xs
index db5c5f79..3f8ccc2e 100644
--- a/src/perl/irc/Irc.xs
+++ b/src/perl/irc/Irc.xs
@@ -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);
}
diff --git a/src/perl/irc/Makefile.PL.in b/src/perl/irc/Makefile.PL.in
index 8f1e94d5..0fbc5241 100644
--- a/src/perl/irc/Makefile.PL.in
+++ b/src/perl/irc/Makefile.PL.in
@@ -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' => '',
diff --git a/src/perl/perl-core.c b/src/perl/perl-core.c
index cb690906..2c61df70 100644
--- a/src/perl/perl-core.c
+++ b/src/perl/perl-core.c
@@ -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;
diff --git a/src/perl/perl-core.h b/src/perl/perl-core.h
index b451cc5c..7390a6fd 100644
--- a/src/perl/perl-core.h
+++ b/src/perl/perl-core.h
@@ -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);
diff --git a/src/perl/perl-fe.c b/src/perl/perl-fe.c
index 04305b63..396c80b7 100644
--- a/src/perl/perl-fe.c
+++ b/src/perl/perl-fe.c
@@ -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);
diff --git a/src/perl/perl-signals.c b/src/perl/perl-signals.c
index 007f7ad5..8f993660 100644
--- a/src/perl/perl-signals.c
+++ b/src/perl/perl-signals.c
@@ -433,8 +433,9 @@ 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) && \
- g_strcmp0(SvPV_nolen(f1), SvPV_nolen(f2)) == 0))
+ ((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)
{
diff --git a/src/perl/textui/Makefile.PL.in b/src/perl/textui/Makefile.PL.in
index 9e80274b..3541f75c 100644
--- a/src/perl/textui/Makefile.PL.in
+++ b/src/perl/textui/Makefile.PL.in
@@ -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' => '',
diff --git a/src/perl/textui/Statusbar.xs b/src/perl/textui/Statusbar.xs
index a449e11d..8b0e5f65 100644
--- a/src/perl/textui/Statusbar.xs
+++ b/src/perl/textui/Statusbar.xs
@@ -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);
diff --git a/src/perl/ui/Makefile.PL.in b/src/perl/ui/Makefile.PL.in
index a349918e..ed87d528 100644
--- a/src/perl/ui/Makefile.PL.in
+++ b/src/perl/ui/Makefile.PL.in
@@ -1,4 +1,4 @@
-use ExtUtils::MakeMaker;
+use ExtUtils::MakeMaker;our $AM_DEFAULT_VERBOSITY='@AM_DEFAULT_VERBOSITY@';require "../Makefile_silent.pm";
WriteMakefile('NAME' => 'Irssi::UI',
'LIBS' => '',