summaryrefslogtreecommitdiffstats
path: root/src/fe-common/irc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 20:18:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 20:18:39 +0000
commitfff5217f02d91268ce90c8c05665602c059faaef (patch)
tree2ba24d32dc96eafe7ed0a85269548e76796d849d /src/fe-common/irc
parentInitial commit. (diff)
downloadirssi-fff5217f02d91268ce90c8c05665602c059faaef.tar.xz
irssi-fff5217f02d91268ce90c8c05665602c059faaef.zip
Adding upstream version 1.4.5.upstream/1.4.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/fe-common/irc')
-rw-r--r--src/fe-common/irc/Makefile.am42
-rw-r--r--src/fe-common/irc/Makefile.in929
-rw-r--r--src/fe-common/irc/dcc/Makefile.am24
-rw-r--r--src/fe-common/irc/dcc/Makefile.in750
-rw-r--r--src/fe-common/irc/dcc/fe-dcc-chat-messages.c164
-rw-r--r--src/fe-common/irc/dcc/fe-dcc-chat.c385
-rw-r--r--src/fe-common/irc/dcc/fe-dcc-get.c150
-rw-r--r--src/fe-common/irc/dcc/fe-dcc-send.c186
-rw-r--r--src/fe-common/irc/dcc/fe-dcc-server.c83
-rw-r--r--src/fe-common/irc/dcc/fe-dcc.c195
-rw-r--r--src/fe-common/irc/dcc/fe-dcc.h7
-rw-r--r--src/fe-common/irc/dcc/meson.build27
-rw-r--r--src/fe-common/irc/dcc/module-formats.c79
-rw-r--r--src/fe-common/irc/dcc/module-formats.h57
-rw-r--r--src/fe-common/irc/dcc/module.h4
-rw-r--r--src/fe-common/irc/fe-cap.c84
-rw-r--r--src/fe-common/irc/fe-common-irc.c134
-rw-r--r--src/fe-common/irc/fe-ctcp.c170
-rw-r--r--src/fe-common/irc/fe-events-numeric.c903
-rw-r--r--src/fe-common/irc/fe-events.c550
-rw-r--r--src/fe-common/irc/fe-irc-channels.c111
-rw-r--r--src/fe-common/irc/fe-irc-channels.h10
-rw-r--r--src/fe-common/irc/fe-irc-commands.c448
-rw-r--r--src/fe-common/irc/fe-irc-messages.c373
-rw-r--r--src/fe-common/irc/fe-irc-queries.c101
-rw-r--r--src/fe-common/irc/fe-irc-server.c201
-rw-r--r--src/fe-common/irc/fe-irc-server.h9
-rw-r--r--src/fe-common/irc/fe-ircnet.c249
-rw-r--r--src/fe-common/irc/fe-modes.c236
-rw-r--r--src/fe-common/irc/fe-netjoin.c515
-rw-r--r--src/fe-common/irc/fe-netsplit.c389
-rw-r--r--src/fe-common/irc/fe-sasl.c53
-rw-r--r--src/fe-common/irc/fe-whois.c456
-rw-r--r--src/fe-common/irc/irc-completion.c41
-rw-r--r--src/fe-common/irc/irc-modules.c4
-rw-r--r--src/fe-common/irc/meson.build44
-rw-r--r--src/fe-common/irc/module-formats.c184
-rw-r--r--src/fe-common/irc/module-formats.h154
-rw-r--r--src/fe-common/irc/module.h4
-rw-r--r--src/fe-common/irc/notifylist/Makefile.am18
-rw-r--r--src/fe-common/irc/notifylist/Makefile.in725
-rw-r--r--src/fe-common/irc/notifylist/fe-notifylist.c250
-rw-r--r--src/fe-common/irc/notifylist/meson.build21
-rw-r--r--src/fe-common/irc/notifylist/module-formats.c41
-rw-r--r--src/fe-common/irc/notifylist/module-formats.h18
-rw-r--r--src/fe-common/irc/notifylist/module.h4
46 files changed, 9582 insertions, 0 deletions
diff --git a/src/fe-common/irc/Makefile.am b/src/fe-common/irc/Makefile.am
new file mode 100644
index 0000000..8a04bee
--- /dev/null
+++ b/src/fe-common/irc/Makefile.am
@@ -0,0 +1,42 @@
+SUBDIRS = dcc notifylist
+
+noinst_LIBRARIES = libfe_common_irc.a
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DHELPDIR=\""$(datadir)/irssi/help"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+real_sources = \
+ fe-irc-channels.c \
+ fe-irc-commands.c \
+ fe-irc-messages.c \
+ fe-irc-queries.c \
+ fe-irc-server.c \
+ fe-ircnet.c \
+ fe-ctcp.c \
+ fe-events.c \
+ fe-events-numeric.c \
+ fe-modes.c \
+ fe-netjoin.c \
+ fe-netsplit.c \
+ fe-common-irc.c \
+ fe-whois.c \
+ fe-sasl.c \
+ fe-cap.c \
+ irc-completion.c \
+ module-formats.c
+
+libfe_common_irc_a_SOURCES = \
+ $(real_sources) \
+ irc-modules.c
+
+pkginc_fe_common_ircdir=$(pkgincludedir)/src/fe-common/irc
+pkginc_fe_common_irc_HEADERS = \
+ fe-irc-server.h \
+ fe-irc-channels.h \
+ module.h \
+ module-formats.h
+
+EXTRA_DIST = meson.build
diff --git a/src/fe-common/irc/Makefile.in b/src/fe-common/irc/Makefile.in
new file mode 100644
index 0000000..202076b
--- /dev/null
+++ b/src/fe-common/irc/Makefile.in
@@ -0,0 +1,929 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/fe-common/irc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \
+ $(top_srcdir)/m4/glibtests.m4 $(top_srcdir)/m4/libgcrypt.m4 \
+ $(top_srcdir)/m4/libotr.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_fe_common_irc_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/irssi-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libfe_common_irc_a_AR = $(AR) $(ARFLAGS)
+libfe_common_irc_a_LIBADD =
+am__objects_1 = fe-irc-channels.$(OBJEXT) fe-irc-commands.$(OBJEXT) \
+ fe-irc-messages.$(OBJEXT) fe-irc-queries.$(OBJEXT) \
+ fe-irc-server.$(OBJEXT) fe-ircnet.$(OBJEXT) fe-ctcp.$(OBJEXT) \
+ fe-events.$(OBJEXT) fe-events-numeric.$(OBJEXT) \
+ fe-modes.$(OBJEXT) fe-netjoin.$(OBJEXT) fe-netsplit.$(OBJEXT) \
+ fe-common-irc.$(OBJEXT) fe-whois.$(OBJEXT) fe-sasl.$(OBJEXT) \
+ fe-cap.$(OBJEXT) irc-completion.$(OBJEXT) \
+ module-formats.$(OBJEXT)
+am_libfe_common_irc_a_OBJECTS = $(am__objects_1) irc-modules.$(OBJEXT)
+libfe_common_irc_a_OBJECTS = $(am_libfe_common_irc_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES =
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/fe-cap.Po \
+ ./$(DEPDIR)/fe-common-irc.Po ./$(DEPDIR)/fe-ctcp.Po \
+ ./$(DEPDIR)/fe-events-numeric.Po ./$(DEPDIR)/fe-events.Po \
+ ./$(DEPDIR)/fe-irc-channels.Po ./$(DEPDIR)/fe-irc-commands.Po \
+ ./$(DEPDIR)/fe-irc-messages.Po ./$(DEPDIR)/fe-irc-queries.Po \
+ ./$(DEPDIR)/fe-irc-server.Po ./$(DEPDIR)/fe-ircnet.Po \
+ ./$(DEPDIR)/fe-modes.Po ./$(DEPDIR)/fe-netjoin.Po \
+ ./$(DEPDIR)/fe-netsplit.Po ./$(DEPDIR)/fe-sasl.Po \
+ ./$(DEPDIR)/fe-whois.Po ./$(DEPDIR)/irc-completion.Po \
+ ./$(DEPDIR)/irc-modules.Po ./$(DEPDIR)/module-formats.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libfe_common_irc_a_SOURCES)
+DIST_SOURCES = $(libfe_common_irc_a_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_fe_common_ircdir)"
+HEADERS = $(pkginc_fe_common_irc_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHAT_MODULES = @CHAT_MODULES@
+COMMON_LIBS = @COMMON_LIBS@
+COMMON_NOUI_LIBS = @COMMON_NOUI_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FUZZER_LIBS = @FUZZER_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOTR_CFLAGS = @LIBOTR_CFLAGS@
+LIBOTR_LIBS = @LIBOTR_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+OTR_CFLAGS = @OTR_CFLAGS@
+OTR_LDFLAGS = @OTR_LDFLAGS@
+OTR_LINK_FLAGS = @OTR_LINK_FLAGS@
+OTR_LINK_LIBS = @OTR_LINK_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL_CFLAGS = @PERL_CFLAGS@
+PERL_EXTRA_OPTS = @PERL_EXTRA_OPTS@
+PERL_FE_LINK_LIBS = @PERL_FE_LINK_LIBS@
+PERL_LDFLAGS = @PERL_LDFLAGS@
+PERL_LINK_FLAGS = @PERL_LINK_FLAGS@
+PERL_LINK_LIBS = @PERL_LINK_LIBS@
+PERL_MM_OPT = @PERL_MM_OPT@
+PERL_MM_PARAMS = @PERL_MM_PARAMS@
+PERL_STATIC_LIBS = @PERL_STATIC_LIBS@
+PERL_USE_LIB = @PERL_USE_LIB@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROG_LIBS = @PROG_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TEXTUI_LIBS = @TEXTUI_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+installed_test_metadir = @installed_test_metadir@
+installed_testdir = @installed_testdir@
+irc_MODULES = @irc_MODULES@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+otr_module_lib = @otr_module_lib@
+otr_static_lib = @otr_static_lib@
+pdfdir = @pdfdir@
+perl_module_fe_lib = @perl_module_fe_lib@
+perl_module_lib = @perl_module_lib@
+perl_static_fe_lib = @perl_static_fe_lib@
+perl_static_lib = @perl_static_lib@
+perlpath = @perlpath@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sedpath = @sedpath@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = dcc notifylist
+noinst_LIBRARIES = libfe_common_irc.a
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DHELPDIR=\""$(datadir)/irssi/help"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+real_sources = \
+ fe-irc-channels.c \
+ fe-irc-commands.c \
+ fe-irc-messages.c \
+ fe-irc-queries.c \
+ fe-irc-server.c \
+ fe-ircnet.c \
+ fe-ctcp.c \
+ fe-events.c \
+ fe-events-numeric.c \
+ fe-modes.c \
+ fe-netjoin.c \
+ fe-netsplit.c \
+ fe-common-irc.c \
+ fe-whois.c \
+ fe-sasl.c \
+ fe-cap.c \
+ irc-completion.c \
+ module-formats.c
+
+libfe_common_irc_a_SOURCES = \
+ $(real_sources) \
+ irc-modules.c
+
+pkginc_fe_common_ircdir = $(pkgincludedir)/src/fe-common/irc
+pkginc_fe_common_irc_HEADERS = \
+ fe-irc-server.h \
+ fe-irc-channels.h \
+ module.h \
+ module-formats.h
+
+EXTRA_DIST = meson.build
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/fe-common/irc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/fe-common/irc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libfe_common_irc.a: $(libfe_common_irc_a_OBJECTS) $(libfe_common_irc_a_DEPENDENCIES) $(EXTRA_libfe_common_irc_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libfe_common_irc.a
+ $(AM_V_AR)$(libfe_common_irc_a_AR) libfe_common_irc.a $(libfe_common_irc_a_OBJECTS) $(libfe_common_irc_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libfe_common_irc.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-cap.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-common-irc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-ctcp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-events-numeric.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-events.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-irc-channels.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-irc-commands.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-irc-messages.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-irc-queries.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-irc-server.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-ircnet.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-modes.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-netjoin.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-netsplit.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-sasl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-whois.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-completion.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc-modules.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module-formats.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_fe_common_ircHEADERS: $(pkginc_fe_common_irc_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_fe_common_irc_HEADERS)'; test -n "$(pkginc_fe_common_ircdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_fe_common_ircdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_fe_common_ircdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_fe_common_ircdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_fe_common_ircdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_fe_common_ircHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_fe_common_irc_HEADERS)'; test -n "$(pkginc_fe_common_ircdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_fe_common_ircdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(pkginc_fe_common_ircdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/fe-cap.Po
+ -rm -f ./$(DEPDIR)/fe-common-irc.Po
+ -rm -f ./$(DEPDIR)/fe-ctcp.Po
+ -rm -f ./$(DEPDIR)/fe-events-numeric.Po
+ -rm -f ./$(DEPDIR)/fe-events.Po
+ -rm -f ./$(DEPDIR)/fe-irc-channels.Po
+ -rm -f ./$(DEPDIR)/fe-irc-commands.Po
+ -rm -f ./$(DEPDIR)/fe-irc-messages.Po
+ -rm -f ./$(DEPDIR)/fe-irc-queries.Po
+ -rm -f ./$(DEPDIR)/fe-irc-server.Po
+ -rm -f ./$(DEPDIR)/fe-ircnet.Po
+ -rm -f ./$(DEPDIR)/fe-modes.Po
+ -rm -f ./$(DEPDIR)/fe-netjoin.Po
+ -rm -f ./$(DEPDIR)/fe-netsplit.Po
+ -rm -f ./$(DEPDIR)/fe-sasl.Po
+ -rm -f ./$(DEPDIR)/fe-whois.Po
+ -rm -f ./$(DEPDIR)/irc-completion.Po
+ -rm -f ./$(DEPDIR)/irc-modules.Po
+ -rm -f ./$(DEPDIR)/module-formats.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkginc_fe_common_ircHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/fe-cap.Po
+ -rm -f ./$(DEPDIR)/fe-common-irc.Po
+ -rm -f ./$(DEPDIR)/fe-ctcp.Po
+ -rm -f ./$(DEPDIR)/fe-events-numeric.Po
+ -rm -f ./$(DEPDIR)/fe-events.Po
+ -rm -f ./$(DEPDIR)/fe-irc-channels.Po
+ -rm -f ./$(DEPDIR)/fe-irc-commands.Po
+ -rm -f ./$(DEPDIR)/fe-irc-messages.Po
+ -rm -f ./$(DEPDIR)/fe-irc-queries.Po
+ -rm -f ./$(DEPDIR)/fe-irc-server.Po
+ -rm -f ./$(DEPDIR)/fe-ircnet.Po
+ -rm -f ./$(DEPDIR)/fe-modes.Po
+ -rm -f ./$(DEPDIR)/fe-netjoin.Po
+ -rm -f ./$(DEPDIR)/fe-netsplit.Po
+ -rm -f ./$(DEPDIR)/fe-sasl.Po
+ -rm -f ./$(DEPDIR)/fe-whois.Po
+ -rm -f ./$(DEPDIR)/irc-completion.Po
+ -rm -f ./$(DEPDIR)/irc-modules.Po
+ -rm -f ./$(DEPDIR)/module-formats.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_fe_common_ircHEADERS
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-am clean clean-generic clean-libtool \
+ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkginc_fe_common_ircHEADERS \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-pkginc_fe_common_ircHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/fe-common/irc/dcc/Makefile.am b/src/fe-common/irc/dcc/Makefile.am
new file mode 100644
index 0000000..feee349
--- /dev/null
+++ b/src/fe-common/irc/dcc/Makefile.am
@@ -0,0 +1,24 @@
+noinst_LIBRARIES = libfe_irc_dcc.a
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DHELPDIR=\""$(datadir)/irssi/help"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+libfe_irc_dcc_a_SOURCES = \
+ fe-dcc.c \
+ fe-dcc-chat.c \
+ fe-dcc-chat-messages.c \
+ fe-dcc-get.c \
+ fe-dcc-send.c \
+ module-formats.c \
+ fe-dcc-server.c
+
+pkginc_fe_common_irc_dccdir=$(pkgincludedir)/src/fe-common/irc/dcc
+pkginc_fe_common_irc_dcc_HEADERS = \
+ module.h \
+ module-formats.h \
+ fe-dcc.h
+
+EXTRA_DIST = meson.build
diff --git a/src/fe-common/irc/dcc/Makefile.in b/src/fe-common/irc/dcc/Makefile.in
new file mode 100644
index 0000000..f73bf3b
--- /dev/null
+++ b/src/fe-common/irc/dcc/Makefile.in
@@ -0,0 +1,750 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/fe-common/irc/dcc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \
+ $(top_srcdir)/m4/glibtests.m4 $(top_srcdir)/m4/libgcrypt.m4 \
+ $(top_srcdir)/m4/libotr.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am \
+ $(pkginc_fe_common_irc_dcc_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/irssi-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libfe_irc_dcc_a_AR = $(AR) $(ARFLAGS)
+libfe_irc_dcc_a_LIBADD =
+am_libfe_irc_dcc_a_OBJECTS = fe-dcc.$(OBJEXT) fe-dcc-chat.$(OBJEXT) \
+ fe-dcc-chat-messages.$(OBJEXT) fe-dcc-get.$(OBJEXT) \
+ fe-dcc-send.$(OBJEXT) module-formats.$(OBJEXT) \
+ fe-dcc-server.$(OBJEXT)
+libfe_irc_dcc_a_OBJECTS = $(am_libfe_irc_dcc_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES =
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/fe-dcc-chat-messages.Po \
+ ./$(DEPDIR)/fe-dcc-chat.Po ./$(DEPDIR)/fe-dcc-get.Po \
+ ./$(DEPDIR)/fe-dcc-send.Po ./$(DEPDIR)/fe-dcc-server.Po \
+ ./$(DEPDIR)/fe-dcc.Po ./$(DEPDIR)/module-formats.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libfe_irc_dcc_a_SOURCES)
+DIST_SOURCES = $(libfe_irc_dcc_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_fe_common_irc_dccdir)"
+HEADERS = $(pkginc_fe_common_irc_dcc_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHAT_MODULES = @CHAT_MODULES@
+COMMON_LIBS = @COMMON_LIBS@
+COMMON_NOUI_LIBS = @COMMON_NOUI_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FUZZER_LIBS = @FUZZER_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOTR_CFLAGS = @LIBOTR_CFLAGS@
+LIBOTR_LIBS = @LIBOTR_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+OTR_CFLAGS = @OTR_CFLAGS@
+OTR_LDFLAGS = @OTR_LDFLAGS@
+OTR_LINK_FLAGS = @OTR_LINK_FLAGS@
+OTR_LINK_LIBS = @OTR_LINK_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL_CFLAGS = @PERL_CFLAGS@
+PERL_EXTRA_OPTS = @PERL_EXTRA_OPTS@
+PERL_FE_LINK_LIBS = @PERL_FE_LINK_LIBS@
+PERL_LDFLAGS = @PERL_LDFLAGS@
+PERL_LINK_FLAGS = @PERL_LINK_FLAGS@
+PERL_LINK_LIBS = @PERL_LINK_LIBS@
+PERL_MM_OPT = @PERL_MM_OPT@
+PERL_MM_PARAMS = @PERL_MM_PARAMS@
+PERL_STATIC_LIBS = @PERL_STATIC_LIBS@
+PERL_USE_LIB = @PERL_USE_LIB@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROG_LIBS = @PROG_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TEXTUI_LIBS = @TEXTUI_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+installed_test_metadir = @installed_test_metadir@
+installed_testdir = @installed_testdir@
+irc_MODULES = @irc_MODULES@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+otr_module_lib = @otr_module_lib@
+otr_static_lib = @otr_static_lib@
+pdfdir = @pdfdir@
+perl_module_fe_lib = @perl_module_fe_lib@
+perl_module_lib = @perl_module_lib@
+perl_static_fe_lib = @perl_static_fe_lib@
+perl_static_lib = @perl_static_lib@
+perlpath = @perlpath@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sedpath = @sedpath@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LIBRARIES = libfe_irc_dcc.a
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DHELPDIR=\""$(datadir)/irssi/help"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+libfe_irc_dcc_a_SOURCES = \
+ fe-dcc.c \
+ fe-dcc-chat.c \
+ fe-dcc-chat-messages.c \
+ fe-dcc-get.c \
+ fe-dcc-send.c \
+ module-formats.c \
+ fe-dcc-server.c
+
+pkginc_fe_common_irc_dccdir = $(pkgincludedir)/src/fe-common/irc/dcc
+pkginc_fe_common_irc_dcc_HEADERS = \
+ module.h \
+ module-formats.h \
+ fe-dcc.h
+
+EXTRA_DIST = meson.build
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/fe-common/irc/dcc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/fe-common/irc/dcc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libfe_irc_dcc.a: $(libfe_irc_dcc_a_OBJECTS) $(libfe_irc_dcc_a_DEPENDENCIES) $(EXTRA_libfe_irc_dcc_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libfe_irc_dcc.a
+ $(AM_V_AR)$(libfe_irc_dcc_a_AR) libfe_irc_dcc.a $(libfe_irc_dcc_a_OBJECTS) $(libfe_irc_dcc_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libfe_irc_dcc.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-dcc-chat-messages.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-dcc-chat.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-dcc-get.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-dcc-send.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-dcc-server.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-dcc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module-formats.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_fe_common_irc_dccHEADERS: $(pkginc_fe_common_irc_dcc_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_fe_common_irc_dcc_HEADERS)'; test -n "$(pkginc_fe_common_irc_dccdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_fe_common_irc_dccdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_fe_common_irc_dccdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_fe_common_irc_dccdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_fe_common_irc_dccdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_fe_common_irc_dccHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_fe_common_irc_dcc_HEADERS)'; test -n "$(pkginc_fe_common_irc_dccdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_fe_common_irc_dccdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_fe_common_irc_dccdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/fe-dcc-chat-messages.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-chat.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-get.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-send.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-server.Po
+ -rm -f ./$(DEPDIR)/fe-dcc.Po
+ -rm -f ./$(DEPDIR)/module-formats.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_fe_common_irc_dccHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/fe-dcc-chat-messages.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-chat.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-get.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-send.Po
+ -rm -f ./$(DEPDIR)/fe-dcc-server.Po
+ -rm -f ./$(DEPDIR)/fe-dcc.Po
+ -rm -f ./$(DEPDIR)/module-formats.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_fe_common_irc_dccHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_fe_common_irc_dccHEADERS \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-pkginc_fe_common_irc_dccHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/fe-common/irc/dcc/fe-dcc-chat-messages.c b/src/fe-common/irc/dcc/fe-dcc-chat-messages.c
new file mode 100644
index 0000000..8dd67f7
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc-chat-messages.c
@@ -0,0 +1,164 @@
+/*
+ fe-dcc-chat-messages.c : irssi
+
+ Copyright (C) 2002 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 <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-queries.h>
+#include <irssi/src/irc/dcc/dcc-chat.h>
+#include <irssi/src/core/ignore.h>
+
+#include <irssi/src/fe-common/irc/dcc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+
+static void sig_message_dcc_own(CHAT_DCC_REC *dcc, const char *msg)
+{
+ TEXT_DEST_REC dest;
+ QUERY_REC *query;
+ char *tag;
+
+ tag = g_strconcat("=", dcc->id, NULL);
+ query = query_find(NULL, tag);
+
+ format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag,
+ MSGLEVEL_DCCMSGS | MSGLEVEL_NOHILIGHT |
+ MSGLEVEL_NO_ACT, NULL);
+
+ printformat_dest(&dest, query != NULL ? IRCTXT_OWN_DCC_QUERY :
+ IRCTXT_OWN_DCC, dcc->mynick, dcc->id, msg);
+ g_free(tag);
+}
+
+static void sig_message_dcc_own_action(CHAT_DCC_REC *dcc, const char *msg)
+{
+ TEXT_DEST_REC dest;
+ QUERY_REC *query;
+ char *tag;
+
+ tag = g_strconcat("=", dcc->id, NULL);
+ query = query_find(NULL, tag);
+
+ format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag,
+ MSGLEVEL_DCCMSGS | MSGLEVEL_ACTIONS |
+ MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, NULL);
+
+ printformat_dest(&dest, query != NULL ? IRCTXT_OWN_DCC_ACTION_QUERY :
+ IRCTXT_OWN_DCC_ACTION, dcc->mynick, dcc->id, msg);
+ g_free(tag);
+}
+
+static void sig_message_dcc_own_ctcp(CHAT_DCC_REC *dcc, const char *cmd,
+ const char *data)
+{
+ TEXT_DEST_REC dest;
+ char *tag;
+
+ tag = g_strconcat("=", dcc->id, NULL);
+
+ format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag,
+ MSGLEVEL_DCC | MSGLEVEL_CTCPS |
+ MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, NULL);
+
+ printformat_dest(&dest, IRCTXT_OWN_DCC_CTCP, dcc->id, cmd, data);
+ g_free(tag);
+}
+
+static void sig_message_dcc(CHAT_DCC_REC *dcc, const char *msg)
+{
+ TEXT_DEST_REC dest;
+ QUERY_REC *query;
+ char *tag;
+ int level = MSGLEVEL_DCCMSGS;
+
+ tag = g_strconcat("=", dcc->id, NULL);
+ query = query_find(NULL, tag);
+
+ ignore_check_plus(SERVER(dcc->server), tag, dcc->addrstr, NULL, msg,
+ &level, FALSE);
+
+ format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag,
+ level, NULL);
+
+ printformat_dest(&dest, query != NULL ? IRCTXT_DCC_MSG_QUERY :
+ IRCTXT_DCC_MSG, dcc->id, msg);
+ g_free(tag);
+}
+
+static void sig_message_dcc_action(CHAT_DCC_REC *dcc, const char *msg)
+{
+ TEXT_DEST_REC dest;
+ QUERY_REC *query;
+ char *tag;
+ int level = MSGLEVEL_DCCMSGS | MSGLEVEL_ACTIONS;
+
+ tag = g_strconcat("=", dcc->id, NULL);
+ query = query_find(NULL, tag);
+
+ ignore_check_plus(SERVER(dcc->server), tag, dcc->addrstr, NULL, msg,
+ &level, FALSE);
+
+ format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag,
+ level, NULL);
+
+ printformat_dest(&dest, query != NULL ? IRCTXT_ACTION_DCC_QUERY :
+ IRCTXT_ACTION_DCC, dcc->id, msg);
+ g_free(tag);
+}
+
+static void sig_message_dcc_ctcp(CHAT_DCC_REC *dcc, const char *cmd,
+ const char *data)
+{
+ TEXT_DEST_REC dest;
+ char *tag;
+ int level = MSGLEVEL_DCCMSGS | MSGLEVEL_CTCPS;
+
+ tag = g_strconcat("=", dcc->id, NULL);
+
+ ignore_check_plus(SERVER(dcc->server), tag, dcc->addrstr, NULL, cmd,
+ &level, FALSE);
+
+ format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag,
+ level, NULL);
+
+ printformat_dest(&dest, IRCTXT_DCC_CTCP, dcc->id, cmd, data);
+ g_free(tag);
+}
+
+void fe_dcc_chat_messages_init(void)
+{
+ signal_add("message dcc own", (SIGNAL_FUNC) sig_message_dcc_own);
+ signal_add("message dcc own_action", (SIGNAL_FUNC) sig_message_dcc_own_action);
+ signal_add("message dcc own_ctcp", (SIGNAL_FUNC) sig_message_dcc_own_ctcp);
+ signal_add("message dcc", (SIGNAL_FUNC) sig_message_dcc);
+ signal_add("message dcc action", (SIGNAL_FUNC) sig_message_dcc_action);
+ signal_add("message dcc ctcp", (SIGNAL_FUNC) sig_message_dcc_ctcp);
+}
+
+void fe_dcc_chat_messages_deinit(void)
+{
+ signal_remove("message dcc own", (SIGNAL_FUNC) sig_message_dcc_own);
+ signal_remove("message dcc own_action", (SIGNAL_FUNC) sig_message_dcc_own_action);
+ signal_remove("message dcc own_ctcp", (SIGNAL_FUNC) sig_message_dcc_own_ctcp);
+ signal_remove("message dcc", (SIGNAL_FUNC) sig_message_dcc);
+ signal_remove("message dcc action", (SIGNAL_FUNC) sig_message_dcc_action);
+ signal_remove("message dcc ctcp", (SIGNAL_FUNC) sig_message_dcc_ctcp);
+}
diff --git a/src/fe-common/irc/dcc/fe-dcc-chat.c b/src/fe-common/irc/dcc/fe-dcc-chat.c
new file mode 100644
index 0000000..4099e2f
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc-chat.c
@@ -0,0 +1,385 @@
+/*
+ fe-dcc-chat.c : irssi
+
+ Copyright (C) 1999-2002 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 <irssi/src/core/signals.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/settings.h>
+#include <irssi/src/core/misc.h>
+
+#include <irssi/src/irc/core/irc.h>
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-queries.h>
+#include <irssi/src/irc/dcc/dcc-chat.h>
+
+#include <irssi/src/fe-common/irc/dcc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/fe-messages.h>
+
+#include <irssi/src/fe-common/core/chat-completion.h>
+
+void fe_dcc_chat_messages_init(void);
+void fe_dcc_chat_messages_deinit(void);
+
+static void dcc_request(CHAT_DCC_REC *dcc)
+{
+ if (!IS_DCC_CHAT(dcc)) return;
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ server_ischannel(SERVER(dcc->server), dcc->target) ? IRCTXT_DCC_CHAT_CHANNEL :
+ IRCTXT_DCC_CHAT, dcc->id, dcc->addrstr,
+ dcc->port, dcc->target);
+}
+
+static void dcc_connected(CHAT_DCC_REC *dcc)
+{
+ char *sender;
+
+ if (!IS_DCC_CHAT(dcc)) return;
+
+ sender = g_strconcat("=", dcc->id, NULL);
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_CHAT_CONNECTED,
+ dcc->id, dcc->addrstr, dcc->port);
+
+ if (query_find(NULL, sender) == NULL) {
+ int level = settings_get_level("autocreate_query_level");
+ int autocreate_dccquery = (level & MSGLEVEL_DCCMSGS) != 0;
+
+ if (!autocreate_dccquery)
+ completion_last_message_add(sender);
+ else
+ irc_query_create(dcc->servertag, sender, TRUE);
+ }
+ g_free(sender);
+}
+
+static void dcc_closed(CHAT_DCC_REC *dcc)
+{
+ char *sender;
+
+ if (!IS_DCC_CHAT(dcc)) return;
+
+ sender = g_strconcat("=", dcc->id, NULL);
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_CHAT_DISCONNECTED, dcc->id);
+ g_free(sender);
+}
+
+static void dcc_chat_msg(CHAT_DCC_REC *dcc, const char *msg)
+{
+ QUERY_REC *query;
+ char *sender, *freemsg;
+
+ g_return_if_fail(IS_DCC_CHAT(dcc));
+ g_return_if_fail(msg != NULL);
+
+ sender = g_strconcat("=", dcc->id, NULL);
+ query = query_find(NULL, sender);
+
+ if (settings_get_bool("emphasis"))
+ msg = freemsg = expand_emphasis((WI_ITEM_REC *) query, msg);
+ else
+ freemsg = NULL;
+
+ if (query == NULL)
+ completion_last_message_add(sender);
+ signal_emit("message dcc", 2, dcc, msg);
+
+ g_free_not_null(freemsg);
+ g_free(sender);
+}
+
+static void dcc_chat_action(CHAT_DCC_REC *dcc, const char *msg)
+{
+ char *sender;
+
+ g_return_if_fail(IS_DCC_CHAT(dcc));
+ g_return_if_fail(msg != NULL);
+
+ sender = g_strconcat("=", dcc->id, NULL);
+ if (query_find(NULL, sender) == NULL)
+ completion_last_message_add(sender);
+
+ signal_emit("message dcc action", 2, dcc, msg);
+ g_free(sender);
+}
+
+static void dcc_chat_ctcp(CHAT_DCC_REC *dcc, const char *cmd, const char *data)
+{
+ g_return_if_fail(IS_DCC_CHAT(dcc));
+
+ signal_emit("message dcc ctcp", 3, dcc, cmd, data);
+}
+
+static void dcc_error_ctcp(const char *type, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_INVALID_CTCP, type, nick, addr, target);
+}
+
+static void dcc_unknown_ctcp(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target, CHAT_DCC_REC *chat)
+{
+ char *type, *args;
+ void *free_arg;
+
+ g_return_if_fail(data != NULL);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
+ &type, &args))
+ return;
+
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_CTCP,
+ type, nick, args);
+ cmd_params_free(free_arg);
+}
+
+static void dcc_unknown_reply(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ char *type, *args;
+ void *free_arg;
+
+ g_return_if_fail(data != NULL);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
+ &type, &args))
+ return;
+
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_REPLY,
+ type, nick, args);
+ cmd_params_free(free_arg);
+}
+
+static void sig_dcc_destroyed(CHAT_DCC_REC *dcc)
+{
+ QUERY_REC *query;
+ char *nick;
+
+ if (!IS_DCC_CHAT(dcc)) return;
+
+ nick = g_strconcat("=", dcc->id, NULL);
+ query = query_find(NULL, nick);
+ if (query != NULL) {
+ /* DCC chat closed, close the query with it. */
+ if (dcc->connection_lost) query->unwanted = TRUE;
+ query_destroy(query);
+ } else {
+ /* remove nick from msg completion
+ since it won't work anymore */
+ completion_last_message_remove(nick);
+ }
+
+ g_free(nick);
+}
+
+static void sig_query_destroyed(QUERY_REC *query)
+{
+ CHAT_DCC_REC *dcc;
+
+ if (*query->name != '=')
+ return;
+
+ dcc = dcc_chat_find_id(query->name+1);
+ if (dcc != NULL && !dcc->destroyed) {
+ /* DCC query window closed, close the dcc chat too. */
+ dcc_close(DCC(dcc));
+ }
+}
+
+static void dcc_error_close_not_found(const char *type, const char *nick,
+ const char *fname)
+{
+ g_return_if_fail(type != NULL);
+ g_return_if_fail(nick != NULL);
+ if (g_ascii_strcasecmp(type, "CHAT") != 0) return;
+
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_CHAT_NOT_FOUND, nick);
+}
+
+static void sig_dcc_list_print(CHAT_DCC_REC *dcc)
+{
+ if (!IS_DCC_CHAT(dcc)) return;
+
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_LINE_CHAT,
+ dcc->id, "CHAT");
+}
+
+static void cmd_msg(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ CHAT_DCC_REC *dcc;
+ GHashTable *optlist;
+ char *text, *target;
+ void *free_arg;
+
+ g_return_if_fail(data != NULL);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_UNKNOWN_OPTIONS |
+ PARAM_FLAG_OPTIONS | PARAM_FLAG_GETREST, "msg",
+ &optlist, &target, &text))
+ return;
+
+ /* handle only DCC messages */
+ if (g_strcmp0(target, "*") == 0)
+ dcc = item_get_dcc(item);
+ else if (*target == '=')
+ dcc = dcc_chat_find_id(target+1);
+ else
+ dcc = NULL;
+
+ if (dcc == NULL && *target == '=') {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ IRCTXT_DCC_CHAT_NOT_FOUND, target+1);
+ } else if (dcc != NULL) {
+ if (query_find(NULL, target) == NULL)
+ completion_last_message_add(target);
+
+ signal_emit("message dcc own", 2, dcc, text);
+ }
+
+ cmd_params_free(free_arg);
+}
+
+static void cmd_me(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ CHAT_DCC_REC *dcc;
+
+ dcc = item_get_dcc(item);
+ if (dcc != NULL)
+ signal_emit("message dcc own_action", 2, dcc, data);
+}
+
+static void cmd_action(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ CHAT_DCC_REC *dcc;
+ char *target, *text;
+ void *free_arg;
+
+ g_return_if_fail(data != NULL);
+
+ if (*data != '=') {
+ /* handle only DCC actions */
+ return;
+ }
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
+ &target, &text))
+ return;
+ if (*target == '\0' || *text == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ dcc = dcc_chat_find_id(target+1);
+ if (dcc == NULL || dcc->sendbuf == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ IRCTXT_DCC_CHAT_NOT_FOUND, target+1);
+ } else {
+ if (query_find(NULL, target) == NULL)
+ completion_last_message_add(target);
+
+ signal_emit("message dcc own_action", 2, dcc, text);
+ }
+ cmd_params_free(free_arg);
+}
+
+static void cmd_ctcp(const char *data, SERVER_REC *server)
+{
+ CHAT_DCC_REC *dcc;
+ char *target, *ctcpcmd, *ctcpdata;
+ void *free_arg;
+
+ g_return_if_fail(data != NULL);
+ if (server == NULL || !server->connected)
+ cmd_return_error(CMDERR_NOT_CONNECTED);
+
+ if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST,
+ &target, &ctcpcmd, &ctcpdata))
+ return;
+ if (*target == '\0' || *ctcpcmd == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ if (*target != '=') {
+ /* handle only DCC CTCPs */
+ cmd_params_free(free_arg);
+ return;
+ }
+
+ dcc = dcc_chat_find_id(target+1);
+ if (dcc == NULL || dcc->sendbuf == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ IRCTXT_DCC_CHAT_NOT_FOUND, target+1);
+ } else {
+ ascii_strup(ctcpcmd);
+ signal_emit("message dcc own_ctcp", 3, dcc, ctcpcmd, ctcpdata);
+ }
+
+ cmd_params_free(free_arg);
+}
+
+void fe_dcc_chat_init(void)
+{
+ fe_dcc_chat_messages_init();
+
+ signal_add("dcc request", (SIGNAL_FUNC) dcc_request);
+ signal_add("dcc connected", (SIGNAL_FUNC) dcc_connected);
+ signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_add("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg);
+ signal_add("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_action);
+ signal_add("default dcc ctcp", (SIGNAL_FUNC) dcc_chat_ctcp);
+ signal_add("dcc error ctcp", (SIGNAL_FUNC) dcc_error_ctcp);
+ signal_add("default ctcp msg dcc", (SIGNAL_FUNC) dcc_unknown_ctcp);
+ signal_add("default ctcp reply dcc", (SIGNAL_FUNC) dcc_unknown_reply);
+ signal_add("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
+ signal_add("query destroyed", (SIGNAL_FUNC) sig_query_destroyed);
+ signal_add("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+ command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg);
+ command_bind("me", NULL, (SIGNAL_FUNC) cmd_me);
+ command_bind("action", NULL, (SIGNAL_FUNC) cmd_action);
+ command_bind("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp);
+ signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
+}
+
+void fe_dcc_chat_deinit(void)
+{
+ fe_dcc_chat_messages_deinit();
+
+ signal_remove("dcc request", (SIGNAL_FUNC) dcc_request);
+ signal_remove("dcc connected", (SIGNAL_FUNC) dcc_connected);
+ signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_remove("dcc chat message", (SIGNAL_FUNC) dcc_chat_msg);
+ signal_remove("dcc ctcp action", (SIGNAL_FUNC) dcc_chat_action);
+ signal_remove("default dcc ctcp", (SIGNAL_FUNC) dcc_chat_ctcp);
+ signal_remove("dcc error ctcp", (SIGNAL_FUNC) dcc_error_ctcp);
+ signal_remove("default ctcp msg dcc", (SIGNAL_FUNC) dcc_unknown_ctcp);
+ signal_remove("default ctcp reply dcc", (SIGNAL_FUNC) dcc_unknown_reply);
+ signal_remove("dcc destroyed", (SIGNAL_FUNC) sig_dcc_destroyed);
+ signal_remove("query destroyed", (SIGNAL_FUNC) sig_query_destroyed);
+ signal_remove("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+ command_unbind("msg", (SIGNAL_FUNC) cmd_msg);
+ command_unbind("me", (SIGNAL_FUNC) cmd_me);
+ command_unbind("action", (SIGNAL_FUNC) cmd_action);
+ command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp);
+ signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
+}
diff --git a/src/fe-common/irc/dcc/fe-dcc-get.c b/src/fe-common/irc/dcc/fe-dcc-get.c
new file mode 100644
index 0000000..e75640b
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc-get.c
@@ -0,0 +1,150 @@
+/*
+ fe-dcc-get.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 <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/servers.h>
+
+#include <irssi/src/irc/core/irc.h>
+#include <irssi/src/irc/dcc/dcc-file.h>
+#include <irssi/src/irc/dcc/dcc-get.h>
+
+#include <irssi/src/fe-common/irc/dcc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+
+#include <irssi/src/fe-common/irc/dcc/fe-dcc.h>
+
+static void dcc_request(GET_DCC_REC *dcc)
+{
+ char *sizestr;
+
+ if (!IS_DCC_GET(dcc)) return;
+
+ sizestr = dcc_get_size_str(dcc->size);
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ server_ischannel(SERVER(dcc->server), dcc->target) ? IRCTXT_DCC_SEND_CHANNEL :
+ IRCTXT_DCC_SEND, dcc->nick, dcc->addrstr,
+ dcc->port, dcc->arg, sizestr, dcc->target);
+
+ g_free(sizestr);
+}
+
+static void dcc_connected(GET_DCC_REC *dcc)
+{
+ if (!IS_DCC_GET(dcc)) return;
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_CONNECTED,
+ dcc->arg, dcc->nick, dcc->addrstr, dcc->port);
+}
+
+static void dcc_closed(GET_DCC_REC *dcc)
+{
+ char *sizestr, timestr[20];
+ double kbs;
+ time_t secs;
+
+ if (!IS_DCC_GET(dcc)) return;
+
+ secs = dcc->starttime == 0 ? -1 : time(NULL)-dcc->starttime;
+ kbs = (double) (dcc->transfd-dcc->skipped) /
+ (secs == 0 ? 1 : secs) / 1024.0;
+
+ sizestr = dcc_get_size_str(dcc->transfd);
+ g_snprintf(timestr, sizeof(timestr), "%02d:%02d:%02d",
+ (int)(secs/3600), (int)((secs/60)%60), (int)(secs%60));
+
+ if (secs == -1) {
+ /* aborted */
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_GET_ABORTED, dcc->arg, dcc->nick);
+ } else {
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_GET_COMPLETE, dcc->arg, sizestr,
+ dcc->nick, timestr, kbs);
+ }
+
+ g_free(sizestr);
+}
+
+static void dcc_error_file_create(GET_DCC_REC *dcc, const char *fname,
+ const char *error)
+{
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CANT_CREATE,
+ fname, error);
+}
+
+
+static void dcc_error_get_not_found(const char *nick)
+{
+ g_return_if_fail(nick != NULL);
+
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_GET_NOT_FOUND, nick);
+}
+
+static void dcc_error_close_not_found(const char *type, const char *nick,
+ const char *fname)
+{
+ g_return_if_fail(type != NULL);
+ g_return_if_fail(nick != NULL);
+ g_return_if_fail(fname != NULL);
+ if (g_ascii_strcasecmp(type, "GET") != 0) return;
+
+ if (fname == NULL || *fname == '\0') fname = "(ANY)";
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_GET_NOT_FOUND, nick, fname);
+}
+
+static void dcc_error_write(GET_DCC_REC *dcc, const char *error)
+{
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_GET_WRITE_ERROR, dcc->file, error);
+}
+
+static void sig_dcc_list_print(GET_DCC_REC *dcc)
+{
+ if (IS_DCC_GET(dcc))
+ dcc_list_print_file((FILE_DCC_REC *) dcc);
+}
+
+void fe_dcc_get_init(void)
+{
+ signal_add("dcc request", (SIGNAL_FUNC) dcc_request);
+ signal_add("dcc connected", (SIGNAL_FUNC) dcc_connected);
+ signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_add("dcc error file create", (SIGNAL_FUNC) dcc_error_file_create);
+ signal_add("dcc error get not found", (SIGNAL_FUNC) dcc_error_get_not_found);
+ signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
+ signal_add("dcc error write", (SIGNAL_FUNC) dcc_error_write);
+ signal_add("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+}
+
+void fe_dcc_get_deinit(void)
+{
+ signal_remove("dcc request", (SIGNAL_FUNC) dcc_request);
+ signal_remove("dcc connected", (SIGNAL_FUNC) dcc_connected);
+ signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_remove("dcc error file create", (SIGNAL_FUNC) dcc_error_file_create);
+ signal_remove("dcc error get not found", (SIGNAL_FUNC) dcc_error_get_not_found);
+ signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
+ signal_remove("dcc error write", (SIGNAL_FUNC) dcc_error_write);
+ signal_remove("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+}
diff --git a/src/fe-common/irc/dcc/fe-dcc-send.c b/src/fe-common/irc/dcc/fe-dcc-send.c
new file mode 100644
index 0000000..cf9b634
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc-send.c
@@ -0,0 +1,186 @@
+/*
+ fe-dcc-send.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 <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/dcc/dcc-file.h>
+#include <irssi/src/irc/dcc/dcc-send.h>
+#include <irssi/src/irc/dcc/dcc-queue.h>
+
+#include <irssi/src/fe-common/irc/dcc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/completion.h>
+
+#include <irssi/src/fe-common/irc/dcc/fe-dcc.h>
+
+static void dcc_connected(SEND_DCC_REC *dcc)
+{
+ if (!IS_DCC_SEND(dcc)) return;
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_CONNECTED,
+ dcc->arg, dcc->nick, dcc->addrstr, dcc->port);
+}
+
+static void dcc_closed(SEND_DCC_REC *dcc)
+{
+ char *sizestr, timestr[20];
+ double kbs;
+ time_t secs;
+
+ if (!IS_DCC_SEND(dcc)) return;
+
+ secs = dcc->starttime == 0 ? -1 : time(NULL)-dcc->starttime;
+ kbs = (double) (dcc->transfd-dcc->skipped) /
+ (secs == 0 ? 1 : secs) / 1024.0;
+
+ if (secs == -1) {
+ /* aborted */
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_ABORTED,
+ dcc->arg, dcc->nick);
+ } else {
+ sizestr = dcc_get_size_str(dcc->transfd);
+ g_snprintf(timestr, sizeof(timestr), "%02d:%02d:%02d",
+ (int)(secs/3600), (int)((secs/60)%60),
+ (int)(secs%60));
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_COMPLETE,
+ dcc->arg, sizestr, dcc->nick, timestr, kbs);
+
+ g_free(sizestr);
+ }
+}
+
+static void dcc_error_file_open(const char *nick, const char *fname,
+ void *error)
+{
+ g_return_if_fail(nick != NULL);
+ g_return_if_fail(fname != NULL);
+
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_FILE_OPEN_ERROR, fname,
+ g_strerror(GPOINTER_TO_INT(error)));
+}
+
+static void dcc_error_send_exists(const char *nick, const char *fname)
+{
+ g_return_if_fail(nick != NULL);
+ g_return_if_fail(fname != NULL);
+
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_EXISTS, fname, nick);
+}
+
+static void dcc_error_send_no_route(const char *nick, const char *fname)
+{
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_NO_ROUTE, nick, fname);
+}
+
+static void dcc_error_close_not_found(const char *type, const char *nick,
+ const char *fname)
+{
+ g_return_if_fail(type != NULL);
+ g_return_if_fail(nick != NULL);
+ g_return_if_fail(fname != NULL);
+ if (g_ascii_strcasecmp(type, "SEND") != 0) return;
+
+ if (fname == NULL || *fname == '\0') fname = "(ANY)";
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SEND_NOT_FOUND, nick, fname);
+}
+
+static void sig_dcc_send_complete(GList **list, WINDOW_REC *window,
+ const char *word, const char *line,
+ int *want_space)
+{
+ char *path;
+
+ g_return_if_fail(list != NULL);
+ g_return_if_fail(word != NULL);
+ g_return_if_fail(line != NULL);
+
+ if (*line == '\0' || strchr(line, ' ') != NULL)
+ return;
+
+ /* completing filename parameter for /DCC SEND */
+ path = convert_home(settings_get_str("dcc_upload_path"));
+ if (*path == '\0') {
+ /* use the default path */
+ g_free_and_null(path);
+ }
+
+ *list = filename_complete(word, path);
+
+ if (*list != NULL) {
+ *want_space = FALSE;
+ signal_stop();
+ }
+}
+
+static void sig_dcc_list_print(SEND_DCC_REC *dcc)
+{
+ GSList *queue;
+
+ if (!IS_DCC_SEND(dcc))
+ return;
+
+ dcc_list_print_file((FILE_DCC_REC *) dcc);
+
+ queue = dcc_queue_get_queue(dcc->queue);
+ for (; queue != NULL; queue = queue->next) {
+ DCC_QUEUE_REC *rec = queue->data;
+
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_LIST_LINE_QUEUED_SEND, rec->nick,
+ rec->servertag == NULL ? "" : rec->servertag,
+ rec->file);
+ }
+}
+
+void fe_dcc_send_init(void)
+{
+ signal_add("dcc connected", (SIGNAL_FUNC) dcc_connected);
+ signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_add("dcc error file open", (SIGNAL_FUNC) dcc_error_file_open);
+ signal_add("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists);
+ signal_add("dcc error send no route", (SIGNAL_FUNC) dcc_error_send_no_route);
+ signal_add("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
+ signal_add("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete);
+ signal_add("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+}
+
+void fe_dcc_send_deinit(void)
+{
+ signal_remove("dcc connected", (SIGNAL_FUNC) dcc_connected);
+ signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_remove("dcc error file open", (SIGNAL_FUNC) dcc_error_file_open);
+ signal_remove("dcc error send exists", (SIGNAL_FUNC) dcc_error_send_exists);
+ signal_remove("dcc error send no route", (SIGNAL_FUNC) dcc_error_send_no_route);
+ signal_remove("dcc error close not found", (SIGNAL_FUNC) dcc_error_close_not_found);
+ signal_remove("complete command dcc send", (SIGNAL_FUNC) sig_dcc_send_complete);
+ signal_remove("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+}
diff --git a/src/fe-common/irc/dcc/fe-dcc-server.c b/src/fe-common/irc/dcc/fe-dcc-server.c
new file mode 100644
index 0000000..eaab963
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc-server.c
@@ -0,0 +1,83 @@
+/*
+ fe-dcc-server.c : irssi
+
+ Copyright (C) 2003 Mark Trumbull
+
+ 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 <irssi/src/core/signals.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/network.h>
+#include <irssi/src/core/levels.h>
+
+#include <irssi/src/irc/dcc/dcc-server.h>
+
+#include <irssi/src/fe-common/irc/dcc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/themes.h>
+
+static void dcc_server_started(SERVER_DCC_REC *dcc)
+{
+ if (!IS_DCC_SERVER(dcc)) {
+ return;
+ }
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SERVER_STARTED, dcc->port);
+}
+
+static void dcc_closed(SERVER_DCC_REC *dcc)
+{
+ /* We don't want to print a msg if its just starting a chat/get */
+ /* and getting rid of the leftover SERVER_DCC_REC */
+ if (!IS_DCC_SERVER(dcc) || dcc->connection_established) {
+ return;
+ }
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_SERVER_CLOSED, dcc->port);
+}
+
+static void sig_dcc_list_print(SERVER_DCC_REC *dcc)
+{
+ /* We don't want to print a msg if its just starting a chat/get */
+ /* and getting rid of the leftover SERVER_DCC_REC */
+ if (!IS_DCC_SERVER(dcc) || dcc->connection_established) {
+ return;
+ }
+
+ /* SERVER: Port(59) - Send(on) - Chat(on) - Fserve(on) */
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_LINE_SERVER,
+ "SERVER", dcc->port, dcc->accept_send ? "on" : "off",
+ dcc->accept_chat ? "on" : "off",
+ dcc->accept_fserve ? "on" : "off");
+}
+
+void fe_dcc_server_init(void)
+{
+ signal_add("dcc server started", (SIGNAL_FUNC) dcc_server_started);
+ signal_add("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_add("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+}
+
+void fe_dcc_server_deinit(void)
+{
+ signal_remove("dcc server started", (SIGNAL_FUNC) dcc_server_started);
+ signal_remove("dcc closed", (SIGNAL_FUNC) dcc_closed);
+ signal_remove("dcc list print", (SIGNAL_FUNC) sig_dcc_list_print);
+}
+
diff --git a/src/fe-common/irc/dcc/fe-dcc.c b/src/fe-common/irc/dcc/fe-dcc.c
new file mode 100644
index 0000000..f5fb3b2
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc.c
@@ -0,0 +1,195 @@
+/*
+ fe-dcc.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 <irssi/src/core/signals.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/network.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/dcc/dcc-chat.h>
+#include <irssi/src/irc/dcc/dcc-file.h>
+#include <irssi/src/irc/dcc/dcc-get.h>
+#include <irssi/src/irc/dcc/dcc-send.h>
+
+#include <irssi/src/fe-common/irc/dcc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/themes.h>
+
+void fe_dcc_chat_init(void);
+void fe_dcc_chat_deinit(void);
+
+void fe_dcc_get_init(void);
+void fe_dcc_get_deinit(void);
+
+void fe_dcc_send_init(void);
+void fe_dcc_send_deinit(void);
+
+void fe_dcc_server_init(void);
+void fe_dcc_server_deinit(void);
+
+char *dcc_get_size_str(uoff_t size)
+{
+ if (size < 1024)
+ return g_strdup_printf("%"PRIuUOFF_T"B", size);
+ if (size < 1024*1024)
+ return g_strdup_printf("%"PRIuUOFF_T"kB", (size+1023) / 1024);
+ return g_strdup_printf("%"PRIuUOFF_T"MB", size / (1024*1024));
+}
+
+static void dcc_request(DCC_REC *dcc)
+{
+ char *service;
+
+ g_return_if_fail(dcc != NULL);
+
+ if (dcc->port < 1024) {
+ /* warn about connecting to lowports */
+ service = net_getservbyport(dcc->port);
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_LOWPORT, dcc->port,
+ service != NULL ? service : "unknown");
+ }
+}
+
+static void dcc_rejected(DCC_REC *dcc)
+{
+ g_return_if_fail(dcc != NULL);
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC, IRCTXT_DCC_CLOSE,
+ dcc_type2str(dcc->type), dcc->nick, dcc->arg);
+}
+
+static void dcc_request_send(DCC_REC *dcc)
+{
+ g_return_if_fail(dcc != NULL);
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC, IRCTXT_DCC_REQUEST_SEND,
+ dcc_type2str(dcc->type), dcc->nick, dcc->arg);
+}
+
+static void dcc_error_connect(DCC_REC *dcc)
+{
+ g_return_if_fail(dcc != NULL);
+
+ printformat(dcc->server, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_CONNECT_ERROR, dcc->addrstr, dcc->port);
+}
+
+static void dcc_error_unknown_type(const char *type)
+{
+ g_return_if_fail(type != NULL);
+
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_UNKNOWN_TYPE, type);
+}
+
+void dcc_list_print_file(FILE_DCC_REC *dcc)
+{
+ time_t going, eta;
+ char *transfd_str, *size_str, etastr[20];
+ uoff_t bps;
+
+ going = time(NULL) - dcc->starttime;
+ if (going <= 0) going = 1;
+
+ transfd_str = dcc_get_size_str(dcc->transfd);
+ size_str = dcc_get_size_str(dcc->size);
+
+ bps = (dcc->transfd-dcc->skipped) / going;
+ if (bps == 0) {
+ strcpy(etastr, "(stalled)");
+ } else {
+ eta = (dcc->size - dcc->transfd) / bps;
+ g_snprintf(etastr, sizeof(etastr), "%02d:%02d:%02d",
+ (int)(eta/3600), (int)((eta/60)%60), (int)(eta%60));
+ }
+
+ printformat(NULL, NULL, MSGLEVEL_DCC,
+ IRCTXT_DCC_LIST_LINE_FILE,
+ dcc->nick, dcc_type2str(dcc->type),
+ transfd_str, size_str,
+ dcc->size == 0 ? 0 : (int)((double)dcc->transfd/(double)dcc->size*100.0),
+ (double)bps/1024.0, dcc->arg, etastr);
+
+ g_free(transfd_str);
+ g_free(size_str);
+}
+
+static void cmd_dcc_list(const char *data)
+{
+ GSList *tmp;
+
+ g_return_if_fail(data != NULL);
+
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_HEADER);
+ for (tmp = dcc_conns; tmp != NULL; tmp = tmp->next)
+ signal_emit("dcc list print", 1, tmp->data);
+ printformat(NULL, NULL, MSGLEVEL_DCC, IRCTXT_DCC_LIST_FOOTER);
+}
+
+static void cmd_dcc(const char *data)
+{
+ if (*data == '\0') {
+ cmd_dcc_list(data);
+ signal_stop();
+ }
+}
+
+void fe_irc_dcc_init(void)
+{
+ fe_dcc_chat_init();
+ fe_dcc_get_init();
+ fe_dcc_send_init();
+ fe_dcc_server_init();
+
+ signal_add("dcc request", (SIGNAL_FUNC) dcc_request);
+ signal_add("dcc rejected", (SIGNAL_FUNC) dcc_rejected);
+ signal_add("dcc request send", (SIGNAL_FUNC) dcc_request_send);
+ signal_add("dcc error connect", (SIGNAL_FUNC) dcc_error_connect);
+ signal_add("dcc error unknown type", (SIGNAL_FUNC) dcc_error_unknown_type);
+ command_bind("dcc", NULL, (SIGNAL_FUNC) cmd_dcc);
+ command_bind("dcc list", NULL, (SIGNAL_FUNC) cmd_dcc_list);
+
+ theme_register(fecommon_irc_dcc_formats);
+ settings_check();
+ module_register("dcc", "fe-irc");
+}
+
+void fe_irc_dcc_deinit(void)
+{
+ fe_dcc_chat_deinit();
+ fe_dcc_get_deinit();
+ fe_dcc_send_deinit();
+ fe_dcc_server_deinit();
+
+ theme_unregister();
+
+ signal_remove("dcc request", (SIGNAL_FUNC) dcc_request);
+ signal_remove("dcc rejected", (SIGNAL_FUNC) dcc_rejected);
+ signal_remove("dcc request send", (SIGNAL_FUNC) dcc_request_send);
+ signal_remove("dcc error connect", (SIGNAL_FUNC) dcc_error_connect);
+ signal_remove("dcc error unknown type", (SIGNAL_FUNC) dcc_error_unknown_type);
+ command_unbind("dcc", (SIGNAL_FUNC) cmd_dcc);
+ command_unbind("dcc list", (SIGNAL_FUNC) cmd_dcc_list);
+}
+
+MODULE_ABICHECK(fe_irc_dcc)
diff --git a/src/fe-common/irc/dcc/fe-dcc.h b/src/fe-common/irc/dcc/fe-dcc.h
new file mode 100644
index 0000000..4d79296
--- /dev/null
+++ b/src/fe-common/irc/dcc/fe-dcc.h
@@ -0,0 +1,7 @@
+#ifndef IRSSI_FE_COMMON_IRC_DCC_FE_DCC_H
+#define IRSSI_FE_COMMON_IRC_DCC_FE_DCC_H
+
+char *dcc_get_size_str(uoff_t size);
+void dcc_list_print_file(FILE_DCC_REC *dcc);
+
+#endif
diff --git a/src/fe-common/irc/dcc/meson.build b/src/fe-common/irc/dcc/meson.build
new file mode 100644
index 0000000..296b1d6
--- /dev/null
+++ b/src/fe-common/irc/dcc/meson.build
@@ -0,0 +1,27 @@
+# this file is part of irssi
+
+libfe_irc_dcc_a = static_library('fe_irc_dcc',
+ files(
+ 'fe-dcc-chat-messages.c',
+ 'fe-dcc-chat.c',
+ 'fe-dcc-get.c',
+ 'fe-dcc-send.c',
+ 'fe-dcc-server.c',
+ 'fe-dcc.c',
+ 'module-formats.c',
+ ),
+ include_directories : rootinc,
+ implicit_include_directories : false,
+ c_args : [
+ def_helpdir,
+ def_sysconfdir,
+ ],
+ dependencies : dep)
+
+install_headers(
+ files(
+ 'fe-dcc.h',
+ 'module-formats.h',
+ 'module.h',
+ ),
+ subdir : incdir / 'src' / 'fe-common' / 'irc' / 'dcc')
diff --git a/src/fe-common/irc/dcc/module-formats.c b/src/fe-common/irc/dcc/module-formats.c
new file mode 100644
index 0000000..f973cd9
--- /dev/null
+++ b/src/fe-common/irc/dcc/module-formats.c
@@ -0,0 +1,79 @@
+/*
+ module-formats.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/core/formats.h>
+
+FORMAT_REC fecommon_irc_dcc_formats[] = {
+ { MODULE_NAME, "IRC", 0 },
+
+ /* ---- */
+ { NULL, "DCC", 0 },
+
+ { "own_dcc", "{dccownmsg dcc {dccownnick $1}}$2", 3, { 0, 0, 0 } },
+ { "own_dcc_action", "{dccownaction_target $0 $1}$2", 3, { 0, 0, 0 } },
+ { "own_dcc_action_query", "{dccownaction $0}$2", 3, { 0, 0, 0 } },
+ { "own_dcc_ctcp", "{ownctcp ctcp $0}$1 $2", 3, { 0, 0, 0 } },
+ { "dcc_msg", "{dccmsg dcc $0}$1", 2, { 0, 0 } },
+ { "action_dcc", "{dccaction $0}$1", 2, { 0, 0 } },
+ { "action_dcc_query", "{dccaction $0}$1", 2, { 0, 0 } },
+ { "own_dcc_query", "{ownmsgnick {dccownquerynick $0}}$2", 3, { 0, 0, 0 } },
+ { "dcc_msg_query", "{privmsgnick $0}$1", 2, { 0, 0 } },
+ { "dcc_ctcp", "{dcc >>> DCC CTCP {hilight $1} received from {hilight $0}: $2}", 3, { 0, 0, 0 } },
+ { "dcc_chat", "{dcc DCC CHAT from {nick $0} [$1 port $2]}", 3, { 0, 0, 1 } },
+ { "dcc_chat_channel", "{dcc DCC CHAT from {nick $0} [$1 port $2] requested in channel {channel $3}}", 4, { 0, 0, 1, 0 } },
+ { "dcc_chat_not_found", "{dcc No DCC CHAT connection open to {nick $0}}", 1, { 0 } },
+ { "dcc_chat_connected", "{dcc DCC CHAT connection with {nick $0} [$1 port $2] established}", 3, { 0, 0, 1 } },
+ { "dcc_chat_disconnected", "{dcc DCC lost chat to {nick $0}}", 1, { 0 } },
+ { "dcc_send", "{dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4]}", 5, { 0, 0, 1, 0, 0 } },
+ { "dcc_send_channel", "{dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes] requested in channel {channel $5}}", 6, { 0, 0, 1, 0, 0, 0 } },
+ { "dcc_send_exists", "{dcc DCC already sending file {dccfile $0} for {nick $1}}", 2, { 0, 0 } },
+ { "dcc_send_no_route", "{dcc DCC route lost to nick {nick $0} when trying to send file {dccfile $1}}", 2, { 0, 0 } },
+ { "dcc_send_not_found", "{dcc DCC not sending file {dccfile $1} to {nick $0}}", 2, { 0, 0 } },
+ { "dcc_send_file_open_error", "{dcc DCC can't open file {dccfile $0}: $1}", 2, { 0, 0 } },
+ { "dcc_send_connected", "{dcc DCC sending file {dccfile $0} for {nick $1} [$2 port $3]}", 4, { 0, 0, 0, 1 } },
+ { "dcc_send_complete", "{dcc DCC sent file {dccfile $0} [{hilight $1}] for {nick $2} in {hilight $3} [{hilight $4kB/s}]}", 5, { 0, 0, 0, 0, 3 } },
+ { "dcc_send_aborted", "{dcc DCC aborted sending file {dccfile $0} for {nick $1}}", 2, { 0, 0 } },
+ { "dcc_get_not_found", "{dcc DCC no file offered by {nick $0}}", 1, { 0 } },
+ { "dcc_get_connected", "{dcc DCC receiving file {dccfile $0} from {nick $1} [$2 port $3]}", 4, { 0, 0, 0, 1 } },
+ { "dcc_get_complete", "{dcc DCC received file {dccfile $0} [$1] from {nick $2} in {hilight $3} [$4kB/s]}", 5, { 0, 0, 0, 0, 3 } },
+ { "dcc_get_aborted", "{dcc DCC aborted receiving file {dccfile $0} from {nick $1}}", 2, { 0, 0 } },
+ { "dcc_get_write_error", "{dcc DCC error writing to file {dccfile $0}: {comment $1}", 2, { 0, 0 } },
+ { "dcc_unknown_ctcp", "{dcc DCC unknown ctcp {hilight $0} from {nick $1} [$2]}", 3, { 0, 0, 0 } },
+ { "dcc_unknown_reply", "{dcc DCC unknown reply {hilight $0} from {nick $1} [$2]}", 3, { 0, 0, 0 } },
+ { "dcc_unknown_type", "{dcc DCC unknown type {hilight $0}}", 1, { 0 } },
+ { "dcc_invalid_ctcp", "{dcc DCC received CTCP {hilight $0} with invalid parameters from {nick $1}}", 4, { 0, 0, 0, 0 } },
+ { "dcc_connect_error", "{dcc DCC can't connect to {hilight $0} port {hilight $1}}", 2, { 0, 1 } },
+ { "dcc_cant_create", "{dcc DCC can't create file {dccfile $0}: $1}", 2, { 0, 0 } },
+ { "dcc_rejected", "{dcc DCC $0 was rejected by {nick $1} [{hilight $2}]}", 3, { 0, 0, 0 } },
+ { "dcc_request_send", "{dcc DCC $0 request sent to {nick $1}: $2", 3, { 0, 0, 0 } },
+ { "dcc_close", "{dcc DCC $0 close for {nick $1} [{hilight $2}]}", 3, { 0, 0, 0 } },
+ { "dcc_lowport", "{dcc Warning: Port sent with DCC request is a lowport ({hilight $0, $1}) - this isn't normal. It is possible the address/port is faked (or maybe someone is just trying to bypass firewall)}", 2, { 1, 0 } },
+ { "dcc_list_header", "{dcc DCC connections}", 0 },
+ { "dcc_list_line_chat", "{dcc $0 $1}", 2, { 0, 0 } },
+ { "dcc_list_line_file", "{dcc $0 $1: %|$2 of $3 ($4%%) - $5kB/s - ETA $7 - $6}", 8, { 0, 0, 0, 0, 1, 3, 0, 0 } },
+ { "dcc_list_line_queued_send", "{dcc - $0 $2 (queued)}", 3, { 0, 0, 0 } },
+ { "dcc_list_footer", "", 0 },
+ { "dcc_list_line_server", "{dcc $0: Port($1) - Send($2) - Chat($3) - Fserve($4)}", 5, { 0, 1, 0, 0, 0 } },
+ { "dcc_server_started", "{dcc DCC SERVER started on port {hilight $0}}", 1, { 1 } },
+ { "dcc_server_closed", "{dcc DCC SERVER on port {hilight $0} closed}", 1, { 1 } },
+
+ { NULL, NULL, 0 }
+};
diff --git a/src/fe-common/irc/dcc/module-formats.h b/src/fe-common/irc/dcc/module-formats.h
new file mode 100644
index 0000000..204c7dd
--- /dev/null
+++ b/src/fe-common/irc/dcc/module-formats.h
@@ -0,0 +1,57 @@
+#include <irssi/src/fe-common/core/formats.h>
+
+enum {
+ IRCTXT_MODULE_NAME,
+
+ IRCTXT_FILL_1,
+
+ IRCTXT_OWN_DCC,
+ IRCTXT_OWN_DCC_ACTION,
+ IRCTXT_OWN_DCC_ACTION_QUERY,
+ IRCTXT_OWN_DCC_CTCP,
+ IRCTXT_DCC_MSG,
+ IRCTXT_ACTION_DCC,
+ IRCTXT_ACTION_DCC_QUERY,
+ IRCTXT_OWN_DCC_QUERY,
+ IRCTXT_DCC_MSG_QUERY,
+ IRCTXT_DCC_CTCP,
+ IRCTXT_DCC_CHAT,
+ IRCTXT_DCC_CHAT_CHANNEL,
+ IRCTXT_DCC_CHAT_NOT_FOUND,
+ IRCTXT_DCC_CHAT_CONNECTED,
+ IRCTXT_DCC_CHAT_DISCONNECTED,
+ IRCTXT_DCC_SEND,
+ IRCTXT_DCC_SEND_CHANNEL,
+ IRCTXT_DCC_SEND_EXISTS,
+ IRCTXT_DCC_SEND_NO_ROUTE,
+ IRCTXT_DCC_SEND_NOT_FOUND,
+ IRCTXT_DCC_SEND_FILE_OPEN_ERROR,
+ IRCTXT_DCC_SEND_CONNECTED,
+ IRCTXT_DCC_SEND_COMPLETE,
+ IRCTXT_DCC_SEND_ABORTED,
+ IRCTXT_DCC_GET_NOT_FOUND,
+ IRCTXT_DCC_GET_CONNECTED,
+ IRCTXT_DCC_GET_COMPLETE,
+ IRCTXT_DCC_GET_ABORTED,
+ IRCTXT_DCC_GET_WRITE_ERROR,
+ IRCTXT_DCC_UNKNOWN_CTCP,
+ IRCTXT_DCC_UNKNOWN_REPLY,
+ IRCTXT_DCC_UNKNOWN_TYPE,
+ IRCTXT_DCC_INVALID_CTCP,
+ IRCTXT_DCC_CONNECT_ERROR,
+ IRCTXT_DCC_CANT_CREATE,
+ IRCTXT_DCC_REJECTED,
+ IRCTXT_DCC_REQUEST_SEND,
+ IRCTXT_DCC_CLOSE,
+ IRCTXT_DCC_LOWPORT,
+ IRCTXT_DCC_LIST_HEADER,
+ IRCTXT_DCC_LIST_LINE_CHAT,
+ IRCTXT_DCC_LIST_LINE_FILE,
+ IRCTXT_DCC_LIST_LINE_QUEUED_SEND,
+ IRCTXT_DCC_LIST_FOOTER,
+ IRCTXT_DCC_LIST_LINE_SERVER,
+ IRCTXT_DCC_SERVER_STARTED,
+ IRCTXT_DCC_SERVER_CLOSED
+};
+
+extern FORMAT_REC fecommon_irc_dcc_formats[];
diff --git a/src/fe-common/irc/dcc/module.h b/src/fe-common/irc/dcc/module.h
new file mode 100644
index 0000000..5493446
--- /dev/null
+++ b/src/fe-common/irc/dcc/module.h
@@ -0,0 +1,4 @@
+#include <irssi/src/common.h>
+#include <irssi/src/irc/core/irc.h>
+
+#define MODULE_NAME "fe-common/irc/dcc"
diff --git a/src/fe-common/irc/fe-cap.c b/src/fe-common/irc/fe-cap.c
new file mode 100644
index 0000000..a75f2bb
--- /dev/null
+++ b/src/fe-common/irc/fe-cap.c
@@ -0,0 +1,84 @@
+/*
+ fe-cap.c : irssi
+
+ Copyright (C) 2018 dequis
+
+ 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 <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+
+static const struct {
+ const char *command;
+ const int template;
+} fe_cap_messages[] = {
+ {"LS", IRCTXT_CAP_LS},
+ {"ACK", IRCTXT_CAP_ACK},
+ {"NAK", IRCTXT_CAP_NAK},
+ {"LIST", IRCTXT_CAP_LIST},
+ {"NEW", IRCTXT_CAP_NEW},
+ {"DEL", IRCTXT_CAP_DEL},
+};
+
+static void event_cap(IRC_SERVER_REC *server, char *args, char *nick, char *address)
+{
+ int i;
+ char *params, *evt, *list, *star;
+
+ params = event_get_params(args, 4, NULL, &evt, &star, &list);
+
+ if (params == NULL) {
+ return;
+ }
+
+ /* With multiline CAP LS, if the '*' parameter isn't present,
+ * adjust the parameter pointer to compensate for this */
+ if (strcmp(star, "*") != 0 && list[0] == '\0') {
+ list = star;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS(fe_cap_messages); i++) {
+ if (!g_ascii_strcasecmp(evt, fe_cap_messages[i].command)) {
+ printformat(server, NULL, MSGLEVEL_CRAP, fe_cap_messages[i].template, list);
+ }
+ }
+
+ g_free(params);
+}
+
+static void sig_server_cap_req(IRC_SERVER_REC *server, char *caps)
+{
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_CAP_REQ, caps);
+}
+
+void fe_cap_init(void)
+{
+ signal_add("event cap", (SIGNAL_FUNC) event_cap);
+ signal_add("server cap req", (SIGNAL_FUNC) sig_server_cap_req);
+}
+
+void fe_cap_deinit(void)
+{
+ signal_remove("event cap", (SIGNAL_FUNC) event_cap);
+ signal_remove("server cap req", (SIGNAL_FUNC) sig_server_cap_req);
+}
diff --git a/src/fe-common/irc/fe-common-irc.c b/src/fe-common/irc/fe-common-irc.c
new file mode 100644
index 0000000..a36d3ca
--- /dev/null
+++ b/src/fe-common/irc/fe-common-irc.c
@@ -0,0 +1,134 @@
+/*
+ fe-common-irc.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/core/modules.h>
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/lib-config/iconfig.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/fe-common/core/themes.h>
+#include <irssi/src/fe-common/irc/fe-irc-server.h>
+#include <irssi/src/fe-common/irc/fe-irc-channels.h>
+
+void fe_irc_modules_init(void);
+void fe_irc_modules_deinit(void);
+
+void fe_irc_queries_init(void);
+void fe_irc_queries_deinit(void);
+
+void fe_irc_layout_init(void);
+void fe_irc_layout_deinit(void);
+
+void fe_irc_messages_init(void);
+void fe_irc_messages_deinit(void);
+
+void fe_irc_commands_init(void);
+void fe_irc_commands_deinit(void);
+
+void fe_ircnet_init(void);
+void fe_ircnet_deinit(void);
+
+void fe_ctcp_init(void);
+void fe_ctcp_deinit(void);
+
+void fe_events_init(void);
+void fe_events_deinit(void);
+
+void fe_events_numeric_init(void);
+void fe_events_numeric_deinit(void);
+
+void fe_modes_init(void);
+void fe_modes_deinit(void);
+
+void fe_netsplit_init(void);
+void fe_netsplit_deinit(void);
+
+void fe_netjoin_init(void);
+void fe_netjoin_deinit(void);
+
+void fe_whois_init(void);
+void fe_whois_deinit(void);
+
+void fe_sasl_init(void);
+void fe_sasl_deinit(void);
+
+void fe_cap_init(void);
+void fe_cap_deinit(void);
+
+void irc_completion_init(void);
+void irc_completion_deinit(void);
+
+void fe_common_irc_init(void)
+{
+ settings_add_bool("lookandfeel", "show_away_once", TRUE);
+
+ theme_register(fecommon_irc_formats);
+
+ fe_irc_channels_init();
+ fe_irc_queries_init();
+ fe_irc_messages_init();
+ fe_irc_commands_init();
+ fe_ircnet_init();
+ fe_irc_server_init();
+ fe_ctcp_init();
+ fe_events_init();
+ fe_events_numeric_init();
+ fe_modes_init();
+ fe_netsplit_init();
+ fe_netjoin_init();
+ fe_whois_init();
+ fe_sasl_init();
+ fe_cap_init();
+ irc_completion_init();
+
+ settings_check();
+ module_register("irc", "fe-common");
+
+ fe_irc_modules_init();
+}
+
+void fe_common_irc_deinit(void)
+{
+ fe_irc_modules_deinit();
+
+ fe_irc_channels_deinit();
+ fe_irc_queries_deinit();
+ fe_irc_messages_deinit();
+ fe_irc_commands_deinit();
+ fe_ircnet_deinit();
+ fe_irc_server_deinit();
+ fe_ctcp_deinit();
+ fe_events_deinit();
+ fe_events_numeric_deinit();
+ fe_modes_deinit();
+ fe_netsplit_deinit();
+ fe_netjoin_deinit();
+ fe_whois_deinit();
+ fe_sasl_deinit();
+ fe_cap_deinit();
+ irc_completion_deinit();
+
+ theme_unregister();
+}
+
+MODULE_ABICHECK(fe_common_irc)
diff --git a/src/fe-common/irc/fe-ctcp.c b/src/fe-common/irc/fe-ctcp.c
new file mode 100644
index 0000000..1489396
--- /dev/null
+++ b/src/fe-common/irc/fe-ctcp.c
@@ -0,0 +1,170 @@
+/*
+ fe-ctcp.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/servers.h>
+#include <irssi/src/core/channels.h>
+#include <irssi/src/core/queries.h>
+#include <irssi/src/core/ignore.h>
+
+#include <irssi/src/fe-common/core/fe-windows.h>
+#include <irssi/src/fe-common/core/window-items.h>
+#include <irssi/src/fe-common/core/printtext.h>
+
+static void ctcp_default_msg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ const char *p;
+ char *cmd;
+
+ p = strchr(data, ' ');
+ if (p == NULL) {
+ cmd = g_strdup(data);
+ data = "";
+ } else {
+ cmd = g_strndup(data, (int) (p-data));
+ data = p+1;
+ }
+
+ printformat(server, server_ischannel(SERVER(server), target) ? target : nick, MSGLEVEL_CTCPS,
+ IRCTXT_CTCP_REQUESTED_UNKNOWN,
+ nick, addr, cmd, data, target);
+ g_free(cmd);
+}
+
+static void ctcp_ping_msg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ signal_emit("message irc ctcp", 6, server, "PING",
+ data, nick, addr, target);
+}
+
+static void ctcp_version_msg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ signal_emit("message irc ctcp", 6, server, "VERSION",
+ data, nick, addr, target);
+}
+
+static void ctcp_time_msg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ signal_emit("message irc ctcp", 6, server, "TIME",
+ data, nick, addr, target);
+}
+
+static void ctcp_userinfo_msg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ signal_emit("message irc ctcp", 6, server, "USERINFO",
+ data, nick, addr, target);
+}
+
+static void ctcp_clientinfo_msg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ signal_emit("message irc ctcp", 6, server, "CLIENTINFO",
+ data, nick, addr, target);
+}
+
+static void ctcp_default_reply(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ const char *ctcpdata;
+ char *ctcp, *ptr;
+
+ g_return_if_fail(data != NULL);
+
+ ctcp = g_strdup(data);
+ ptr = strchr(ctcp, ' ');
+ if (ptr == NULL)
+ ctcpdata = "";
+ else {
+ *ptr = '\0';
+ ctcpdata = ptr+1;
+ }
+
+ printformat(server, server_ischannel(SERVER(server), target) ? target : nick, MSGLEVEL_CTCPS,
+ server_ischannel(SERVER(server), target) ? IRCTXT_CTCP_REPLY_CHANNEL :
+ IRCTXT_CTCP_REPLY, ctcp, nick, ctcpdata, target);
+ g_free(ctcp);
+}
+
+static void ctcp_ping_reply(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ gint64 tv, tv2;
+ long usecs;
+
+ g_return_if_fail(data != NULL);
+
+ if (sscanf(data,
+ "%" G_GINT64_FORMAT " "
+ "%" G_GINT64_FORMAT,
+ &tv, &tv2) < 1) {
+ char *tmp = g_strconcat("PING ", data, NULL);
+ ctcp_default_reply(server, tmp, nick, addr, target);
+ g_free(tmp);
+ return;
+ }
+
+ tv2 += tv * G_TIME_SPAN_SECOND;
+ tv = g_get_real_time();
+ usecs = tv - tv2;
+ printformat(server, server_ischannel(SERVER(server), target) ? target : nick, MSGLEVEL_CTCPS,
+ IRCTXT_CTCP_PING_REPLY, nick, usecs / G_TIME_SPAN_SECOND, usecs % G_TIME_SPAN_SECOND);
+}
+
+void fe_ctcp_init(void)
+{
+ signal_add("default ctcp msg", (SIGNAL_FUNC) ctcp_default_msg);
+ signal_add("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping_msg);
+ signal_add("ctcp msg version", (SIGNAL_FUNC) ctcp_version_msg);
+ signal_add("ctcp msg time", (SIGNAL_FUNC) ctcp_time_msg);
+ signal_add("ctcp msg userinfo", (SIGNAL_FUNC) ctcp_userinfo_msg);
+ signal_add("ctcp msg clientinfo", (SIGNAL_FUNC) ctcp_clientinfo_msg);
+ signal_add("default ctcp reply", (SIGNAL_FUNC) ctcp_default_reply);
+ signal_add("ctcp reply ping", (SIGNAL_FUNC) ctcp_ping_reply);
+}
+
+void fe_ctcp_deinit(void)
+{
+ signal_remove("default ctcp msg", (SIGNAL_FUNC) ctcp_default_msg);
+ signal_remove("ctcp msg ping", (SIGNAL_FUNC) ctcp_ping_msg);
+ signal_remove("ctcp msg version", (SIGNAL_FUNC) ctcp_version_msg);
+ signal_remove("ctcp msg time", (SIGNAL_FUNC) ctcp_time_msg);
+ signal_remove("ctcp msg userinfo", (SIGNAL_FUNC) ctcp_userinfo_msg);
+ signal_remove("ctcp msg clientinfo", (SIGNAL_FUNC) ctcp_clientinfo_msg);
+ signal_remove("default ctcp reply", (SIGNAL_FUNC) ctcp_default_reply);
+ signal_remove("ctcp reply ping", (SIGNAL_FUNC) ctcp_ping_reply);
+}
diff --git a/src/fe-common/irc/fe-events-numeric.c b/src/fe-common/irc/fe-events-numeric.c
new file mode 100644
index 0000000..34ba3fe
--- /dev/null
+++ b/src/fe-common/irc/fe-events-numeric.c
@@ -0,0 +1,903 @@
+/*
+ fe-events-numeric.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/recode.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/core/nicklist.h>
+#include <irssi/src/irc/core/mode-lists.h>
+
+#include <irssi/src/fe-common/core/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/fe-channels.h>
+#include <irssi/src/fe-common/irc/fe-irc-server.h>
+
+static void print_event_received(IRC_SERVER_REC *server, const char *data,
+ const char *nick, int target_param);
+
+static char *last_away_nick = NULL;
+static char *last_away_msg = NULL;
+
+static void event_user_mode(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *mode;
+
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(server != NULL);
+
+ params = event_get_params(data, 2, NULL, &mode);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_USER_MODE,
+ g_strchomp(mode));
+ g_free(params);
+}
+
+static void event_ison(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *online;
+
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(server != NULL);
+
+ params = event_get_params(data, 2, NULL, &online);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_ONLINE, online);
+ g_free(params);
+}
+
+static void event_names_list(IRC_SERVER_REC *server, const char *data)
+{
+ IRC_CHANNEL_REC *chanrec;
+ char *params, *channel, *names;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 4, NULL, NULL, &channel, &names);
+
+ chanrec = irc_channel_find(server, channel);
+ if (chanrec == NULL || chanrec->names_got) {
+ printformat_module("fe-common/core", server, channel,
+ MSGLEVEL_CRAP, TXT_NAMES,
+ channel, 0, 0, 0, 0, 0);
+ printtext(server, channel, MSGLEVEL_CRAP, "%s", names);
+
+ }
+ g_free(params);
+}
+
+static void event_end_of_names(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ IRC_CHANNEL_REC *chanrec;
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+
+ chanrec = irc_channel_find(server, channel);
+ if (chanrec == NULL || chanrec->names_got)
+ print_event_received(server, data, nick, FALSE);
+ g_free(params);
+}
+
+static void event_who(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *channel, *user, *host, *stat, *realname, *hops;
+ char *serv, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 8, NULL, &channel, &user,
+ &host, &serv, &nick, &stat, &realname);
+
+ /* split hops/realname */
+ hops = realname;
+ while (*realname != '\0' && *realname != ' ') realname++;
+ if (*realname == ' ')
+ *realname++ = '\0';
+
+ recoded = recode_in(SERVER(server), realname, nick);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_WHO,
+ channel, nick, stat, hops, user, host, recoded, serv);
+
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_end_of_who(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_END_OF_WHO, channel);
+ g_free(params);
+}
+
+static void event_ban_list(IRC_SERVER_REC *server, const char *data)
+{
+ IRC_CHANNEL_REC *chanrec;
+ BAN_REC *banrec;
+ const char *channel;
+ char *params, *ban, *setby, *tims;
+ long secs;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 5, NULL, &channel,
+ &ban, &setby, &tims);
+ secs = *tims == '\0' ? 0 :
+ (long) (time(NULL) - atol(tims));
+
+ chanrec = irc_channel_find(server, channel);
+ banrec = chanrec == NULL ? NULL : banlist_find(chanrec->banlist, ban);
+
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ *setby == '\0' ? IRCTXT_BANLIST : IRCTXT_BANLIST_LONG,
+ banrec == NULL ? 0 : g_slist_index(chanrec->banlist, banrec)+1,
+ channel, ban, setby, secs);
+
+ g_free(params);
+}
+
+static void event_eban_list(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *ban, *setby, *tims;
+ long secs;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 5, NULL, &channel,
+ &ban, &setby, &tims);
+ secs = *tims == '\0' ? 0 :
+ (long) (time(NULL) - atol(tims));
+
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ *setby == '\0' ? IRCTXT_EBANLIST : IRCTXT_EBANLIST_LONG,
+ channel, ban, setby, secs);
+
+ g_free(params);
+}
+
+static void event_silence_list(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *mask;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &mask);
+ printformat(server, NULL, MSGLEVEL_CRAP,
+ IRCTXT_SILENCE_LINE, nick, mask);
+ g_free(params);
+}
+
+static void event_accept_list(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *accepted;
+
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(server != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST,
+ NULL, &accepted);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_ACCEPT_LIST, accepted);
+ g_free(params);
+}
+
+static void event_invite_list(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *invite, *setby, *tims;
+ long secs;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 5, NULL, &channel, &invite,
+ &setby, &tims);
+ secs = *tims == '\0' ? 0 :
+ (long) (time(NULL) - atol(tims));
+
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ *setby == '\0' ? IRCTXT_INVITELIST : IRCTXT_INVITELIST_LONG,
+ channel, invite, setby, secs);
+ g_free(params);
+}
+
+static void event_nick_in_use(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &nick);
+ if (server->connected) {
+ printformat(server, NULL, MSGLEVEL_CRAP,
+ IRCTXT_NICK_IN_USE, nick);
+ }
+
+ g_free(params);
+}
+
+static void event_topic_get(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *topic, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &channel, &topic);
+ recoded = recode_in(SERVER(server), topic, channel);
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ IRCTXT_TOPIC, channel, recoded);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_topic_info(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *timestr, *bynick, *byhost, *topictime;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 4, NULL, &channel,
+ &bynick, &topictime);
+
+ timestr = my_asctime((time_t) atol(topictime));
+
+ byhost = strchr(bynick, '!');
+ if (byhost != NULL)
+ *byhost++ = '\0';
+
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP, IRCTXT_TOPIC_INFO,
+ bynick, timestr, byhost == NULL ? "" : byhost);
+ g_free(timestr);
+ g_free(params);
+}
+
+static void event_channel_mode(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *mode;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3 | PARAM_FLAG_GETREST,
+ NULL, &channel, &mode);
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ IRCTXT_CHANNEL_MODE, channel, g_strchomp(mode));
+ g_free(params);
+}
+
+static void event_channel_created(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *createtime, *timestr;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &channel, &createtime);
+
+ timestr = my_asctime((time_t) atol(createtime));
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ IRCTXT_CHANNEL_CREATED, channel, timestr);
+ g_free(timestr);
+ g_free(params);
+}
+
+static void event_nowaway(IRC_SERVER_REC *server, const char *data)
+{
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_AWAY);
+}
+
+static void event_unaway(IRC_SERVER_REC *server, const char *data)
+{
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_UNAWAY);
+}
+
+static void event_away(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *awaymsg, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &awaymsg);
+ recoded = recode_in(SERVER(server), awaymsg, nick);
+ if (!settings_get_bool("show_away_once") ||
+ last_away_nick == NULL ||
+ g_ascii_strcasecmp(last_away_nick, nick) != 0 ||
+ last_away_msg == NULL ||
+ g_ascii_strcasecmp(last_away_msg, awaymsg) != 0) {
+ /* don't show the same away message
+ from the same nick all the time */
+ g_free_not_null(last_away_nick);
+ g_free_not_null(last_away_msg);
+ last_away_nick = g_strdup(nick);
+ last_away_msg = g_strdup(awaymsg);
+
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_NICK_AWAY, nick, recoded);
+ }
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_userhost(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *hosts;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &hosts);
+ printtext(server, NULL, MSGLEVEL_CRAP, "%s", hosts);
+ g_free(params);
+}
+
+static void event_sent_invite(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &channel);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_INVITING, nick, channel);
+ g_free(params);
+}
+
+static void event_chanserv_url(IRC_SERVER_REC *server, const char *data)
+{
+ const char *channel;
+ char *params, *url;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &channel, &url);
+ channel = get_visible_target(server, channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ IRCTXT_CHANNEL_URL, channel, url);
+ g_free(params);
+}
+
+static void event_target_unavailable(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ IRC_CHANNEL_REC *chanrec;
+ char *params, *target;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &target);
+ if (!server_ischannel(SERVER(server), target)) {
+ /* nick unavailable */
+ printformat(server, NULL, MSGLEVEL_CRAP,
+ IRCTXT_NICK_UNAVAILABLE, target);
+ } else {
+ chanrec = irc_channel_find(server, target);
+ if (chanrec != NULL && chanrec->joined) {
+ /* dalnet - can't change nick while being banned */
+ print_event_received(server, data, nick, FALSE);
+ } else {
+ /* channel is unavailable. */
+ printformat(server, NULL, MSGLEVEL_CRAP,
+ IRCTXT_JOINERROR_UNAVAIL, target);
+ }
+ }
+
+ g_free(params);
+}
+
+static void event_no_such_nick(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *unick;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &unick);
+ if (!g_strcmp0(unick, "*"))
+ /* more information will be in the description,
+ * e.g. * :Target left IRC. Failed to deliver: [hi] */
+ print_event_received(server, data, nick, FALSE);
+ else
+ printformat(server, unick, MSGLEVEL_CRAP, IRCTXT_NO_SUCH_NICK, unick);
+ g_free(params);
+}
+
+static void event_no_such_channel(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+ printformat(server, channel, MSGLEVEL_CRAP,
+ IRCTXT_NO_SUCH_CHANNEL, channel);
+ g_free(params);
+}
+
+static void cannot_join(IRC_SERVER_REC *server, const char *data, int format)
+{
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+ printformat(server, NULL, MSGLEVEL_CRAP, format, channel);
+ g_free(params);
+}
+
+static void event_too_many_channels(IRC_SERVER_REC *server, const char *data)
+{
+ cannot_join(server, data, IRCTXT_JOINERROR_TOOMANY);
+}
+
+static void event_duplicate_channel(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ char *params, *channel, *p;
+
+ g_return_if_fail(data != NULL);
+
+ /* this new addition to ircd breaks completely with older
+ "standards", "nick Duplicate ::!!channel ...." */
+ params = event_get_params(data, 3, NULL, NULL, &channel);
+ p = strchr(channel, ' ');
+ if (p != NULL) *p = '\0';
+
+ if (channel[0] == '!' && channel[1] == '!') {
+ printformat(server, NULL, MSGLEVEL_CRAP,
+ IRCTXT_JOINERROR_DUPLICATE, channel+1);
+ } else
+ print_event_received(server, data, nick, FALSE);
+
+ g_free(params);
+}
+
+static void event_channel_is_full(IRC_SERVER_REC *server, const char *data)
+{
+ cannot_join(server, data, IRCTXT_JOINERROR_FULL);
+}
+
+static void event_invite_only(IRC_SERVER_REC *server, const char *data)
+{
+ cannot_join(server, data, IRCTXT_JOINERROR_INVITE);
+}
+
+static void event_banned(IRC_SERVER_REC *server, const char *data)
+{
+ cannot_join(server, data, IRCTXT_JOINERROR_BANNED);
+}
+
+static void event_bad_channel_key(IRC_SERVER_REC *server, const char *data)
+{
+ cannot_join(server, data, IRCTXT_JOINERROR_BAD_KEY);
+}
+
+static void event_bad_channel_mask(IRC_SERVER_REC *server, const char *data)
+{
+ cannot_join(server, data, IRCTXT_JOINERROR_BAD_MASK);
+}
+
+static void event_477(IRC_SERVER_REC *server, const char *data, const char *nick)
+{
+ /* Numeric 477 can mean many things:
+ * modeless channel, cannot join/send to channel (+r/+R/+M).
+ * If we tried to join this channel, display the error in the
+ * status window. Otherwise display it in the channel window.
+ */
+ IRC_CHANNEL_REC *chanrec;
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+
+ chanrec = irc_channel_find(server, channel);
+ print_event_received(server, data, nick, chanrec == NULL || chanrec->joined);
+ g_free(params);
+}
+
+static void event_489(IRC_SERVER_REC *server, const char *data, const char *nick)
+{
+ /* Numeric 489 can mean one of two things things:
+ * cannot join to channel (secure only), or not chanop or voice.
+ * If we tried to join this channel, display the joinerror.
+ * Otherwise depending on the channel being joined or not
+ * display the error in the channel or status window.
+ */
+ IRC_CHANNEL_REC *chanrec;
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+
+ chanrec = irc_channel_find(server, channel);
+ if (chanrec != NULL && !chanrec->joined) {
+ cannot_join(server, data, IRCTXT_JOINERROR_SECURE_ONLY);
+ } else {
+ print_event_received(server, data, nick, chanrec == NULL || chanrec->joined);
+ }
+ g_free(params);
+}
+
+static void event_help(IRC_SERVER_REC *server, int formatnum, const char *data)
+{
+ /* Common handling for umerics 704 (RPL_HELPSTART), 705 (RPL_HELPTXT),
+ * and 706 (RPL_ENDOFHELP); sent as a reply to HELP or HELPOP command.
+ */
+ char *params, *topic, *help_text;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &topic, &help_text);
+
+ g_return_if_fail(help_text != NULL);
+
+ if (help_text[0] == '\0') {
+ /* Empty lines can be used by servers for styling; and we need to replace
+ * them with something non-empty or they would be dropped when displayed.
+ */
+ help_text = " ";
+ }
+
+ printformat(server, NULL, MSGLEVEL_CRAP, formatnum, topic, help_text);
+ g_free(params);
+}
+
+static void event_helpstart(IRC_SERVER_REC *server, const char *data, const char *nick)
+{
+ /* Numeric 704 (RPL_HELPSTART) sent as a reply to HELP or HELPOP command.
+ */
+ event_help(server, IRCTXT_SERVER_HELP_START, data);
+}
+
+static void event_helptxt(IRC_SERVER_REC *server, const char *data, const char *nick)
+{
+ /* Numeric 705 (RPL_HELPTXT), sent as a reply to HELP or HELPOP command.
+ */
+ event_help(server, IRCTXT_SERVER_HELP_TXT, data);
+}
+
+static void event_endofhelp(IRC_SERVER_REC *server, const char *data, const char *nick)
+{
+ /* Numeric 706 (RPL_ENDOFHELP), sent as a reply to HELP or HELPOP command.
+ */
+ event_help(server, IRCTXT_SERVER_END_OF_HELP, data);
+}
+
+static void event_target_too_fast(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ /* Target change too fast, could be nick or channel.
+ * If we tried to join this channel, display the error in the
+ * status window. Otherwise display it in the channel window.
+ */
+ IRC_CHANNEL_REC *chanrec;
+ char *params, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &channel);
+
+ chanrec = irc_channel_find(server, channel);
+ print_event_received(server, data, nick, chanrec == NULL || chanrec->joined);
+ g_free(params);
+}
+
+static void event_unknown_mode(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *mode;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &mode);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_UNKNOWN_MODE, mode);
+ g_free(params);
+}
+
+static void event_numeric(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ data = strchr(data, ' ');
+ if (data != NULL)
+ print_event_received(server, data+1, nick, FALSE);
+}
+
+static void print_event_received(IRC_SERVER_REC *server, const char *data,
+ const char *nick, int target_param)
+{
+ char *target, *args, *ptr, *ptr2, *recoded;
+ int format;
+
+ g_return_if_fail(data != NULL);
+
+ /* first param is our nick, "*" or a channel */
+ ptr = strchr(data, ' ');
+ if (ptr == NULL)
+ return;
+ ptr++;
+
+ if (server_ischannel(SERVER(server), data)) /* directed at channel */
+ target = g_strndup(data, (int)(ptr - data - 1));
+ else if (!target_param || *ptr == ':' || (ptr2 = strchr(ptr, ' ')) == NULL)
+ target = NULL;
+ else {
+ /* target parameter expected and present */
+ target = g_strndup(ptr, (int) (ptr2-ptr));
+ }
+
+ /* param1 param2 ... :last parameter */
+ if (*ptr == ':') {
+ /* only one parameter */
+ args = g_strdup(ptr+1);
+ } else {
+ args = g_strdup(ptr);
+ ptr = strstr(args, " :");
+ if (ptr != NULL)
+ memmove(ptr+1, ptr+2, strlen(ptr+1));
+ }
+
+ recoded = recode_in(SERVER(server), args, NULL);
+ format = nick == NULL || server->real_address == NULL ||
+ g_strcmp0(nick, server->real_address) == 0 ?
+ IRCTXT_DEFAULT_EVENT : IRCTXT_DEFAULT_EVENT_SERVER;
+ printformat(server, target, MSGLEVEL_CRAP, format,
+ nick, recoded, current_server_event);
+
+ g_free(recoded);
+ g_free(args);
+ g_free(target);
+}
+
+static void event_received(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ print_event_received(server, data, nick, FALSE);
+}
+
+static void event_target_received(IRC_SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ print_event_received(server, data, nick, TRUE);
+}
+
+static void event_motd(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ /* don't ignore motd anymore after 3 seconds of connection time -
+ we might have called /MOTD */
+ if (settings_get_bool("skip_motd") && !server->motd_got)
+ return;
+
+ print_event_received(server, data, nick, FALSE);
+}
+
+static void sig_empty(void)
+{
+}
+
+void fe_events_numeric_init(void)
+{
+ last_away_nick = NULL;
+ last_away_msg = NULL;
+
+ /* clang-format off */
+ signal_add("event 221", (SIGNAL_FUNC) event_user_mode);
+ signal_add("event 303", (SIGNAL_FUNC) event_ison);
+ signal_add("event 353", (SIGNAL_FUNC) event_names_list);
+ signal_add_first("event 366", (SIGNAL_FUNC) event_end_of_names);
+ signal_add("event 352", (SIGNAL_FUNC) event_who);
+ signal_add("event 315", (SIGNAL_FUNC) event_end_of_who);
+ signal_add("event 271", (SIGNAL_FUNC) event_silence_list);
+ signal_add("event 272", (SIGNAL_FUNC) sig_empty);
+ signal_add("event 281", (SIGNAL_FUNC) event_accept_list);
+ signal_add("event 367", (SIGNAL_FUNC) event_ban_list);
+ signal_add("event 348", (SIGNAL_FUNC) event_eban_list);
+ signal_add("event 346", (SIGNAL_FUNC) event_invite_list);
+ signal_add("event 433", (SIGNAL_FUNC) event_nick_in_use);
+ signal_add("event 332", (SIGNAL_FUNC) event_topic_get);
+ signal_add("event 333", (SIGNAL_FUNC) event_topic_info);
+ signal_add("event 324", (SIGNAL_FUNC) event_channel_mode);
+ signal_add("event 329", (SIGNAL_FUNC) event_channel_created);
+ signal_add("event 306", (SIGNAL_FUNC) event_nowaway);
+ signal_add("event 305", (SIGNAL_FUNC) event_unaway);
+ signal_add("event 301", (SIGNAL_FUNC) event_away);
+ signal_add("event 328", (SIGNAL_FUNC) event_chanserv_url);
+ signal_add("event 302", (SIGNAL_FUNC) event_userhost);
+ signal_add("event 341", (SIGNAL_FUNC) event_sent_invite);
+
+ signal_add("event 437", (SIGNAL_FUNC) event_target_unavailable);
+ signal_add("event 401", (SIGNAL_FUNC) event_no_such_nick);
+ signal_add("event 403", (SIGNAL_FUNC) event_no_such_channel);
+ signal_add("event 405", (SIGNAL_FUNC) event_too_many_channels);
+ signal_add("event 407", (SIGNAL_FUNC) event_duplicate_channel);
+ signal_add("event 471", (SIGNAL_FUNC) event_channel_is_full);
+ signal_add("event 472", (SIGNAL_FUNC) event_unknown_mode);
+ signal_add("event 473", (SIGNAL_FUNC) event_invite_only);
+ signal_add("event 474", (SIGNAL_FUNC) event_banned);
+ signal_add("event 475", (SIGNAL_FUNC) event_bad_channel_key);
+ signal_add("event 476", (SIGNAL_FUNC) event_bad_channel_mask);
+ signal_add("event 477", (SIGNAL_FUNC) event_477);
+ signal_add("event 489", (SIGNAL_FUNC) event_489); /* cannot join to channel (secure only), or not chanop or voice. */
+ signal_add("event 375", (SIGNAL_FUNC) event_motd);
+ signal_add("event 376", (SIGNAL_FUNC) event_motd);
+ signal_add("event 372", (SIGNAL_FUNC) event_motd);
+ signal_add("event 422", (SIGNAL_FUNC) event_motd);
+ signal_add("event 439", (SIGNAL_FUNC) event_target_too_fast);
+ signal_add("event 704", (SIGNAL_FUNC) event_helpstart);
+ signal_add("event 705", (SIGNAL_FUNC) event_helptxt);
+ signal_add("event 706", (SIGNAL_FUNC) event_endofhelp);
+ signal_add("event 707", (SIGNAL_FUNC) event_target_too_fast);
+
+ signal_add("default event numeric", (SIGNAL_FUNC) event_numeric);
+ /* Because default event numeric only fires if there is no specific
+ * event, add all numerics with a handler elsewhere in irssi that
+ * should not be printed specially here.
+ */
+ signal_add("event 001", (SIGNAL_FUNC) event_received);
+ signal_add("event 004", (SIGNAL_FUNC) event_received);
+ signal_add("event 005", (SIGNAL_FUNC) event_received);
+ signal_add("event 254", (SIGNAL_FUNC) event_received);
+ signal_add("event 354", (SIGNAL_FUNC) event_received);
+ signal_add("event 364", (SIGNAL_FUNC) event_received);
+ signal_add("event 365", (SIGNAL_FUNC) event_received);
+ signal_add("event 381", (SIGNAL_FUNC) event_received);
+ signal_add("event 396", (SIGNAL_FUNC) event_received);
+ signal_add("event 421", (SIGNAL_FUNC) event_received);
+ signal_add("event 432", (SIGNAL_FUNC) event_received);
+ signal_add("event 436", (SIGNAL_FUNC) event_received);
+ signal_add("event 438", (SIGNAL_FUNC) event_received);
+ signal_add("event 465", (SIGNAL_FUNC) event_received);
+ signal_add("event 470", (SIGNAL_FUNC) event_received);
+ signal_add("event 479", (SIGNAL_FUNC) event_received);
+
+ signal_add("event 344", (SIGNAL_FUNC) event_target_received); /* reop list */
+ signal_add("event 345", (SIGNAL_FUNC) event_target_received); /* end of reop list */
+ signal_add("event 347", (SIGNAL_FUNC) event_target_received); /* end of invite exception list */
+ signal_add("event 349", (SIGNAL_FUNC) event_target_received); /* end of ban exception list */
+ signal_add("event 368", (SIGNAL_FUNC) event_target_received); /* end of ban list */
+ signal_add("event 386", (SIGNAL_FUNC) event_target_received); /* owner list; old rsa challenge (harmless) */
+ signal_add("event 387", (SIGNAL_FUNC) event_target_received); /* end of owner list */
+ signal_add("event 388", (SIGNAL_FUNC) event_target_received); /* protect list */
+ signal_add("event 389", (SIGNAL_FUNC) event_target_received); /* end of protect list */
+ signal_add("event 404", (SIGNAL_FUNC) event_target_received); /* cannot send to channel */
+ signal_add("event 408", (SIGNAL_FUNC) event_target_received); /* cannot send (+c) */
+ signal_add("event 442", (SIGNAL_FUNC) event_target_received); /* you're not on that channel */
+ signal_add("event 478", (SIGNAL_FUNC) event_target_received); /* ban list is full */
+ signal_add("event 482", (SIGNAL_FUNC) event_target_received); /* not chanop */
+ signal_add("event 486", (SIGNAL_FUNC) event_target_received); /* cannot /msg (+R) */
+ signal_add("event 494", (SIGNAL_FUNC) event_target_received); /* cannot /msg (own +R) */
+ signal_add("event 506", (SIGNAL_FUNC) event_target_received); /* cannot send (+R) */
+ signal_add("event 716", (SIGNAL_FUNC) event_target_received); /* cannot /msg (+g) */
+ signal_add("event 717", (SIGNAL_FUNC) event_target_received); /* +g notified */
+ signal_add("event 728", (SIGNAL_FUNC) event_target_received); /* quiet (or other) list */
+ signal_add("event 729", (SIGNAL_FUNC) event_target_received); /* end of quiet (or other) list */
+ /* clang-format on */
+}
+
+void fe_events_numeric_deinit(void)
+{
+ g_free_not_null(last_away_nick);
+ g_free_not_null(last_away_msg);
+
+ signal_remove("event 221", (SIGNAL_FUNC) event_user_mode);
+ signal_remove("event 303", (SIGNAL_FUNC) event_ison);
+ signal_remove("event 353", (SIGNAL_FUNC) event_names_list);
+ signal_remove("event 366", (SIGNAL_FUNC) event_end_of_names);
+ signal_remove("event 352", (SIGNAL_FUNC) event_who);
+ signal_remove("event 315", (SIGNAL_FUNC) event_end_of_who);
+ signal_remove("event 271", (SIGNAL_FUNC) event_silence_list);
+ signal_remove("event 272", (SIGNAL_FUNC) sig_empty);
+ signal_remove("event 281", (SIGNAL_FUNC) event_accept_list);
+ signal_remove("event 367", (SIGNAL_FUNC) event_ban_list);
+ signal_remove("event 348", (SIGNAL_FUNC) event_eban_list);
+ signal_remove("event 346", (SIGNAL_FUNC) event_invite_list);
+ signal_remove("event 433", (SIGNAL_FUNC) event_nick_in_use);
+ signal_remove("event 332", (SIGNAL_FUNC) event_topic_get);
+ signal_remove("event 333", (SIGNAL_FUNC) event_topic_info);
+ signal_remove("event 324", (SIGNAL_FUNC) event_channel_mode);
+ signal_remove("event 329", (SIGNAL_FUNC) event_channel_created);
+ signal_remove("event 306", (SIGNAL_FUNC) event_nowaway);
+ signal_remove("event 305", (SIGNAL_FUNC) event_unaway);
+ signal_remove("event 301", (SIGNAL_FUNC) event_away);
+ signal_remove("event 328", (SIGNAL_FUNC) event_chanserv_url);
+ signal_remove("event 302", (SIGNAL_FUNC) event_userhost);
+ signal_remove("event 341", (SIGNAL_FUNC) event_sent_invite);
+
+ signal_remove("event 437", (SIGNAL_FUNC) event_target_unavailable);
+ signal_remove("event 401", (SIGNAL_FUNC) event_no_such_nick);
+ signal_remove("event 403", (SIGNAL_FUNC) event_no_such_channel);
+ signal_remove("event 405", (SIGNAL_FUNC) event_too_many_channels);
+ signal_remove("event 407", (SIGNAL_FUNC) event_duplicate_channel);
+ signal_remove("event 471", (SIGNAL_FUNC) event_channel_is_full);
+ signal_remove("event 472", (SIGNAL_FUNC) event_unknown_mode);
+ signal_remove("event 473", (SIGNAL_FUNC) event_invite_only);
+ signal_remove("event 474", (SIGNAL_FUNC) event_banned);
+ signal_remove("event 475", (SIGNAL_FUNC) event_bad_channel_key);
+ signal_remove("event 476", (SIGNAL_FUNC) event_bad_channel_mask);
+ signal_remove("event 477", (SIGNAL_FUNC) event_477);
+ signal_remove("event 489", (SIGNAL_FUNC) event_489);
+ signal_remove("event 375", (SIGNAL_FUNC) event_motd);
+ signal_remove("event 376", (SIGNAL_FUNC) event_motd);
+ signal_remove("event 372", (SIGNAL_FUNC) event_motd);
+ signal_remove("event 422", (SIGNAL_FUNC) event_motd);
+ signal_remove("event 439", (SIGNAL_FUNC) event_target_too_fast);
+ signal_remove("event 704", (SIGNAL_FUNC) event_helpstart);
+ signal_remove("event 705", (SIGNAL_FUNC) event_helptxt);
+ signal_remove("event 706", (SIGNAL_FUNC) event_endofhelp);
+ signal_remove("event 707", (SIGNAL_FUNC) event_target_too_fast);
+
+ signal_remove("default event numeric", (SIGNAL_FUNC) event_numeric);
+ signal_remove("event 001", (SIGNAL_FUNC) event_received);
+ signal_remove("event 004", (SIGNAL_FUNC) event_received);
+ signal_remove("event 005", (SIGNAL_FUNC) event_received);
+ signal_remove("event 254", (SIGNAL_FUNC) event_received);
+ signal_remove("event 354", (SIGNAL_FUNC) event_received);
+ signal_remove("event 364", (SIGNAL_FUNC) event_received);
+ signal_remove("event 365", (SIGNAL_FUNC) event_received);
+ signal_remove("event 381", (SIGNAL_FUNC) event_received);
+ signal_remove("event 396", (SIGNAL_FUNC) event_received);
+ signal_remove("event 421", (SIGNAL_FUNC) event_received);
+ signal_remove("event 432", (SIGNAL_FUNC) event_received);
+ signal_remove("event 436", (SIGNAL_FUNC) event_received);
+ signal_remove("event 438", (SIGNAL_FUNC) event_received);
+ signal_remove("event 465", (SIGNAL_FUNC) event_received);
+ signal_remove("event 470", (SIGNAL_FUNC) event_received);
+ signal_remove("event 479", (SIGNAL_FUNC) event_received);
+
+ signal_remove("event 344", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 345", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 347", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 349", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 368", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 386", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 387", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 388", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 389", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 404", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 408", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 442", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 478", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 482", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 486", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 494", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 506", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 716", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 717", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 728", (SIGNAL_FUNC) event_target_received);
+ signal_remove("event 729", (SIGNAL_FUNC) event_target_received);
+}
diff --git a/src/fe-common/irc/fe-events.c b/src/fe-common/irc/fe-events.c
new file mode 100644
index 0000000..b6b3e75
--- /dev/null
+++ b/src/fe-common/irc/fe-events.c
@@ -0,0 +1,550 @@
+/*
+ fe-events.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/servers.h>
+#include <irssi/src/irc/core/servers-redirect.h>
+#include <irssi/src/core/servers-reconnect.h>
+#include <irssi/src/core/queries.h>
+#include <irssi/src/core/ignore.h>
+#include <irssi/src/core/recode.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/irc/core/irc-nicklist.h>
+#include <irssi/src/irc/core/irc-masks.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/fe-queries.h>
+#include <irssi/src/fe-common/core/fe-windows.h>
+#include <irssi/src/fe-common/irc/fe-irc-server.h>
+#include <irssi/src/fe-common/irc/fe-irc-channels.h>
+
+static void event_privmsg(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *target, *msg, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
+ if (nick == NULL) nick = server->real_address;
+ if (addr == NULL) addr = "";
+
+ if (fe_channel_is_opchannel(server, target)) {
+ /* Hybrid 6 feature, send msg to all ops in channel */
+ const char *cleantarget = fe_channel_skip_prefix(server, target);
+ recoded = recode_in(SERVER(server), msg, cleantarget);
+
+ /* pass the original target to the signal, with the @+ here
+ * the other one is only needed for recode_in*/
+ signal_emit("message irc op_public", 5,
+ server, recoded, nick, addr, target);
+ } else {
+ recoded = recode_in(SERVER(server), msg, server_ischannel(SERVER(server), target) ? target : nick);
+ signal_emit(server_ischannel(SERVER(server), target) ?
+ "message public" : "message private", 5,
+ server, recoded, nick, addr,
+ get_visible_target(server, target));
+ }
+
+ g_free(params);
+ g_free(recoded);
+}
+
+static void ctcp_action(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr,
+ const char *target)
+{
+ char *recoded;
+
+ g_return_if_fail(data != NULL);
+ recoded = recode_in(SERVER(server), data, target);
+ signal_emit("message irc action", 5,
+ server, recoded, nick, addr,
+ get_visible_target(server, target));
+ g_free(recoded);
+}
+
+static void event_notice(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *target, *msg, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg);
+ recoded = recode_in(SERVER(server), msg, target);
+ if (nick == NULL) {
+ nick = server->real_address == NULL ?
+ server->connrec->address :
+ server->real_address;
+ }
+
+ signal_emit("message irc notice", 5, server, recoded, nick, addr,
+ get_visible_target(server, target));
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_join(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *channel, *tmp, *account, *realname;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, &channel, &account, &realname);
+ tmp = strchr(channel, 7); /* ^G does something weird.. */
+ if (tmp != NULL) *tmp = '\0';
+
+ signal_emit("message join", 6, server,
+ get_visible_target(server, channel), nick, addr, account, realname);
+ g_free(params);
+}
+
+static void event_chghost(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *user, *host, *new_addr;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, &user, &host);
+ new_addr = g_strconcat(user, "@", host, NULL);
+
+ signal_emit("message host_changed", 4, server, nick, new_addr, addr);
+
+ g_free(new_addr);
+ g_free(params);
+}
+
+static void event_account(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *account;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 1, &account);
+
+ signal_emit("message account_changed", 4, server, nick, addr, account);
+
+ g_free(params);
+}
+
+static void event_part(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *channel, *reason, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST,
+ &channel, &reason);
+ recoded = recode_in(SERVER(server), reason, channel);
+ signal_emit("message part", 5, server,
+ get_visible_target(server, channel), nick, addr, recoded);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_quit(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ if (*data == ':') data++; /* quit message */
+ recoded = recode_in(SERVER(server), data, nick);
+ signal_emit("message quit", 4, server, nick, addr, recoded);
+ g_free(recoded);
+}
+
+static void event_kick(IRC_SERVER_REC *server, const char *data,
+ const char *kicker, const char *addr)
+{
+ char *params, *channel, *nick, *reason, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3 | PARAM_FLAG_GETREST,
+ &channel, &nick, &reason);
+ recoded = recode_in(SERVER(server), reason, channel);
+ signal_emit("message kick", 6,
+ server, get_visible_target(server, channel),
+ nick, kicker, addr, recoded);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_kill(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *path, *reason;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST,
+ NULL, &path);
+ reason = strstr(path, " (");
+ if (reason == NULL || reason[strlen(reason)-1] != ')') {
+ /* weird server, maybe it didn't give path */
+ reason = path;
+ path = "";
+ } else {
+ /* reason inside (...) */
+ *reason = '\0';
+ reason += 2;
+ reason[strlen(reason)-1] = '\0';
+ }
+
+ if (addr != NULL) {
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_KILL,
+ nick, addr, reason, path);
+ } else {
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_KILL_SERVER,
+ nick, reason, path);
+ }
+
+ g_free(params);
+}
+
+static void event_nick(IRC_SERVER_REC *server, const char *data,
+ const char *sender, const char *addr)
+{
+ char *params, *newnick;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 1, &newnick);
+
+ /* NOTE: server->nick was already changed in irc/core/irc-nicklist.c */
+ signal_emit(g_ascii_strcasecmp(newnick, server->nick) == 0 ?
+ "message own_nick" : "message nick", 4,
+ server, newnick, sender, addr);
+
+ g_free(params);
+}
+
+static void event_mode(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *channel, *mode;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST,
+ &channel, &mode);
+
+ signal_emit("message irc mode", 5,
+ server, get_visible_target(server, channel),
+ nick, addr, g_strchomp(mode));
+ g_free(params);
+}
+
+static void event_away_notify(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *awaymsg;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 1 | PARAM_FLAG_GETREST,
+ &awaymsg);
+
+ signal_emit("message away_notify", 4,
+ server, nick, addr, awaymsg);
+ g_free(params);
+}
+
+static void event_pong(IRC_SERVER_REC *server, const char *data, const char *nick)
+{
+ char *params, *host, *reply;
+
+ g_return_if_fail(data != NULL);
+ if (nick == NULL) nick = server->real_address;
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &host, &reply);
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_PONG, host, reply);
+ g_free(params);
+}
+
+static void event_invite(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *invited, *channel;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, &invited, &channel);
+ if (server->nick_comp_func(invited, server->nick) == 0) {
+ signal_emit("message invite", 4,
+ server, get_visible_target(server, channel), nick, addr);
+ } else {
+ signal_emit("message invite_other", 5,
+ server, get_visible_target(server, channel), invited, nick, addr);
+ }
+ g_free(params);
+}
+
+static void event_topic(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ char *params, *channel, *topic, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST,
+ &channel, &topic);
+ recoded = recode_in(SERVER(server), topic, channel);
+ signal_emit("message topic", 5, server,
+ get_visible_target(server, channel), recoded, nick, addr);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_error(IRC_SERVER_REC *server, const char *data)
+{
+ g_return_if_fail(data != NULL);
+
+ if (*data == ':') data++;
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_ERROR, data);
+}
+
+static void event_wallops(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr)
+{
+ g_return_if_fail(data != NULL);
+
+ if (*data == ':') data++;
+ if (ignore_check(SERVER(server), nick, addr, NULL, data, MSGLEVEL_WALLOPS))
+ return;
+
+ if (g_ascii_strncasecmp(data, "\001ACTION ", 8) != 0)
+ printformat(server, NULL, MSGLEVEL_WALLOPS, IRCTXT_WALLOPS, nick, data);
+ else {
+ /* Action in WALLOP */
+ int len;
+ char *tmp;
+
+ tmp = g_strdup(data+8);
+ len = strlen(tmp);
+ if (len >= 1 && tmp[len-1] == 1) tmp[len-1] = '\0';
+ printformat(server, NULL, MSGLEVEL_WALLOPS, IRCTXT_ACTION_WALLOPS, nick, tmp);
+ g_free(tmp);
+ }
+}
+
+static void event_silence(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr)
+{
+ g_return_if_fail(data != NULL);
+
+ g_return_if_fail(*data == '+' || *data == '-');
+
+ printformat(server, NULL, MSGLEVEL_CRAP, *data == '+' ? IRCTXT_SILENCED : IRCTXT_UNSILENCED, data+1);
+}
+
+static void channel_sync(CHANNEL_REC *channel)
+{
+ g_return_if_fail(channel != NULL);
+
+ printformat(channel->server, channel->visible_name,
+ MSGLEVEL_CLIENTNOTICE|MSGLEVEL_NO_ACT,
+ IRCTXT_CHANNEL_SYNCED, channel->visible_name,
+ (long) (time(NULL)-channel->createtime));
+}
+
+static void event_connected(IRC_SERVER_REC *server)
+{
+ const char *nick;
+
+ g_return_if_fail(server != NULL);
+
+ nick = server->connrec->nick;
+ if (g_ascii_strcasecmp(server->nick, nick) == 0)
+ return;
+
+ /* someone has our nick, find out who. */
+ server_redirect_event(server, "whois", 1, nick, TRUE, NULL,
+ "event 311", "nickfind event whois",
+ "", "event empty", NULL);
+ irc_send_cmdv(server, "WHOIS %s", nick);
+}
+
+static void event_nickfind_whois(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *user, *host, *realname;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 6, NULL, &nick, &user, &host, NULL, &realname);
+ printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_YOUR_NICK_OWNED, nick, user, host, realname);
+ g_free(params);
+}
+
+static void event_ban_type_changed(void *ban_typep)
+{
+ GString *str;
+ int ban_type;
+
+ ban_type = GPOINTER_TO_INT(ban_typep);
+
+ if (ban_type == 0) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ IRCTXT_BANTYPE, "Error, using Normal");
+ return;
+ }
+
+ if (ban_type == (IRC_MASK_USER|IRC_MASK_DOMAIN)) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_BANTYPE, "Normal");
+ } else if (ban_type == (IRC_MASK_HOST|IRC_MASK_DOMAIN)) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_BANTYPE, "Host");
+ } else if (ban_type == IRC_MASK_DOMAIN) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_BANTYPE, "Domain");
+ } else {
+ str = g_string_new("Custom:");
+ if (ban_type & IRC_MASK_NICK)
+ g_string_append(str, " Nick");
+ if (ban_type & IRC_MASK_USER)
+ g_string_append(str, " User");
+ if (ban_type & IRC_MASK_HOST)
+ g_string_append(str, " Host");
+ if (ban_type & IRC_MASK_DOMAIN)
+ g_string_append(str, " Domain");
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_BANTYPE, str->str);
+ g_string_free(str, TRUE);
+ }
+}
+
+static void sig_whois_event_not_found(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &nick);
+ printformat(server, nick, MSGLEVEL_CRAP, IRCTXT_WHOIS_NOT_FOUND, nick);
+ g_free(params);
+}
+
+static void sig_whowas_event_end(IRC_SERVER_REC *server, const char *data,
+ const char *sender, const char *addr)
+{
+ char *params, *nick;
+
+ g_return_if_fail(data != NULL);
+
+ if (server->whowas_found) {
+ signal_emit("event 369", 4, server, data, sender, addr);
+ return;
+ }
+
+ params = event_get_params(data, 2, NULL, &nick);
+ printformat(server, nick, MSGLEVEL_CRAP, IRCTXT_WHOIS_NOT_FOUND, nick);
+ g_free(params);
+}
+
+static void event_received(IRC_SERVER_REC *server, const char *data,
+ const char *nick, const char *addr)
+{
+ if (!i_isdigit(*data)) {
+ printtext(server, NULL, MSGLEVEL_CRAP, "%s", data);
+ return;
+ }
+
+ /* numeric event. */
+ signal_emit("default event numeric", 4, server, data, nick, addr);
+}
+
+void fe_events_init(void)
+{
+ signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
+ signal_add("ctcp action", (SIGNAL_FUNC) ctcp_action);
+ signal_add("event notice", (SIGNAL_FUNC) event_notice);
+ signal_add("event join", (SIGNAL_FUNC) event_join);
+ signal_add("event chghost", (SIGNAL_FUNC) event_chghost);
+ signal_add("event account", (SIGNAL_FUNC) event_account);
+ signal_add("event part", (SIGNAL_FUNC) event_part);
+ signal_add("event quit", (SIGNAL_FUNC) event_quit);
+ signal_add("event kick", (SIGNAL_FUNC) event_kick);
+ signal_add("event kill", (SIGNAL_FUNC) event_kill);
+ signal_add("event nick", (SIGNAL_FUNC) event_nick);
+ signal_add("event mode", (SIGNAL_FUNC) event_mode);
+ signal_add("event pong", (SIGNAL_FUNC) event_pong);
+ signal_add("event invite", (SIGNAL_FUNC) event_invite);
+ signal_add("event topic", (SIGNAL_FUNC) event_topic);
+ signal_add("event error", (SIGNAL_FUNC) event_error);
+ signal_add("event wallops", (SIGNAL_FUNC) event_wallops);
+ signal_add("event silence", (SIGNAL_FUNC) event_silence);
+ signal_add("event away", (SIGNAL_FUNC) event_away_notify);
+
+ signal_add("default event", (SIGNAL_FUNC) event_received);
+
+ signal_add("channel sync", (SIGNAL_FUNC) channel_sync);
+ signal_add("event connected", (SIGNAL_FUNC) event_connected);
+ signal_add("nickfind event whois", (SIGNAL_FUNC) event_nickfind_whois);
+ signal_add("ban type changed", (SIGNAL_FUNC) event_ban_type_changed);
+ signal_add("whois event not found", (SIGNAL_FUNC) sig_whois_event_not_found);
+ signal_add("whowas event end", (SIGNAL_FUNC) sig_whowas_event_end);
+}
+
+void fe_events_deinit(void)
+{
+ signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
+ signal_remove("ctcp action", (SIGNAL_FUNC) ctcp_action);
+ signal_remove("event notice", (SIGNAL_FUNC) event_notice);
+ signal_remove("event join", (SIGNAL_FUNC) event_join);
+ signal_remove("event chghost", (SIGNAL_FUNC) event_chghost);
+ signal_remove("event account", (SIGNAL_FUNC) event_account);
+ signal_remove("event part", (SIGNAL_FUNC) event_part);
+ signal_remove("event quit", (SIGNAL_FUNC) event_quit);
+ signal_remove("event kick", (SIGNAL_FUNC) event_kick);
+ signal_remove("event kill", (SIGNAL_FUNC) event_kill);
+ signal_remove("event nick", (SIGNAL_FUNC) event_nick);
+ signal_remove("event mode", (SIGNAL_FUNC) event_mode);
+ signal_remove("event pong", (SIGNAL_FUNC) event_pong);
+ signal_remove("event invite", (SIGNAL_FUNC) event_invite);
+ signal_remove("event topic", (SIGNAL_FUNC) event_topic);
+ signal_remove("event error", (SIGNAL_FUNC) event_error);
+ signal_remove("event wallops", (SIGNAL_FUNC) event_wallops);
+ signal_remove("event silence", (SIGNAL_FUNC) event_silence);
+ signal_remove("event away", (SIGNAL_FUNC) event_away_notify);
+
+ signal_remove("default event", (SIGNAL_FUNC) event_received);
+
+ signal_remove("channel sync", (SIGNAL_FUNC) channel_sync);
+ signal_remove("event connected", (SIGNAL_FUNC) event_connected);
+ signal_remove("nickfind event whois", (SIGNAL_FUNC) event_nickfind_whois);
+ signal_remove("ban type changed", (SIGNAL_FUNC) event_ban_type_changed);
+ signal_remove("whois event not found", (SIGNAL_FUNC) sig_whois_event_not_found);
+ signal_remove("whowas event end", (SIGNAL_FUNC) sig_whowas_event_end);
+}
diff --git a/src/fe-common/irc/fe-irc-channels.c b/src/fe-common/irc/fe-irc-channels.c
new file mode 100644
index 0000000..93ff360
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-channels.c
@@ -0,0 +1,111 @@
+/*
+ fe-irc-channels.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/irc/core/channel-rejoin.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/fe-windows.h>
+#include <irssi/src/fe-common/core/window-items.h>
+
+int fe_channel_is_opchannel(IRC_SERVER_REC *server, const char *target)
+{
+ const char *statusmsg;
+
+ /* Quick check */
+ if (server == NULL || server->prefix[(int)(unsigned char)*target] == 0)
+ return FALSE;
+
+ statusmsg = g_hash_table_lookup(server->isupport, "statusmsg");
+ if (statusmsg == NULL)
+ statusmsg = "@";
+
+ return strchr(statusmsg, *target) != NULL;
+}
+
+const char *fe_channel_skip_prefix(IRC_SERVER_REC *server, const char *target)
+{
+ const char *statusmsg;
+
+ /* Quick check */
+ if (server == NULL || server->prefix[(int)(unsigned char)*target] == 0)
+ return target;
+
+ /* Exit early if target doesn't name a channel */
+ if (server_ischannel(SERVER(server), target) == FALSE)
+ return target;
+
+ statusmsg = g_hash_table_lookup(server->isupport, "statusmsg");
+
+ /* Hack: for bahamut 1.4 which sends neither STATUSMSG nor
+ * WALLCHOPS in 005 */
+ if (statusmsg == NULL)
+ statusmsg = "@";
+
+ /* Strip the leading statusmsg prefixes */
+ while (strchr(statusmsg, *target) != NULL) {
+ target++;
+ }
+
+ return target;
+}
+
+static void sig_channel_rejoin(SERVER_REC *server, REJOIN_REC *rec)
+{
+ g_return_if_fail(rec != NULL);
+
+ printformat(server, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_CHANNEL_REJOIN, rec->channel);
+}
+
+static void sig_event_forward(SERVER_REC *server, const char *data,
+ const char *nick)
+{
+ IRC_CHANNEL_REC *channel;
+ char *params, *from, *to;
+
+ params = event_get_params(data, 3, NULL, &from, &to);
+ if (from != NULL && to != NULL && server_ischannel(server, from) && server_ischannel(server, to)) {
+ channel = irc_channel_find(server, from);
+ if (channel != NULL && irc_channel_find(server, to) == NULL) {
+ window_bind_add(window_item_window(channel),
+ server->tag, to);
+ }
+ }
+ g_free(params);
+}
+
+void fe_irc_channels_init(void)
+{
+ signal_add("channel rejoin new", (SIGNAL_FUNC) sig_channel_rejoin);
+ signal_add_first("event 470", (SIGNAL_FUNC) sig_event_forward);
+}
+
+void fe_irc_channels_deinit(void)
+{
+ signal_remove("channel rejoin new", (SIGNAL_FUNC) sig_channel_rejoin);
+ signal_remove("event 470", (SIGNAL_FUNC) sig_event_forward);
+}
diff --git a/src/fe-common/irc/fe-irc-channels.h b/src/fe-common/irc/fe-irc-channels.h
new file mode 100644
index 0000000..a577010
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-channels.h
@@ -0,0 +1,10 @@
+#ifndef IRSSI_FE_COMMON_IRC_FE_IRC_CHANNELS_H
+#define IRSSI_FE_COMMON_IRC_FE_IRC_CHANNELS_H
+
+int fe_channel_is_opchannel(IRC_SERVER_REC *server, const char *target);
+const char *fe_channel_skip_prefix(IRC_SERVER_REC *server, const char *target);
+
+void fe_irc_channels_init(void);
+void fe_irc_channels_deinit(void);
+
+#endif
diff --git a/src/fe-common/irc/fe-irc-commands.c b/src/fe-common/irc/fe-irc-commands.c
new file mode 100644
index 0000000..40ad36e
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-commands.c
@@ -0,0 +1,448 @@
+/*
+ fe-irc-commands.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 <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/special-vars.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/servers.h>
+#include <irssi/src/irc/core/mode-lists.h>
+#include <irssi/src/core/nicklist.h>
+#include <irssi/src/irc/core/irc-commands.h>
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/irc/core/irc-queries.h>
+
+#include <irssi/src/fe-common/core/fe-queries.h>
+#include <irssi/src/fe-common/core/fe-windows.h>
+#include <irssi/src/fe-common/core/window-items.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/keyboard.h>
+
+/* SYNTAX: ME <message> */
+static void cmd_me(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item)
+{
+ const char *target;
+ char *subdata;
+ char **splitdata;
+ int n = 0;
+
+ CMD_IRC_SERVER(server);
+ if (!IS_IRC_ITEM(item))
+ return;
+
+ if (server == NULL || !server->connected)
+ cmd_return_error(CMDERR_NOT_CONNECTED);
+
+ target = window_item_get_target(item);
+ splitdata = irc_server_split_action(server, target, data);
+ while ((subdata = splitdata[n++])) {
+ irc_server_send_action(server, target, subdata);
+ signal_emit("message irc own_action", 3, server, subdata,
+ item->visible_name);
+ }
+ g_strfreev(splitdata);
+}
+
+/* SYNTAX: ACTION [-<server tag>] <target> <message> */
+static void cmd_action(const char *data, IRC_SERVER_REC *server)
+{
+ GHashTable *optlist;
+ const char *target, *text;
+ char *subtext;
+ char **splittexts;
+ int n = 0;
+ void *free_arg;
+
+ CMD_IRC_SERVER(server);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS |
+ PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_GETREST,
+ "action", &optlist, &target, &text))
+ return;
+ if (*target == '\0' || *text == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ server = IRC_SERVER(cmd_options_get_server("action", optlist, SERVER(server)));
+ if (server == NULL || !server->connected)
+ cmd_param_error(CMDERR_NOT_CONNECTED);
+
+ splittexts = irc_server_split_action(server, target, text);
+ while ((subtext = splittexts[n++])) {
+ irc_server_send_action(server, target, subtext);
+ signal_emit("message irc own_action", 3, server, subtext,
+ target);
+ }
+
+ g_strfreev(splittexts);
+ cmd_params_free(free_arg);
+}
+
+static void cmd_notice(const char *data, IRC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ const char *target, *msg;
+ void *free_arg;
+
+ CMD_IRC_SERVER(server);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
+ &target, &msg))
+ return;
+ if (g_strcmp0(target, "*") == 0)
+ target = item == NULL ? "" : window_item_get_target(item);
+
+ if (*target == '\0' || *msg == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ signal_emit("message irc own_notice", 3, server, msg, target);
+
+ cmd_params_free(free_arg);
+}
+
+static void cmd_ctcp(const char *data, IRC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ const char *target;
+ char *ctcpcmd, *ctcpdata;
+ void *free_arg;
+
+ CMD_IRC_SERVER(server);
+
+ if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST,
+ &target, &ctcpcmd, &ctcpdata))
+ return;
+ if (g_strcmp0(target, "*") == 0)
+ target = item == NULL ? "" : window_item_get_target(item);
+ if (*target == '\0' || *ctcpcmd == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ if (*target == '=') {
+ /* don't handle DCC CTCPs */
+ cmd_params_free(free_arg);
+ return;
+ }
+
+ ascii_strup(ctcpcmd);
+ signal_emit("message irc own_ctcp", 4,
+ server, ctcpcmd, ctcpdata, target);
+
+ cmd_params_free(free_arg);
+}
+
+static void cmd_nctcp(const char *data, IRC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ const char *target, *text;
+ void *free_arg;
+
+ CMD_IRC_SERVER(server);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
+ &target, &text))
+ return;
+ if (g_strcmp0(target, "*") == 0)
+ target = item == NULL ? "" : window_item_get_target(item);
+ if (*target == '\0' || *text == '\0')
+ cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ signal_emit("message irc own_notice", 3, server, text, target);
+ cmd_params_free(free_arg);
+}
+
+static void cmd_wall(const char *data, IRC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ IRC_CHANNEL_REC *chanrec;
+ const char *channame, *msg;
+ void *free_arg;
+
+ CMD_IRC_SERVER(server);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTCHAN |
+ PARAM_FLAG_GETREST, item, &channame, &msg))
+ return;
+ if (*msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ chanrec = irc_channel_find(server, channame);
+ if (chanrec == NULL) cmd_param_error(CMDERR_CHAN_NOT_FOUND);
+
+ signal_emit("message irc own_wall", 3, server, msg,
+ chanrec->visible_name);
+
+ cmd_params_free(free_arg);
+}
+
+static void bans_ask_channel(const char *channel, IRC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ GString *str;
+
+ str = g_string_new(NULL);
+ g_string_printf(str, "%s b", channel);
+ signal_emit("command mode", 3, str->str, server, item);
+ if (server->emode_known) {
+ g_string_printf(str, "%s e", channel);
+ signal_emit("command mode", 3, str->str, server, item);
+ }
+ g_string_free(str, TRUE);
+}
+
+static void bans_show_channel(IRC_CHANNEL_REC *channel, IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+ int counter;
+
+ if (channel->banlist == NULL) {
+ printformat(server, channel->visible_name,
+ MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NO_BANS, channel->visible_name);
+ return;
+ }
+
+ /* show bans.. */
+ counter = 1;
+ for (tmp = channel->banlist; tmp != NULL; tmp = tmp->next) {
+ BAN_REC *rec = tmp->data;
+
+ printformat(server, channel->visible_name, MSGLEVEL_CRAP,
+ (rec->setby == NULL || *rec->setby == '\0') ?
+ IRCTXT_BANLIST : IRCTXT_BANLIST_LONG,
+ counter, channel->visible_name,
+ rec->ban, rec->setby,
+ (int) (time(NULL)-rec->time));
+ counter++;
+ }
+}
+
+/* SYNTAX: BAN [<channel>] [<nicks>] */
+static void cmd_ban(const char *data, IRC_SERVER_REC *server,
+ WI_ITEM_REC *item)
+{
+ IRC_CHANNEL_REC *chanrec;
+ char *channel, *nicks;
+ void *free_arg;
+
+ CMD_IRC_SERVER(server);
+
+ if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTCHAN |
+ PARAM_FLAG_GETREST | PARAM_FLAG_STRIP_TRAILING_WS,
+ item, &channel, &nicks))
+ return;
+
+ if (*nicks != '\0') {
+ /* setting ban - don't handle here */
+ cmd_params_free(free_arg);
+ return;
+ }
+
+ /* display bans */
+ chanrec = IRC_CHANNEL(item);
+ if (chanrec == NULL && *channel == '\0')
+ cmd_param_error(CMDERR_NOT_JOINED);
+
+ if (*channel != '\0' && g_strcmp0(channel, "*") != 0)
+ chanrec = irc_channel_find(server, channel);
+
+ if (chanrec == NULL || !chanrec->synced) {
+ /* not joined to such channel or not yet synced,
+ ask ban lists from server */
+ bans_ask_channel(channel, server, item);
+ } else {
+ bans_show_channel(chanrec, server);
+ }
+
+ signal_stop();
+ cmd_params_free(free_arg);
+}
+
+/* SYNTAX: VER [<nick> | <channel> | *] */
+static void cmd_ver(gchar *data, IRC_SERVER_REC *server, WI_ITEM_REC *item)
+{
+ char *str;
+
+ g_return_if_fail(data != NULL);
+
+ CMD_IRC_SERVER(server);
+ if (*data == '\0' && !IS_QUERY(item))
+ cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ str = g_strdup_printf("%s VERSION", *data == '\0' ?
+ window_item_get_target(item) : data);
+ signal_emit("command ctcp", 3, str, server, item);
+ g_free(str);
+}
+
+static void cmd_topic(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ CHANNEL_REC *channel;
+ char *timestr, *bynick, *byhost;
+
+ g_return_if_fail(data != NULL);
+
+ channel = *data != '\0' ? channel_find(server, data) : CHANNEL(item);
+ if (channel == NULL) return;
+
+ printformat(server, channel->visible_name, MSGLEVEL_CRAP,
+ (channel->topic == NULL || *channel->topic == '\0') ? IRCTXT_NO_TOPIC : IRCTXT_TOPIC,
+ channel->visible_name, channel->topic);
+
+ if (channel->topic_time > 0) {
+ byhost = strchr(channel->topic_by, '!');
+ if (byhost == NULL) {
+ bynick = g_strdup(channel->topic_by);
+ byhost = "";
+ } else {
+ bynick = g_strndup(channel->topic_by,
+ (int) (byhost-channel->topic_by));
+ byhost++;
+ }
+
+ timestr = my_asctime(channel->topic_time);
+ printformat(server, channel->visible_name, MSGLEVEL_CRAP,
+ IRCTXT_TOPIC_INFO, bynick, timestr, byhost);
+ g_free(timestr);
+ g_free(bynick);
+ }
+ signal_stop();
+}
+
+/* SYNTAX: TS */
+static void cmd_ts(const char *data)
+{
+ GSList *tmp;
+
+ g_return_if_fail(data != NULL);
+
+ for (tmp = channels; tmp != NULL; tmp = tmp->next) {
+ CHANNEL_REC *rec = tmp->data;
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_TOPIC,
+ rec->visible_name,
+ rec->topic == NULL ? "" : rec->topic);
+ }
+}
+
+typedef struct {
+ char *server_tag;
+ char *nick;
+} OPER_PASS_REC;
+
+static void cmd_oper_got_pass(const char *password, OPER_PASS_REC *rec)
+{
+ SERVER_REC *server_rec = server_find_tag(rec->server_tag);
+ if (*password != '\0' && IS_IRC_SERVER(server_rec))
+ irc_send_cmdv((IRC_SERVER_REC *) server_rec, "OPER %s %s", rec->nick, password);
+ g_free(rec->nick);
+ g_free(rec->server_tag);
+ g_free(rec);
+}
+
+static void cmd_oper(const char *data, IRC_SERVER_REC *server)
+{
+ char *nick, *password, *format;
+ void *free_arg;
+
+ g_return_if_fail(data != NULL);
+ if (!IS_IRC_SERVER(server) || !server->connected)
+ cmd_return_error(CMDERR_NOT_CONNECTED);
+
+ if (!cmd_get_params(data, &free_arg, 2, &nick, &password))
+ return;
+ if (*password == '\0') {
+ /* password not given, ask it.
+ irc/core handles the /OPER when password is given */
+ OPER_PASS_REC *rec;
+
+ rec = g_new(OPER_PASS_REC, 1);
+ rec->server_tag = g_strdup(server->tag);
+ rec->nick = g_strdup(*nick != '\0' ? nick : server->nick);
+
+ format = format_get_text(MODULE_NAME, NULL, server, NULL,
+ IRCTXT_ASK_OPER_PASS);
+
+ keyboard_entry_redirect((SIGNAL_FUNC) cmd_oper_got_pass,
+ format,
+ ENTRY_REDIRECT_FLAG_HIDDEN, rec);
+ g_free(format);
+
+ signal_stop();
+ }
+
+ cmd_params_free(free_arg);
+}
+
+/* SYNTAX: SETHOST <host> <password> (non-ircops)
+ SETHOST <ident> <host> (ircops) */
+static void cmd_sethost(const char *data, IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+
+ g_return_if_fail(data != NULL);
+ if (!IS_IRC_SERVER(server) || !server->connected)
+ cmd_return_error(CMDERR_NOT_CONNECTED);
+
+ /* Save all the joined channels in server to window binds, since
+ the server will soon /PART + /JOIN us in all channels. */
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ CHANNEL_REC *channel = tmp->data;
+
+ window_bind_add(window_item_window(channel),
+ server->tag, channel->visible_name);
+ }
+
+ irc_send_cmdv(server, "SETHOST %s", data);
+}
+
+void fe_irc_commands_init(void)
+{
+ command_bind_irc_last("me", NULL, (SIGNAL_FUNC) cmd_me);
+ command_bind_irc_last("action", NULL, (SIGNAL_FUNC) cmd_action);
+ command_bind_irc("notice", NULL, (SIGNAL_FUNC) cmd_notice);
+ command_bind_irc("ctcp", NULL, (SIGNAL_FUNC) cmd_ctcp);
+ command_bind_irc("nctcp", NULL, (SIGNAL_FUNC) cmd_nctcp);
+ command_bind_irc("wall", NULL, (SIGNAL_FUNC) cmd_wall);
+ command_bind_irc("ban", NULL, (SIGNAL_FUNC) cmd_ban);
+ command_bind_irc("ver", NULL, (SIGNAL_FUNC) cmd_ver);
+ command_bind_irc("topic", NULL, (SIGNAL_FUNC) cmd_topic);
+ command_bind_irc("ts", NULL, (SIGNAL_FUNC) cmd_ts);
+ command_bind_irc("oper", NULL, (SIGNAL_FUNC) cmd_oper);
+ command_bind_irc("sethost", NULL, (SIGNAL_FUNC) cmd_sethost);
+}
+
+void fe_irc_commands_deinit(void)
+{
+ command_unbind("me", (SIGNAL_FUNC) cmd_me);
+ command_unbind("action", (SIGNAL_FUNC) cmd_action);
+ command_unbind("notice", (SIGNAL_FUNC) cmd_notice);
+ command_unbind("ctcp", (SIGNAL_FUNC) cmd_ctcp);
+ command_unbind("nctcp", (SIGNAL_FUNC) cmd_nctcp);
+ command_unbind("wall", (SIGNAL_FUNC) cmd_wall);
+ command_unbind("ban", (SIGNAL_FUNC) cmd_ban);
+ command_unbind("ver", (SIGNAL_FUNC) cmd_ver);
+ command_unbind("topic", (SIGNAL_FUNC) cmd_topic);
+ command_unbind("ts", (SIGNAL_FUNC) cmd_ts);
+ command_unbind("oper", (SIGNAL_FUNC) cmd_oper);
+ command_unbind("sethost", (SIGNAL_FUNC) cmd_sethost);
+}
diff --git a/src/fe-common/irc/fe-irc-messages.c b/src/fe-common/irc/fe-irc-messages.c
new file mode 100644
index 0000000..5d820bb
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-messages.c
@@ -0,0 +1,373 @@
+/*
+ fe-irc-messages.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 <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/channels.h>
+#include <irssi/src/core/ignore.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/irc/core/irc-queries.h>
+
+#include <irssi/src/fe-common/core/module-formats.h>
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/fe-common/core/fe-messages.h>
+
+#include <irssi/src/fe-common/core/fe-queries.h>
+#include <irssi/src/fe-common/core/hilight-text.h>
+#include <irssi/src/fe-common/core/window-items.h>
+#include <irssi/src/fe-common/irc/fe-irc-channels.h>
+#include <irssi/src/fe-common/irc/fe-irc-server.h>
+
+static void sig_message_own_public(SERVER_REC *server, const char *msg,
+ const char *target, const char *origtarget)
+{
+ const char *oldtarget;
+ char *nickmode;
+
+ if (!IS_IRC_SERVER(server))
+ return;
+ oldtarget = target;
+ target = fe_channel_skip_prefix(IRC_SERVER(server), target);
+ if (target != oldtarget) {
+ /* Hybrid 6 / Bahamut feature, send msg to all
+ ops / ops+voices in channel */
+ nickmode = channel_get_nickmode(channel_find(server, target),
+ server->nick);
+
+ printformat_module("fe-common/core", server, target,
+ MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT |
+ MSGLEVEL_NO_ACT,
+ TXT_OWN_MSG_CHANNEL,
+ server->nick, oldtarget, msg, nickmode);
+ g_free(nickmode);
+ signal_stop();
+ }
+
+}
+
+/* received msg to all ops in channel.
+ TODO: this code is a duplication of sig_message_public */
+static void sig_message_irc_op_public(SERVER_REC *server, const char *msg,
+ const char *nick, const char *address,
+ const char *target)
+{
+ CHANNEL_REC *chanrec;
+ char *nickmode, *optarget, *prefix, *color, *freemsg = NULL;
+ const char *cleantarget;
+ int for_me, level;
+ HILIGHT_REC *hilight;
+ TEXT_DEST_REC dest;
+
+ /* only skip here so the difference can be stored in prefix */
+ cleantarget = fe_channel_skip_prefix(IRC_SERVER(server), target);
+ prefix = g_strndup(target, cleantarget - target);
+
+ /* and clean the rest here */
+ cleantarget = get_visible_target(IRC_SERVER(server), cleantarget);
+
+ chanrec = channel_find(server, cleantarget);
+
+ nickmode = channel_get_nickmode(chanrec, nick);
+
+ optarget = g_strconcat(prefix, cleantarget, NULL);
+
+ /* Check for hilights */
+ for_me = !settings_get_bool("hilight_nick_matches") ? FALSE :
+ !settings_get_bool("hilight_nick_matches_everywhere") ?
+ nick_match_msg(chanrec, msg, server->nick) :
+ nick_match_msg_everywhere(chanrec, msg, server->nick);
+ hilight = for_me ? NULL :
+ hilight_match_nick(server, cleantarget, nick, address, MSGLEVEL_PUBLIC, msg);
+ color = (hilight == NULL) ? NULL : hilight_get_color(hilight);
+
+ level = MSGLEVEL_PUBLIC;
+ if (for_me)
+ level |= MSGLEVEL_HILIGHT;
+
+ if (ignore_check_plus(server, nick, address, cleantarget, msg, &level, TRUE)) {
+ g_free(nickmode);
+ g_free(color);
+ g_free(optarget);
+ g_free(prefix);
+ return;
+ }
+
+ if (level & MSGLEVEL_NOHILIGHT) {
+ for_me = FALSE;
+ g_free_and_null(color);
+ level &= ~MSGLEVEL_HILIGHT;
+ }
+
+ if (settings_get_bool("emphasis"))
+ msg = freemsg = expand_emphasis((WI_ITEM_REC *) chanrec, msg);
+
+ if (color != NULL) {
+ format_create_dest(&dest, server, cleantarget, level, NULL);
+ dest.address = address;
+ dest.nick = nick;
+ hilight_update_text_dest(&dest,hilight);
+ printformat_module_dest("fe-common/core", &dest,
+ TXT_PUBMSG_HILIGHT_CHANNEL,
+ color, nick, optarget, msg, nickmode);
+ } else {
+ printformat_module("fe-common/core", server, cleantarget, level,
+ for_me ? TXT_PUBMSG_ME_CHANNEL : TXT_PUBMSG_CHANNEL,
+ nick, optarget, msg, nickmode);
+ }
+
+ g_free(nickmode);
+ g_free(freemsg);
+ g_free(color);
+ g_free(optarget);
+ g_free(prefix);
+}
+
+static void sig_message_own_wall(SERVER_REC *server, const char *msg,
+ const char *target)
+{
+ char *nickmode, *optarget;
+
+ nickmode = channel_get_nickmode(channel_find(server, target),
+ server->nick);
+
+ /* this is always @, skip_prefix is not needed here */
+ optarget = g_strconcat("@", target, NULL);
+ printformat_module("fe-common/core", server, target,
+ MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT |
+ MSGLEVEL_NO_ACT,
+ TXT_OWN_MSG_CHANNEL,
+ server->nick, optarget, msg, nickmode);
+ g_free(nickmode);
+ g_free(optarget);
+}
+
+static void sig_message_own_action(IRC_SERVER_REC *server, const char *msg,
+ const char *target)
+{
+ void *item;
+ const char *oldtarget;
+ char *freemsg = NULL;
+
+ oldtarget = target;
+ target = fe_channel_skip_prefix(IRC_SERVER(server), target);
+ if (server_ischannel(SERVER(server), target))
+ item = channel_find(SERVER(server), target);
+ else
+ item = irc_query_find(server, target);
+
+ if (settings_get_bool("emphasis"))
+ msg = freemsg = expand_emphasis(item, msg);
+
+ printformat(server, target,
+ MSGLEVEL_ACTIONS | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT |
+ (server_ischannel(SERVER(server), target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS),
+ item != NULL && oldtarget == target ? IRCTXT_OWN_ACTION : IRCTXT_OWN_ACTION_TARGET,
+ server->nick, msg, oldtarget);
+ g_free_not_null(freemsg);
+}
+
+static void sig_message_irc_action(IRC_SERVER_REC *server, const char *msg,
+ const char *nick, const char *address,
+ const char *target)
+{
+ void *item;
+ const char *oldtarget;
+ char *freemsg = NULL;
+ int level;
+ int own = FALSE;
+
+ oldtarget = target;
+ target = fe_channel_skip_prefix(IRC_SERVER(server), target);
+
+ level = MSGLEVEL_ACTIONS |
+ (server_ischannel(SERVER(server), target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS);
+
+ if (ignore_check_plus(SERVER(server), nick, address, target, msg, &level, TRUE))
+ return;
+
+ if (server_ischannel(SERVER(server), target)) {
+ item = channel_find(SERVER(server), target);
+ } else {
+ own = (!g_strcmp0(nick, server->nick));
+ item = privmsg_get_query(SERVER(server), own ? target : nick, FALSE, level);
+ }
+
+ if (settings_get_bool("emphasis"))
+ msg = freemsg = expand_emphasis(item, msg);
+
+ if (server_ischannel(SERVER(server), target)) {
+ /* channel action */
+ if (window_item_is_active(item) && target == oldtarget) {
+ /* message to active channel in window */
+ printformat(server, target, level,
+ IRCTXT_ACTION_PUBLIC, nick, msg);
+ } else {
+ /* message to not existing/active channel, or to @/+ */
+ printformat(server, target, level,
+ IRCTXT_ACTION_PUBLIC_CHANNEL,
+ nick, oldtarget, msg);
+ }
+ } else {
+ if (own) {
+ /* own action bounced */
+ printformat(server, target,
+ MSGLEVEL_ACTIONS | MSGLEVEL_MSGS,
+ item != NULL && oldtarget == target ? IRCTXT_OWN_ACTION : IRCTXT_OWN_ACTION_TARGET,
+ server->nick, msg, oldtarget);
+ } else {
+ /* private action */
+ printformat(server, nick, MSGLEVEL_ACTIONS | MSGLEVEL_MSGS,
+ item == NULL ? IRCTXT_ACTION_PRIVATE :
+ IRCTXT_ACTION_PRIVATE_QUERY,
+ nick, address == NULL ? "" : address, msg);
+ }
+ }
+
+ g_free_not_null(freemsg);
+}
+
+static char *notice_channel_context(SERVER_REC *server, const char *msg)
+{
+ if (!settings_get_bool("notice_channel_context"))
+ return NULL;
+
+ if (*msg == '[') {
+ char *end, *channel;
+ end = strpbrk(msg, " ,]");
+ if (end != NULL && *end == ']') {
+ channel = g_strndup(msg + 1, end - msg - 1);
+ if (server_ischannel(server, channel)) {
+ return channel;
+ }
+ g_free(channel);
+ }
+ }
+ return NULL;
+}
+
+static void sig_message_own_notice(IRC_SERVER_REC *server, const char *msg, const char *target)
+{
+ char *channel;
+ /* check if this is a cnotice */
+ channel = notice_channel_context((SERVER_REC *) server, msg);
+ printformat(server, channel != NULL ? channel : fe_channel_skip_prefix(server, target),
+ MSGLEVEL_NOTICES | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, IRCTXT_OWN_NOTICE,
+ target, msg);
+ g_free(channel);
+}
+
+static void sig_message_irc_notice(SERVER_REC *server, const char *msg,
+ const char *nick, const char *address,
+ const char *target)
+{
+ const char *oldtarget;
+ int level = MSGLEVEL_NOTICES;
+
+ oldtarget = target;
+ target = fe_channel_skip_prefix(IRC_SERVER(server), target);
+
+ if (address == NULL || *address == '\0') {
+ level = MSGLEVEL_SNOTES;
+ /* notice from server */
+ if (!ignore_check_plus(server, nick, "",
+ target, msg, &level, TRUE)) {
+ printformat(server, target, level,
+ IRCTXT_NOTICE_SERVER, nick, msg);
+ }
+ return;
+ }
+
+ if (ignore_check_plus(server, nick, address,
+ server_ischannel(SERVER(server), target) ? target : NULL,
+ msg, &level, TRUE))
+ return;
+
+ if (server_ischannel(SERVER(server), target)) {
+ /* notice in some channel */
+ printformat(server, target, level,
+ IRCTXT_NOTICE_PUBLIC, nick, oldtarget, msg);
+ } else {
+ char *channel;
+ /* check if this is a cnotice */
+ channel = notice_channel_context(server, msg);
+
+ if (channel == NULL) {
+ /* private notice */
+ privmsg_get_query(SERVER(server), nick, FALSE, MSGLEVEL_NOTICES);
+ }
+ printformat(server, channel == NULL ? nick : channel, level, IRCTXT_NOTICE_PRIVATE,
+ nick, address, msg);
+
+ g_free(channel);
+ }
+}
+
+static void sig_message_own_ctcp(IRC_SERVER_REC *server, const char *cmd,
+ const char *data, const char *target)
+{
+ printformat(server, fe_channel_skip_prefix(server, target), MSGLEVEL_CTCPS |
+ MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT,
+ IRCTXT_OWN_CTCP, target, cmd, data);
+}
+
+static void sig_message_irc_ctcp(IRC_SERVER_REC *server, const char *cmd,
+ const char *data, const char *nick,
+ const char *addr, const char *target)
+{
+ const char *oldtarget;
+
+ oldtarget = target;
+ target = fe_channel_skip_prefix(server, target);
+ printformat(server, server_ischannel(SERVER(server), target) ? target : nick, MSGLEVEL_CTCPS,
+ IRCTXT_CTCP_REQUESTED, nick, addr, cmd, data, oldtarget);
+}
+
+void fe_irc_messages_init(void)
+{
+ settings_add_bool("misc", "notice_channel_context", TRUE);
+
+ signal_add_last("message own_public", (SIGNAL_FUNC) sig_message_own_public);
+ signal_add_last("message irc op_public", (SIGNAL_FUNC) sig_message_irc_op_public);
+ signal_add_last("message irc own_wall", (SIGNAL_FUNC) sig_message_own_wall);
+ signal_add_last("message irc own_action", (SIGNAL_FUNC) sig_message_own_action);
+ signal_add_last("message irc action", (SIGNAL_FUNC) sig_message_irc_action);
+ signal_add_last("message irc own_notice", (SIGNAL_FUNC) sig_message_own_notice);
+ signal_add_last("message irc notice", (SIGNAL_FUNC) sig_message_irc_notice);
+ signal_add_last("message irc own_ctcp", (SIGNAL_FUNC) sig_message_own_ctcp);
+ signal_add_last("message irc ctcp", (SIGNAL_FUNC) sig_message_irc_ctcp);
+}
+
+void fe_irc_messages_deinit(void)
+{
+ signal_remove("message own_public", (SIGNAL_FUNC) sig_message_own_public);
+ signal_remove("message irc op_public", (SIGNAL_FUNC) sig_message_irc_op_public);
+ signal_remove("message irc own_wall", (SIGNAL_FUNC) sig_message_own_wall);
+ signal_remove("message irc own_action", (SIGNAL_FUNC) sig_message_own_action);
+ signal_remove("message irc action", (SIGNAL_FUNC) sig_message_irc_action);
+ signal_remove("message irc own_notice", (SIGNAL_FUNC) sig_message_own_notice);
+ signal_remove("message irc notice", (SIGNAL_FUNC) sig_message_irc_notice);
+ signal_remove("message irc own_ctcp", (SIGNAL_FUNC) sig_message_own_ctcp);
+ signal_remove("message irc ctcp", (SIGNAL_FUNC) sig_message_irc_ctcp);
+}
diff --git a/src/fe-common/irc/fe-irc-queries.c b/src/fe-common/irc/fe-irc-queries.c
new file mode 100644
index 0000000..7a13542
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-queries.c
@@ -0,0 +1,101 @@
+/*
+ fe-irc-queries.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/settings.h>
+#include <irssi/src/core/servers.h>
+#include <irssi/src/core/queries.h>
+#include <irssi/src/core/nicklist.h>
+
+static QUERY_REC *query_find_address(SERVER_REC *server, const char *address)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(IS_SERVER(server), NULL);
+
+ for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
+ QUERY_REC *rec = tmp->data;
+
+ if (*rec->name != '=' && rec->address != NULL &&
+ g_ascii_strcasecmp(address, rec->address) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static int server_has_nick(SERVER_REC *server, const char *nick)
+{
+ GSList *tmp;
+
+ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+ CHANNEL_REC *channel = tmp->data;
+
+ if (nicklist_find(channel, nick) != NULL)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void event_privmsg(SERVER_REC *server, const char *data,
+ const char *nick, const char *address)
+{
+ QUERY_REC *query;
+
+ g_return_if_fail(data != NULL);
+
+ if (nick == NULL || address == NULL || server_ischannel(server, data) ||
+ !settings_get_bool("query_track_nick_changes"))
+ return;
+
+ query = query_find(server, nick);
+ if (query == NULL) {
+ /* check if there's query with another nick from the same
+ address. it was probably a nick change or reconnect to
+ server, so rename the query. */
+ query = query_find_address(server, address);
+ if (query != NULL) {
+ /* make sure the old nick doesn't exist anymore */
+ if (!server_has_nick(server, query->name))
+ query_change_nick(query, nick);
+ }
+ } else {
+ /* process the changes to the query structure now, before the
+ * privmsg is dispatched. */
+ if (g_strcmp0(query->name, nick) != 0)
+ query_change_nick(query, nick);
+ if (address != NULL && g_strcmp0(query->address, address) != 0)
+ query_change_address(query, address);
+ }
+}
+
+void fe_irc_queries_init(void)
+{
+ settings_add_bool("lookandfeel", "query_track_nick_changes", TRUE);
+
+ signal_add_first("event privmsg", (SIGNAL_FUNC) event_privmsg);
+}
+
+void fe_irc_queries_deinit(void)
+{
+ signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
+}
diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c
new file mode 100644
index 0000000..4aad7ee
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-server.c
@@ -0,0 +1,201 @@
+/*
+ fe-irc-server.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/misc.h>
+
+#include <irssi/src/core/servers-setup.h>
+
+#include <irssi/src/core/levels.h>
+#include <irssi/src/irc/core/irc-chatnets.h>
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/core/servers-reconnect.h>
+#include <irssi/src/irc/core/irc-servers-setup.h>
+
+#include <irssi/src/fe-common/core/fe-windows.h>
+#include <irssi/src/fe-common/core/printtext.h>
+
+const char *get_visible_target(IRC_SERVER_REC *server, const char *target)
+{
+ IRC_CHANNEL_REC *channel;
+
+ if (*target == '!') {
+ /* visible_name of !channels is different - don't bother
+ checking other types for now, they'll just slow up */
+ channel = irc_channel_find(server, target);
+ if (channel != NULL)
+ return channel->visible_name;
+ }
+
+ return target;
+}
+
+/* SYNTAX: SERVER ADD|MODIFY [-4 | -6] [-cap | -nocap] [-tls_cert <cert>] [-tls_pkey <pkey>]
+ [-tls_pass <password>] [-tls_verify] [-tls_cafile <cafile>]
+ [-tls_capath <capath>] [-tls_ciphers <list>] [-tls | -notls]
+ [-starttls | -nostarttls | -disallow_starttls | -nodisallow_starttls]
+ [-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)
+{
+ IRC_CHATNET_REC *ircnet;
+ char *value;
+
+ value = g_hash_table_lookup(optlist, "network");
+ /* For backwards compatibility, also allow the old name 'ircnet'.
+ But of course only if -network was not given. */
+ if (!value)
+ value = g_hash_table_lookup(optlist, "ircnet");
+
+ if (value != NULL) {
+ g_free_and_null(rec->chatnet);
+ if (*value != '\0') {
+ ircnet = ircnet_find(value);
+ rec->chatnet = ircnet != NULL ?
+ g_strdup(ircnet->name) : g_strdup(value);
+ }
+ }
+
+ value = g_hash_table_lookup(optlist, "cmdspeed");
+ if (value != NULL && *value != '\0') rec->cmd_queue_speed = atoi(value);
+ value = g_hash_table_lookup(optlist, "cmdmax");
+ if (value != NULL && *value != '\0') rec->max_cmds_at_once = atoi(value);
+ value = g_hash_table_lookup(optlist, "querychans");
+ if (value != NULL && *value != '\0') rec->max_query_chans = atoi(value);
+ if (g_hash_table_lookup(optlist, "nodisallow_starttls") ||
+ g_hash_table_lookup(optlist, "nostarttls"))
+ rec->starttls = STARTTLS_NOTSET;
+ if (g_hash_table_lookup(optlist, "disallow_starttls"))
+ rec->starttls = STARTTLS_DISALLOW;
+ if (g_hash_table_lookup(optlist, "starttls")) {
+ rec->starttls = STARTTLS_ENABLED;
+ rec->use_tls = 0;
+ }
+ if (g_hash_table_lookup(optlist, "nocap"))
+ rec->no_cap = 1;
+ if (g_hash_table_lookup(optlist, "cap"))
+ rec->no_cap = 0;
+}
+
+static void sig_server_waiting_info(IRC_SERVER_REC *server, const char *version)
+{
+ if (!IS_IRC_SERVER(server))
+ return;
+
+ printformat(server, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SERVER_WAITING_CAP_LS, server,
+ version);
+}
+
+/* SYNTAX: SERVER LIST */
+static void cmd_server_list(const char *data)
+{
+ GString *str;
+ GSList *tmp;
+
+ str = g_string_new(NULL);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_HEADER);
+ for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
+ IRC_SERVER_SETUP_REC *rec = tmp->data;
+
+ if (!IS_IRC_SERVER_SETUP(rec))
+ continue;
+
+ g_string_truncate(str, 0);
+ if (rec->password != NULL)
+ g_string_append(str, "(pass), ");
+ if (rec->autoconnect)
+ g_string_append(str, "autoconnect, ");
+ if (rec->no_proxy)
+ g_string_append(str, "noproxy, ");
+ if (rec->no_cap)
+ g_string_append(str, "nocap, ");
+ if (rec->starttls == STARTTLS_DISALLOW)
+ g_string_append(str, "disallow_starttls, ");
+ if (rec->starttls == STARTTLS_ENABLED)
+ g_string_append(str, "starttls, ");
+ if (rec->use_tls)
+ g_string_append(str, "tls, ");
+ if (rec->tls_cert) {
+ g_string_append_printf(str, "tls_cert: %s, ", rec->tls_cert);
+ if (rec->tls_pkey)
+ g_string_append_printf(str, "tls_pkey: %s, ", rec->tls_pkey);
+ if (rec->tls_pass)
+ g_string_append_printf(str, "(pass), ");
+ }
+ if (!rec->tls_verify)
+ g_string_append(str, "notls_verify, ");
+ if (rec->tls_cafile)
+ g_string_append_printf(str, "tls_cafile: %s, ", rec->tls_cafile);
+ if (rec->tls_capath)
+ g_string_append_printf(str, "tls_capath: %s, ", rec->tls_capath);
+ if (rec->tls_ciphers)
+ g_string_append_printf(str, "tls_ciphers: %s, ", rec->tls_ciphers);
+ if (rec->tls_pinned_cert)
+ g_string_append_printf(str, "tls_pinned_cert: %s, ", rec->tls_pinned_cert);
+ if (rec->tls_pinned_pubkey)
+ g_string_append_printf(str, "tls_pinned_pubkey: %s, ",
+ rec->tls_pinned_pubkey);
+
+ if (rec->max_cmds_at_once > 0)
+ g_string_append_printf(str, "cmdmax: %d, ", rec->max_cmds_at_once);
+ if (rec->cmd_queue_speed > 0)
+ g_string_append_printf(str, "cmdspeed: %d, ", rec->cmd_queue_speed);
+ if (rec->max_query_chans > 0)
+ g_string_append_printf(str, "querychans: %d, ", rec->max_query_chans);
+ if (rec->own_host != NULL)
+ g_string_append_printf(str, "host: %s, ", rec->own_host);
+
+ if (str->len > 1) g_string_truncate(str, str->len-2);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_LINE,
+ rec->address, rec->port,
+ rec->chatnet == NULL ? "" : rec->chatnet,
+ str->str);
+ }
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_FOOTER);
+ g_string_free(str, TRUE);
+}
+
+void fe_irc_server_init(void)
+{
+ signal_add("server add fill", (SIGNAL_FUNC) sig_server_add_fill);
+ signal_add("server waiting cap ls", (SIGNAL_FUNC) sig_server_waiting_info);
+ command_bind("server list", NULL, (SIGNAL_FUNC) cmd_server_list);
+
+ command_set_options("server add",
+ "-ircnet -network -cmdspeed -cmdmax -querychans starttls "
+ "nostarttls disallow_starttls nodisallow_starttls cap nocap");
+ command_set_options("server modify",
+ "-ircnet -network -cmdspeed -cmdmax -querychans starttls nostarttls "
+ "disallow_starttls nodisallow_starttls cap nocap");
+}
+
+void fe_irc_server_deinit(void)
+{
+ signal_remove("server add fill", (SIGNAL_FUNC) sig_server_add_fill);
+ signal_remove("server waiting cap ls", (SIGNAL_FUNC) sig_server_waiting_info);
+ command_unbind("server list", (SIGNAL_FUNC) cmd_server_list);
+}
diff --git a/src/fe-common/irc/fe-irc-server.h b/src/fe-common/irc/fe-irc-server.h
new file mode 100644
index 0000000..28a709e
--- /dev/null
+++ b/src/fe-common/irc/fe-irc-server.h
@@ -0,0 +1,9 @@
+#ifndef IRSSI_FE_COMMON_IRC_FE_IRC_SERVER_H
+#define IRSSI_FE_COMMON_IRC_FE_IRC_SERVER_H
+
+const char *get_visible_target(IRC_SERVER_REC *server, const char *target);
+
+void fe_irc_server_init(void);
+void fe_irc_server_deinit(void);
+
+#endif
diff --git a/src/fe-common/irc/fe-ircnet.c b/src/fe-common/irc/fe-ircnet.c
new file mode 100644
index 0000000..3484d92
--- /dev/null
+++ b/src/fe-common/irc/fe-ircnet.c
@@ -0,0 +1,249 @@
+/*
+ fe-ircnet.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/chatnets.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-chatnets.h>
+#include <irssi/src/fe-common/core/printtext.h>
+#include <irssi/src/core/servers-setup.h>
+#include <irssi/src/core/channels-setup.h>
+
+static void cmd_network_list(void)
+{
+ GString *str;
+ GSList *tmp;
+
+ str = g_string_new(NULL);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETWORK_HEADER);
+ for (tmp = chatnets; tmp != NULL; tmp = tmp->next) {
+ IRC_CHATNET_REC *rec = tmp->data;
+
+ if (!IS_IRCNET(rec))
+ continue;
+
+ g_string_truncate(str, 0);
+ if (rec->nick != NULL)
+ g_string_append_printf(str, "nick: %s, ", rec->nick);
+ if (rec->alternate_nick != NULL)
+ g_string_append_printf(str, "alternate_nick: %s, ", rec->alternate_nick);
+ if (rec->username != NULL)
+ g_string_append_printf(str, "username: %s, ", rec->username);
+ if (rec->realname != NULL)
+ g_string_append_printf(str, "realname: %s, ", rec->realname);
+ if (rec->own_host != NULL)
+ g_string_append_printf(str, "host: %s, ", rec->own_host);
+ if (rec->autosendcmd != NULL)
+ g_string_append_printf(str, "autosendcmd: %s, ", rec->autosendcmd);
+ if (rec->usermode != NULL)
+ g_string_append_printf(str, "usermode: %s, ", rec->usermode);
+ if (rec->sasl_mechanism != NULL)
+ g_string_append_printf(str, "sasl_mechanism: %s, ", rec->sasl_mechanism);
+ if (rec->sasl_username != NULL)
+ g_string_append_printf(str, "sasl_username: %s, ", rec->sasl_username);
+ if (rec->sasl_password != NULL)
+ g_string_append_printf(str, "sasl_password: (pass), ");
+ if (rec->cmd_queue_speed > 0)
+ g_string_append_printf(str, "cmdspeed: %d, ", rec->cmd_queue_speed);
+ if (rec->max_cmds_at_once > 0)
+ g_string_append_printf(str, "cmdmax: %d, ", rec->max_cmds_at_once);
+ if (rec->max_query_chans > 0)
+ g_string_append_printf(str, "querychans: %d, ", rec->max_query_chans);
+
+ if (rec->max_kicks > 0)
+ g_string_append_printf(str, "max_kicks: %d, ", rec->max_kicks);
+ if (rec->max_msgs > 0)
+ g_string_append_printf(str, "max_msgs: %d, ", rec->max_msgs);
+ if (rec->max_modes > 0)
+ g_string_append_printf(str, "max_modes: %d, ", rec->max_modes);
+ if (rec->max_whois > 0)
+ g_string_append_printf(str, "max_whois: %d, ", rec->max_whois);
+
+ if (str->len > 1) g_string_truncate(str, str->len-2);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ IRCTXT_NETWORK_LINE, rec->name, str->str);
+ }
+ g_string_free(str, TRUE);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETWORK_FOOTER);
+}
+
+static void cmd_network_add_modify(const char *data, gboolean add)
+{
+ GHashTable *optlist;
+ char *name, *value;
+ void *free_arg;
+ IRC_CHATNET_REC *rec;
+
+ if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
+ "network add", &optlist, &name))
+ return;
+
+ if (*name == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ rec = ircnet_find(name);
+ if (rec == NULL) {
+ if (add == FALSE) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NETWORK_NOT_FOUND, name);
+ cmd_params_free(free_arg);
+ return;
+ }
+
+ rec = g_new0(IRC_CHATNET_REC, 1);
+ rec->name = g_strdup(name);
+ } else {
+ if (g_hash_table_lookup(optlist, "nick")) g_free_and_null(rec->nick);
+ if (g_hash_table_lookup(optlist, "alternate_nick")) g_free_and_null(rec->alternate_nick);
+ if (g_hash_table_lookup(optlist, "user")) g_free_and_null(rec->username);
+ if (g_hash_table_lookup(optlist, "realname")) g_free_and_null(rec->realname);
+ if (g_hash_table_lookup(optlist, "host")) {
+ g_free_and_null(rec->own_host);
+ rec->own_ip4 = rec->own_ip6 = NULL;
+ }
+ if (g_hash_table_lookup(optlist, "usermode")) g_free_and_null(rec->usermode);
+ if (g_hash_table_lookup(optlist, "autosendcmd")) g_free_and_null(rec->autosendcmd);
+ if (g_hash_table_lookup(optlist, "sasl_mechanism")) g_free_and_null(rec->sasl_mechanism);
+ if (g_hash_table_lookup(optlist, "sasl_username")) g_free_and_null(rec->sasl_username);
+ if (g_hash_table_lookup(optlist, "sasl_password")) g_free_and_null(rec->sasl_password);
+ }
+
+ value = g_hash_table_lookup(optlist, "kicks");
+ if (value != NULL) rec->max_kicks = atoi(value);
+ value = g_hash_table_lookup(optlist, "msgs");
+ if (value != NULL) rec->max_msgs = atoi(value);
+ value = g_hash_table_lookup(optlist, "modes");
+ if (value != NULL) rec->max_modes = atoi(value);
+ value = g_hash_table_lookup(optlist, "whois");
+ if (value != NULL) rec->max_whois = atoi(value);
+
+ value = g_hash_table_lookup(optlist, "cmdspeed");
+ if (value != NULL) rec->cmd_queue_speed = atoi(value);
+ value = g_hash_table_lookup(optlist, "cmdmax");
+ if (value != NULL) rec->max_cmds_at_once = atoi(value);
+ value = g_hash_table_lookup(optlist, "querychans");
+ if (value != NULL) rec->max_query_chans = atoi(value);
+
+ value = g_hash_table_lookup(optlist, "nick");
+ if (value != NULL && *value != '\0') rec->nick = g_strdup(value);
+ value = g_hash_table_lookup(optlist, "alternate_nick");
+ if (value != NULL && *value != '\0') rec->alternate_nick = g_strdup(value);
+ value = g_hash_table_lookup(optlist, "user");
+ if (value != NULL && *value != '\0') rec->username = g_strdup(value);
+ value = g_hash_table_lookup(optlist, "realname");
+ if (value != NULL && *value != '\0') rec->realname = g_strdup(value);
+
+ value = g_hash_table_lookup(optlist, "host");
+ if (value != NULL && *value != '\0') {
+ rec->own_host = g_strdup(value);
+ rec->own_ip4 = rec->own_ip6 = NULL;
+ }
+
+ value = g_hash_table_lookup(optlist, "usermode");
+ if (value != NULL && *value != '\0') rec->usermode = g_strdup(value);
+ value = g_hash_table_lookup(optlist, "autosendcmd");
+ if (value != NULL && *value != '\0') rec->autosendcmd = g_strdup(value);
+
+ /* the validity of the parameters is checked in sig_server_setup_fill_chatnet */
+ value = g_hash_table_lookup(optlist, "sasl_mechanism");
+ if (value != NULL) rec->sasl_mechanism = *value != '\0' ? g_strdup(value) : NULL;
+ value = g_hash_table_lookup(optlist, "sasl_username");
+ if (value != NULL) rec->sasl_username = *value != '\0' ? g_strdup(value) : NULL;
+ value = g_hash_table_lookup(optlist, "sasl_password");
+ if (value != NULL) rec->sasl_password = *value != '\0' ? g_strdup(value) : NULL;
+
+ ircnet_create(rec);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NETWORK_ADDED, name);
+
+ cmd_params_free(free_arg);
+}
+
+/* SYNTAX: NETWORK ADD|MODIFY [-nick <nick>] [-alternate_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)
+{
+ IRC_CHATNET_REC *rec;
+
+ if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
+
+ rec = ircnet_find(data);
+ if (rec == NULL)
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NETWORK_NOT_FOUND, data);
+ else {
+ server_setup_remove_chatnet(data);
+ channel_setup_remove_chatnet(data);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NETWORK_REMOVED, data);
+ chatnet_remove(CHATNET(rec));
+ }
+}
+
+static void cmd_network(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
+{
+ if (*data == '\0')
+ cmd_network_list();
+ else
+ command_runsub("network", data, server, item);
+}
+
+void fe_ircnet_init(void)
+{
+ command_bind("ircnet", NULL, (SIGNAL_FUNC) cmd_network);
+ 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 -alternate_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 -alternate_nick -user -realname -host -autosendcmd -querychans -usermode -sasl_mechanism -sasl_username -sasl_password");
+}
+
+void fe_ircnet_deinit(void)
+{
+ command_unbind("ircnet", (SIGNAL_FUNC) cmd_network);
+ 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-common/irc/fe-modes.c b/src/fe-common/irc/fe-modes.c
new file mode 100644
index 0000000..623fca0
--- /dev/null
+++ b/src/fe-common/irc/fe-modes.c
@@ -0,0 +1,236 @@
+/*
+ fe-modes.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-channels.h>
+#include <irssi/src/irc/core/modes.h>
+#include <irssi/src/core/ignore.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+
+#define MODE_WAIT_TIME 3 /* how many seconds to wait for identical modes */
+
+typedef struct {
+ IRC_CHANNEL_REC *channel;
+ int level;
+ char *mode;
+ GSList *nicks;
+ time_t last_mode;
+} MODE_REC;
+
+static int mode_tag, group_multi_mode;
+static GSList *modes;
+
+static MODE_REC *mode_find_channel(IRC_CHANNEL_REC *channel)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(channel != NULL, NULL);
+
+ for (tmp = modes; tmp != NULL; tmp = tmp->next) {
+ MODE_REC *rec = tmp->data;
+
+ if (rec->channel == channel)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static void mode_destroy(MODE_REC *mode)
+{
+ g_return_if_fail(mode != NULL);
+
+ modes = g_slist_remove(modes, mode);
+ g_slist_foreach(mode->nicks, (GFunc) g_free, NULL);
+ g_slist_free(mode->nicks);
+ g_free(mode->mode);
+ g_free(mode);
+}
+
+static void print_mode(MODE_REC *rec)
+{
+ GSList *tmp;
+ char *nicks;
+
+ if (g_slist_find(channels, rec->channel) == NULL) {
+ /* channel was destroyed while we were waiting.. */
+ return;
+ }
+
+ tmp = modes; modes = NULL;
+
+ nicks = i_slist_to_string(rec->nicks, ", ");
+ printformat(rec->channel->server, rec->channel->visible_name, rec->level,
+ IRCTXT_CHANMODE_CHANGE, rec->channel->visible_name, rec->mode, nicks, "");
+ g_free(nicks);
+
+ modes = tmp;
+}
+
+/* something is going to be printed to screen, print our current netsplit
+ message before it. */
+static void sig_print_starting(void)
+{
+ while (modes != NULL) {
+ print_mode(modes->data);
+ mode_destroy(modes->data);
+ }
+
+ signal_remove("print starting", sig_print_starting);
+}
+
+static int sig_check_modes(void)
+{
+ GSList *tmp, *next;
+
+ if (modes == NULL)
+ return 1;
+
+ for (tmp = modes; tmp != NULL; tmp = next) {
+ MODE_REC *rec = tmp->data;
+
+ next = tmp->next;
+ if (time(NULL)-rec->last_mode >= MODE_WAIT_TIME) {
+ print_mode(rec);
+ mode_destroy(rec);
+ }
+ }
+
+ if (modes == NULL)
+ signal_remove("print starting", (SIGNAL_FUNC) sig_print_starting);
+ return 1;
+}
+
+static void msg_multi_mode(IRC_CHANNEL_REC *channel, int level, const char *sender,
+ const char *addr, const char *mode)
+{
+ MODE_REC *rec;
+
+ if (modes == NULL)
+ signal_add("print starting", (SIGNAL_FUNC) sig_print_starting);
+
+ rec = mode_find_channel(channel);
+ if (rec != NULL && g_strcmp0(rec->mode, mode) != 0) {
+ /* different mode than last time, show and remove the old */
+ print_mode(rec);
+ mode_destroy(rec);
+ rec = NULL;
+ }
+
+ if (rec == NULL) {
+ /* no previous mode, create new */
+ rec = g_new0(MODE_REC, 1);
+ modes = g_slist_append(modes, rec);
+
+ rec->level = level;
+ rec->channel = channel;
+ rec->mode = g_strdup(mode);
+ }
+ /* the levels (everything below MSGLEVEL_ALL) are combined (|)
+ whereas the flags (anything above) must all match (&) */
+ rec->level = ((rec->level | level) & MSGLEVEL_ALL) | (rec->level & level);
+ rec->nicks = g_slist_append(rec->nicks, g_strdup(sender));
+ rec->last_mode = time(NULL);
+
+ signal_stop();
+}
+
+/* FIXME: should be moved to fe-irc-messages.c.. */
+static void sig_message_mode(IRC_SERVER_REC *server, const char *channel,
+ const char *nick, const char *addr,
+ const char *mode)
+{
+ int level = MSGLEVEL_MODES;
+
+ if (nick == NULL) nick = server->real_address;
+
+ if (ignore_check_plus(SERVER(server), nick, addr, channel,
+ mode, &level, TRUE))
+ return;
+
+ if (!server_ischannel(SERVER(server), channel)) {
+ /* user mode change */
+ printformat(server, NULL, level,
+ IRCTXT_USERMODE_CHANGE, mode, channel);
+ } else if (addr == NULL) {
+ /* channel mode changed by server */
+ printformat(server, channel, level,
+ IRCTXT_SERVER_CHANMODE_CHANGE,
+ channel, mode, nick);
+ } else {
+ /* channel mode changed by normal user */
+ IRC_CHANNEL_REC *chanrec;
+
+ chanrec = !group_multi_mode ? NULL :
+ irc_channel_find(server, channel);
+
+ if (chanrec != NULL && g_ascii_strcasecmp(nick, server->nick) != 0)
+ msg_multi_mode(chanrec, level, nick, addr, mode);
+ else {
+ printformat(server, channel, level,
+ IRCTXT_CHANMODE_CHANGE,
+ channel, mode, nick, addr);
+ }
+ }
+}
+
+static void read_settings(void)
+{
+ int old_group;
+
+ old_group = group_multi_mode;
+ group_multi_mode = settings_get_bool("group_multi_mode");
+
+ if (old_group && !group_multi_mode) {
+ g_source_remove(mode_tag);
+ mode_tag = -1;
+ } else if (!old_group && group_multi_mode) {
+ mode_tag = g_timeout_add(1000, (GSourceFunc) sig_check_modes, NULL);
+ }
+}
+
+void fe_modes_init(void)
+{
+ settings_add_bool("misc", "group_multi_mode", TRUE);
+ mode_tag = -1;
+
+ read_settings();
+ signal_add("message irc mode", (SIGNAL_FUNC) sig_message_mode);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+}
+
+void fe_modes_deinit(void)
+{
+ if (mode_tag != -1)
+ g_source_remove(mode_tag);
+
+ signal_remove("message irc mode", (SIGNAL_FUNC) sig_message_mode);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+
+ signal_remove("print starting", (SIGNAL_FUNC) sig_print_starting);
+}
diff --git a/src/fe-common/irc/fe-netjoin.c b/src/fe-common/irc/fe-netjoin.c
new file mode 100644
index 0000000..ea41f7f
--- /dev/null
+++ b/src/fe-common/irc/fe-netjoin.c
@@ -0,0 +1,515 @@
+/*
+ fe-netjoin.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/modes.h>
+#include <irssi/src/core/ignore.h>
+#include <irssi/src/irc/core/netsplit.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+
+#define NETJOIN_WAIT_TIME 5 /* how many seconds to wait for the netsplitted JOIN messages to stop */
+#define NETJOIN_MAX_WAIT 30 /* how many seconds to wait for nick to join to the rest of the channels she was before the netsplit */
+
+typedef struct {
+ char *nick;
+ GSList *old_channels;
+ GSList *now_channels;
+} NETJOIN_REC;
+
+typedef struct {
+ IRC_SERVER_REC *server;
+ time_t last_netjoin;
+
+ GSList *netjoins;
+} NETJOIN_SERVER_REC;
+
+typedef struct {
+ int count;
+ GString *nicks;
+} TEMP_PRINT_REC;
+
+static int join_tag;
+static int netjoin_max_nicks, hide_netsplit_quits;
+static int printing_joins;
+static GSList *joinservers;
+
+static NETJOIN_SERVER_REC *netjoin_find_server(IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+
+ g_return_val_if_fail(server != NULL, NULL);
+
+ for (tmp = joinservers; tmp != NULL; tmp = tmp->next) {
+ NETJOIN_SERVER_REC *rec = tmp->data;
+
+ if (rec->server == server)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static NETJOIN_REC *netjoin_add(IRC_SERVER_REC *server, const char *nick,
+ GSList *channels)
+{
+ NETJOIN_REC *rec;
+ NETJOIN_SERVER_REC *srec;
+
+ g_return_val_if_fail(server != NULL, NULL);
+ g_return_val_if_fail(nick != NULL, NULL);
+
+ rec = g_new0(NETJOIN_REC, 1);
+ rec->nick = g_strdup(nick);
+ while (channels != NULL) {
+ NETSPLIT_CHAN_REC *channel = channels->data;
+
+ rec->old_channels = g_slist_append(rec->old_channels,
+ g_strdup(channel->name));
+ channels = channels->next;
+ }
+
+ srec = netjoin_find_server(server);
+ if (srec == NULL) {
+ srec = g_new0(NETJOIN_SERVER_REC, 1);
+ srec->server = server;
+ joinservers = g_slist_append(joinservers, srec);
+ }
+
+ srec->last_netjoin = time(NULL);
+ srec->netjoins = g_slist_append(srec->netjoins, rec);
+ return rec;
+}
+
+static NETJOIN_REC *netjoin_find(IRC_SERVER_REC *server, const char *nick)
+{
+ NETJOIN_SERVER_REC *srec;
+ GSList *tmp;
+
+ g_return_val_if_fail(server != NULL, NULL);
+ g_return_val_if_fail(nick != NULL, NULL);
+
+ srec = netjoin_find_server(server);
+ if (srec == NULL) return NULL;
+
+ for (tmp = srec->netjoins; tmp != NULL; tmp = tmp->next) {
+ NETJOIN_REC *rec = tmp->data;
+
+ if (g_ascii_strcasecmp(rec->nick, nick) == 0)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static void netjoin_remove(NETJOIN_SERVER_REC *server, NETJOIN_REC *rec)
+{
+ server->netjoins = g_slist_remove(server->netjoins, rec);
+
+ g_slist_foreach(rec->old_channels, (GFunc) g_free, NULL);
+ g_slist_foreach(rec->now_channels, (GFunc) g_free, NULL);
+ g_slist_free(rec->old_channels);
+ g_slist_free(rec->now_channels);
+
+ g_free(rec->nick);
+ g_free(rec);
+}
+
+static void netjoin_server_remove(NETJOIN_SERVER_REC *server)
+{
+ joinservers = g_slist_remove(joinservers, server);
+
+ while (server->netjoins != NULL)
+ netjoin_remove(server, server->netjoins->data);
+ g_free(server);
+}
+
+static void print_channel_netjoins(char *channel, TEMP_PRINT_REC *rec,
+ NETJOIN_SERVER_REC *server)
+{
+ if (rec->nicks->len > 0)
+ g_string_truncate(rec->nicks, rec->nicks->len-2);
+
+ printformat(server->server, channel, MSGLEVEL_JOINS,
+ rec->count > netjoin_max_nicks ?
+ IRCTXT_NETSPLIT_JOIN_MORE : IRCTXT_NETSPLIT_JOIN,
+ rec->nicks->str, rec->count-netjoin_max_nicks);
+
+ g_string_free(rec->nicks, TRUE);
+ g_free(rec);
+ g_free(channel);
+}
+
+static void print_netjoins(NETJOIN_SERVER_REC *server, const char *filter_channel)
+{
+ TEMP_PRINT_REC *temp;
+ GHashTable *channels;
+ GSList *tmp, *tmp2, *next, *next2, *old;
+
+ g_return_if_fail(server != NULL);
+
+ printing_joins = TRUE;
+
+ /* save nicks to string, clear now_channels and remove the same
+ channels from old_channels list */
+ channels = g_hash_table_new((GHashFunc) i_istr_hash, (GCompareFunc) i_istr_equal);
+ for (tmp = server->netjoins; tmp != NULL; tmp = next) {
+ NETJOIN_REC *rec = tmp->data;
+
+ next = g_slist_next(tmp);
+
+ for (tmp2 = rec->now_channels; tmp2 != NULL; tmp2 = next2) {
+ char *channel = tmp2->data;
+ char *realchannel = channel + 1;
+
+ next2 = g_slist_next(tmp2);
+
+ /* Filter the results by channel if asked to do so */
+ if (filter_channel != NULL &&
+ strcasecmp(realchannel, filter_channel) != 0)
+ continue;
+
+ temp = g_hash_table_lookup(channels, realchannel);
+ if (temp == NULL) {
+ temp = g_new0(TEMP_PRINT_REC, 1);
+ temp->nicks = g_string_new(NULL);
+ g_hash_table_insert(channels,
+ g_strdup(realchannel),
+ temp);
+ }
+
+ temp->count++;
+ if (temp->count <= netjoin_max_nicks) {
+ if (*channel != ' ')
+ g_string_append_c(temp->nicks,
+ *channel);
+ g_string_append_printf(temp->nicks, "%s, ",
+ rec->nick);
+ }
+
+ /* remove the channel from old_channels too */
+ old = i_slist_find_icase_string(rec->old_channels, realchannel);
+ if (old != NULL) {
+ void *data = old->data;
+ rec->old_channels =
+ g_slist_remove(rec->old_channels, data);
+ g_free(data);
+ }
+
+ /* drop tmp2 from the list */
+ rec->now_channels = g_slist_delete_link(rec->now_channels, tmp2);
+ g_free(channel);
+ }
+
+ if (rec->old_channels == NULL)
+ netjoin_remove(server, rec);
+ }
+
+ g_hash_table_foreach(channels, (GHFunc) print_channel_netjoins,
+ server);
+ g_hash_table_destroy(channels);
+
+ if (server->netjoins == NULL)
+ netjoin_server_remove(server);
+
+ printing_joins = FALSE;
+}
+
+/* something is going to be printed to screen, print our current netsplit
+ message before it. */
+static void sig_print_starting(TEXT_DEST_REC *dest)
+{
+ NETJOIN_SERVER_REC *rec;
+
+ if (printing_joins)
+ return;
+
+ if (!IS_IRC_SERVER(dest->server))
+ return;
+
+ rec = netjoin_find_server(IRC_SERVER(dest->server));
+ if (rec != NULL && rec->netjoins != NULL) {
+ /* if netjoins exists, the server rec should be
+ still valid. otherwise, calling server->ischannel
+ may not be safe. */
+ if (dest->target != NULL &&
+ !server_ischannel((SERVER_REC *) rec->server, dest->target))
+ return;
+
+ print_netjoins(rec, NULL);
+ }
+}
+
+static int sig_check_netjoins(void)
+{
+ GSList *tmp, *next;
+ int diff;
+ time_t now;
+
+ now = time(NULL);
+ /* first print all netjoins which haven't had any new joins
+ * for NETJOIN_WAIT_TIME; this may cause them to be removed
+ * (all users who rejoined, rejoined all channels) */
+ for (tmp = joinservers; tmp != NULL; tmp = next) {
+ NETJOIN_SERVER_REC *server = tmp->data;
+
+ next = tmp->next;
+ diff = now-server->last_netjoin;
+ if (diff <= NETJOIN_WAIT_TIME) {
+ /* wait for more JOINs */
+ continue;
+ }
+
+ if (server->netjoins != NULL)
+ print_netjoins(server, NULL);
+ }
+
+ /* now remove all netjoins which haven't had any new joins
+ * for NETJOIN_MAX_WAIT (user rejoined some but not all channels
+ * after split) */
+ for (tmp = joinservers; tmp != NULL; tmp = next) {
+ NETJOIN_SERVER_REC *server = tmp->data;
+
+ next = tmp->next;
+ diff = now-server->last_netjoin;
+ if (diff >= NETJOIN_MAX_WAIT) {
+ /* waited long enough, forget about the rest */
+ netjoin_server_remove(server);
+ }
+ }
+
+ if (joinservers == NULL) {
+ g_source_remove(join_tag);
+ signal_remove("print starting", (SIGNAL_FUNC) sig_print_starting);
+ join_tag = -1;
+ }
+ return 1;
+}
+
+static void msg_quit(IRC_SERVER_REC *server, const char *nick,
+ const char *address, const char *reason)
+{
+ if (IS_IRC_SERVER(server) && quitmsg_is_split(reason))
+ signal_stop();
+}
+
+static void msg_join(IRC_SERVER_REC *server, const char *channel,
+ const char *nick, const char *address)
+{
+ NETSPLIT_REC *split;
+ NETJOIN_REC *netjoin;
+ GSList *channels;
+ int rejoin = 1;
+
+ if (!IS_IRC_SERVER(server))
+ return;
+
+ if (ignore_check(SERVER(server), nick, address,
+ channel, NULL, MSGLEVEL_JOINS))
+ return;
+
+ split = netsplit_find(server, nick, address);
+ netjoin = netjoin_find(server, nick);
+ if (split == NULL && netjoin == NULL)
+ return;
+
+ /* if this was not a channel they split from, treat it normally */
+ if (netjoin != NULL) {
+ if (!i_slist_find_icase_string(netjoin->old_channels, channel))
+ return;
+ } else {
+ channels = split->channels;
+ while (channels != NULL) {
+ NETSPLIT_CHAN_REC *schannel = channels->data;
+
+ if (!strcasecmp(schannel->name, channel))
+ break;
+ channels = channels->next;
+ }
+ /* we still need to create a NETJOIN_REC now as the
+ * NETSPLIT_REC will be destroyed */
+ if (channels == NULL)
+ rejoin = 0;
+ }
+
+ if (join_tag == -1) {
+ join_tag = g_timeout_add(1000, (GSourceFunc)
+ sig_check_netjoins, NULL);
+ signal_add("print starting", (SIGNAL_FUNC) sig_print_starting);
+ }
+
+ if (netjoin == NULL)
+ netjoin = netjoin_add(server, nick, split->channels);
+
+ if (rejoin)
+ {
+ netjoin->now_channels = g_slist_append(netjoin->now_channels,
+ g_strconcat(" ", channel, NULL));
+ signal_stop();
+ }
+}
+
+static int netjoin_set_nickmode(IRC_SERVER_REC *server, NETJOIN_REC *rec,
+ const char *channel, char prefix)
+{
+ GSList *pos;
+ const char *flags;
+ char *found_chan = NULL;
+
+ for (pos = rec->now_channels; pos != NULL; pos = pos->next) {
+ char *chan = pos->data;
+ if (strcasecmp(chan+1, channel) == 0) {
+ found_chan = chan;
+ break;
+ }
+ }
+
+ if (found_chan == NULL)
+ return FALSE;
+
+ flags = server->get_nick_flags(SERVER(server));
+ while (*flags != '\0') {
+ if (found_chan[0] == *flags)
+ break;
+ if (prefix == *flags) {
+ found_chan[0] = prefix;
+ break;
+ }
+ flags++;
+ }
+ return TRUE;
+}
+
+static void msg_mode(IRC_SERVER_REC *server, const char *channel,
+ const char *sender, const char *addr, const char *data)
+{
+ NETJOIN_REC *rec;
+ char *params, *mode, *nicks;
+ char **nicklist, **nick, type, prefix;
+ int show;
+
+ g_return_if_fail(data != NULL);
+ if (!server_ischannel(SERVER(server), channel) || addr != NULL)
+ return;
+
+ params = event_get_params(data, 2 | PARAM_FLAG_GETREST,
+ &mode, &nicks);
+
+ /* parse server mode changes - hide operator status changes and
+ show them in the netjoin message instead as @ before the nick */
+ nick = nicklist = g_strsplit(nicks, " ", -1);
+
+ type = '+'; show = FALSE;
+ for (; *mode != '\0'; mode++) {
+ if (*mode == '+' || *mode == '-') {
+ type = *mode;
+ continue;
+ }
+
+ if (*nick != NULL && GET_MODE_PREFIX(server, *mode)) {
+ /* give/remove ops */
+ rec = netjoin_find(server, *nick);
+ prefix = GET_MODE_PREFIX(server, *mode);
+ if (rec == NULL || type != '+' || prefix == '\0' ||
+ !netjoin_set_nickmode(server, rec, channel, prefix))
+ show = TRUE;
+ nick++;
+ } else {
+ if (HAS_MODE_ARG(server, type, *mode) && *nick != NULL)
+ nick++;
+ show = TRUE;
+ }
+ }
+
+ if (!show) signal_stop();
+
+ g_strfreev(nicklist);
+ g_free(params);
+}
+
+static void read_settings(void)
+{
+ int old_hide;
+
+ old_hide = hide_netsplit_quits;
+ hide_netsplit_quits = settings_get_bool("hide_netsplit_quits");
+ netjoin_max_nicks = settings_get_int("netjoin_max_nicks");
+
+ if (old_hide && !hide_netsplit_quits) {
+ signal_remove("message quit", (SIGNAL_FUNC) msg_quit);
+ signal_remove("message join", (SIGNAL_FUNC) msg_join);
+ signal_remove("message irc mode", (SIGNAL_FUNC) msg_mode);
+ } else if (!old_hide && hide_netsplit_quits) {
+ signal_add("message quit", (SIGNAL_FUNC) msg_quit);
+ signal_add("message join", (SIGNAL_FUNC) msg_join);
+ signal_add("message irc mode", (SIGNAL_FUNC) msg_mode);
+ }
+}
+
+static void sig_server_disconnected(IRC_SERVER_REC *server)
+{
+ NETJOIN_SERVER_REC *netjoin_server;
+
+ g_return_if_fail(server != NULL);
+
+ if (!IS_IRC_SERVER(server))
+ return;
+
+ if ((netjoin_server = netjoin_find_server(server))) {
+ netjoin_server_remove(netjoin_server);
+ }
+}
+
+void fe_netjoin_init(void)
+{
+ settings_add_bool("misc", "hide_netsplit_quits", TRUE);
+ settings_add_int("misc", "netjoin_max_nicks", 10);
+
+ join_tag = -1;
+ printing_joins = FALSE;
+
+ read_settings();
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+ signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
+}
+
+void fe_netjoin_deinit(void)
+{
+ while (joinservers != NULL)
+ netjoin_server_remove(joinservers->data);
+ if (join_tag != -1) {
+ g_source_remove(join_tag);
+ signal_remove("print starting", (SIGNAL_FUNC) sig_print_starting);
+ }
+
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+ signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
+
+ signal_remove("message quit", (SIGNAL_FUNC) msg_quit);
+ signal_remove("message join", (SIGNAL_FUNC) msg_join);
+ signal_remove("message irc mode", (SIGNAL_FUNC) msg_mode);
+}
diff --git a/src/fe-common/irc/fe-netsplit.c b/src/fe-common/irc/fe-netsplit.c
new file mode 100644
index 0000000..b76d4ce
--- /dev/null
+++ b/src/fe-common/irc/fe-netsplit.c
@@ -0,0 +1,389 @@
+/*
+ fe-netsplit.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-commands.h>
+#include <irssi/src/core/ignore.h>
+#include <irssi/src/irc/core/netsplit.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+
+#define SPLIT_WAIT_TIME 5 /* how many seconds to wait for the QUIT split messages to stop */
+
+static int split_tag;
+static int netsplit_max_nicks, netsplit_nicks_hide_threshold;
+static int printing_splits;
+
+static int get_last_split(IRC_SERVER_REC *server)
+{
+ GSList *tmp;
+ time_t last;
+
+ last = 0;
+ for (tmp = server->split_servers; tmp != NULL; tmp = tmp->next) {
+ NETSPLIT_SERVER_REC *rec = tmp->data;
+
+ if (rec->last > last) last = rec->last;
+ }
+
+ return last;
+}
+
+typedef struct {
+ char *name;
+ int nick_count, maxnickpos;
+ GString *nicks;
+} TEMP_SPLIT_CHAN_REC;
+
+typedef struct {
+ IRC_SERVER_REC *server_rec;
+ GSList *servers; /* if many servers splitted from the same one */
+ GSList *channels;
+} TEMP_SPLIT_REC;
+
+static GSList *get_source_servers(const char *server, GSList **servers)
+{
+ GSList *list, *next, *tmp;
+
+ list = NULL;
+ for (tmp = *servers; tmp != NULL; tmp = next) {
+ NETSPLIT_SERVER_REC *rec = tmp->data;
+ next = tmp->next;
+
+ if (g_ascii_strcasecmp(rec->server, server) == 0) {
+ rec->prints = 0;
+ list = g_slist_append(list, rec);
+ *servers = g_slist_remove(*servers, rec);
+ }
+ }
+
+ return list;
+}
+
+static TEMP_SPLIT_CHAN_REC *find_split_chan(TEMP_SPLIT_REC *rec,
+ const char *name)
+{
+ GSList *tmp;
+
+ for (tmp = rec->channels; tmp != NULL; tmp = tmp->next) {
+ TEMP_SPLIT_CHAN_REC *chanrec = tmp->data;
+
+ if (g_ascii_strcasecmp(chanrec->name, name) == 0)
+ return chanrec;
+ }
+
+ return NULL;
+}
+
+static void get_server_splits(void *key, NETSPLIT_REC *split,
+ TEMP_SPLIT_REC *rec)
+{
+ TEMP_SPLIT_CHAN_REC *chanrec;
+ GSList *tmp;
+
+ if (split->printed ||
+ g_slist_find(rec->servers, split->server) == NULL)
+ return;
+
+ split->printed = TRUE;
+ for (tmp = split->channels; tmp != NULL; tmp = tmp->next) {
+ NETSPLIT_CHAN_REC *splitchan = tmp->data;
+
+ if (ignore_check(SERVER(rec->server_rec), split->nick,
+ split->address, splitchan->name, "",
+ MSGLEVEL_QUITS))
+ continue;
+
+ chanrec = find_split_chan(rec, splitchan->name);
+ if (chanrec == NULL) {
+ chanrec = g_new0(TEMP_SPLIT_CHAN_REC, 1);
+ chanrec->name = splitchan->name;
+ chanrec->nicks = g_string_new(NULL);
+
+ rec->channels = g_slist_append(rec->channels, chanrec);
+ }
+
+ split->server->prints++;
+ chanrec->nick_count++;
+ if (netsplit_nicks_hide_threshold <= 0 ||
+ chanrec->nick_count <= netsplit_nicks_hide_threshold) {
+ if (splitchan->op)
+ g_string_append_c(chanrec->nicks, '@');
+ else if (splitchan->voice)
+ g_string_append_c(chanrec->nicks, '+');
+ g_string_append_printf(chanrec->nicks, "%s, ", split->nick);
+
+ if (chanrec->nick_count == netsplit_max_nicks)
+ chanrec->maxnickpos = chanrec->nicks->len;
+ }
+ }
+}
+
+static void print_server_splits(IRC_SERVER_REC *server, TEMP_SPLIT_REC *rec, const char *filter_channel)
+{
+ GString *destservers;
+ char *sourceserver;
+ GSList *tmp;
+
+ g_return_if_fail(rec->servers != NULL);
+
+ destservers = g_string_new(NULL);
+ for (tmp = rec->servers; tmp != NULL; tmp = tmp->next) {
+ NETSPLIT_SERVER_REC *rec = tmp->data;
+
+ if (rec->prints > 0) {
+ g_string_append_printf(destservers, "%s, ",
+ rec->destserver);
+ }
+ }
+ if (destservers->len == 0) {
+ /* no nicks to print in this server */
+ g_string_free(destservers, TRUE);
+ return;
+ }
+ g_string_truncate(destservers, destservers->len-2);
+
+ sourceserver = ((NETSPLIT_SERVER_REC *) (rec->servers->data))->server;
+ for (tmp = rec->channels; tmp != NULL; tmp = tmp->next) {
+ TEMP_SPLIT_CHAN_REC *chan = tmp->data;
+
+ if (filter_channel != NULL &&
+ strcasecmp(chan->name, filter_channel) != 0)
+ continue;
+
+ g_string_truncate(chan->nicks, chan->nicks->len-2);
+
+ if (netsplit_max_nicks > 0 &&
+ chan->nick_count > netsplit_max_nicks) {
+ g_string_truncate(chan->nicks, chan->maxnickpos);
+ printformat(server, chan->name, MSGLEVEL_QUITS,
+ IRCTXT_NETSPLIT_MORE, sourceserver,
+ destservers->str, chan->nicks->str,
+ chan->nick_count - netsplit_max_nicks);
+ } else {
+ printformat(server, chan->name, MSGLEVEL_QUITS,
+ IRCTXT_NETSPLIT, sourceserver,
+ destservers->str, chan->nicks->str);
+ }
+ }
+
+ g_string_free(destservers, TRUE);
+}
+
+static void temp_split_chan_free(TEMP_SPLIT_CHAN_REC *rec)
+{
+ g_string_free(rec->nicks, TRUE);
+ g_free(rec);
+}
+
+static void print_splits(IRC_SERVER_REC *server, const char *filter_channel)
+{
+ TEMP_SPLIT_REC temp;
+ GSList *servers;
+
+ printing_splits = TRUE;
+
+ servers = g_slist_copy(server->split_servers);
+ while (servers != NULL) {
+ NETSPLIT_SERVER_REC *sserver = servers->data;
+
+ /* get all the splitted servers that have the same
+ source server */
+ temp.servers = get_source_servers(sserver->server, &servers);
+ temp.server_rec = server;
+ temp.channels = NULL;
+
+ g_hash_table_foreach(server->splits,
+ (GHFunc) get_server_splits, &temp);
+ print_server_splits(server, &temp, filter_channel);
+
+ g_slist_foreach(temp.channels,
+ (GFunc) temp_split_chan_free, NULL);
+ g_slist_free(temp.servers);
+ g_slist_free(temp.channels);
+ }
+
+ printing_splits = FALSE;
+}
+
+static int check_server_splits(IRC_SERVER_REC *server)
+{
+ time_t last;
+
+ g_return_val_if_fail(IS_IRC_SERVER(server), FALSE);
+
+ last = get_last_split(server);
+ if (time(NULL)-last < SPLIT_WAIT_TIME)
+ return FALSE;
+
+ print_splits(server, NULL);
+ return TRUE;
+}
+
+/* something is going to be printed to screen, print our current netsplit
+ message before it. */
+static void sig_print_starting(TEXT_DEST_REC *dest)
+{
+ IRC_SERVER_REC *rec;
+
+ if (printing_splits)
+ return;
+
+ if (!IS_IRC_SERVER(dest->server))
+ return;
+
+ rec = IRC_SERVER(dest->server);
+ if (rec->split_servers != NULL) {
+ /* if split_servers exists, the server rec should be
+ still valid. otherwise, calling server->ischannel
+ may not be safe. */
+ if (dest->target != NULL && !server_ischannel((SERVER_REC *) rec, dest->target))
+ return;
+
+ print_splits(rec, NULL);
+ }
+}
+
+static int sig_check_splits(void)
+{
+ GSList *tmp;
+ int stop;
+
+ stop = TRUE;
+ for (tmp = servers; tmp != NULL; tmp = tmp->next) {
+ IRC_SERVER_REC *rec = tmp->data;
+
+ if (!IS_IRC_SERVER(rec))
+ continue;
+
+ if (rec->split_servers != NULL) {
+ if (!check_server_splits(rec))
+ stop = FALSE;
+ }
+ }
+
+ if (stop) {
+ g_source_remove(split_tag);
+ signal_remove("print starting", (SIGNAL_FUNC) sig_print_starting);
+ split_tag = -1;
+ }
+ return 1;
+}
+
+static void sig_netsplit_servers(void)
+{
+ if (settings_get_bool("hide_netsplit_quits") && split_tag == -1) {
+ split_tag = g_timeout_add(1000,
+ (GSourceFunc) sig_check_splits,
+ NULL);
+ signal_add("print starting", (SIGNAL_FUNC) sig_print_starting);
+ }
+}
+
+static int split_equal(NETSPLIT_REC *n1, NETSPLIT_REC *n2)
+{
+ return g_ascii_strcasecmp(n1->nick, n2->nick);
+}
+
+static void split_get(void *key, NETSPLIT_REC *rec, GSList **list)
+{
+ *list = g_slist_insert_sorted(*list, rec,
+ (GCompareFunc) split_equal);
+}
+
+static void split_print(NETSPLIT_REC *rec, SERVER_REC *server)
+{
+ NETSPLIT_CHAN_REC *chan;
+ char *chanstr;
+
+ chan = rec->channels->data;
+ chanstr = chan == NULL ?
+ g_strdup("") :
+ g_strconcat(chan->op ? "@" : (chan->voice ? "+" : ""), chan->name, NULL);
+
+ printformat(server, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_LINE,
+ rec->nick, chanstr, rec->server->server,
+ rec->server->destserver);
+
+ g_free(chanstr);
+}
+
+/* SYNTAX: NETSPLIT */
+static void cmd_netsplit(const char *data, IRC_SERVER_REC *server)
+{
+ GSList *list;
+
+ CMD_IRC_SERVER(server);
+
+ if (server->split_servers == NULL) {
+ printformat(server, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NO_NETSPLITS);
+ return;
+ }
+
+ printformat(server, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_HEADER);
+
+ list = NULL;
+ g_hash_table_foreach(server->splits, (GHFunc) split_get, &list);
+ g_slist_foreach(list, (GFunc) split_print, server);
+ g_slist_free(list);
+
+ printformat(server, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_FOOTER);
+}
+
+static void read_settings(void)
+{
+ netsplit_max_nicks = settings_get_int("netsplit_max_nicks");
+ netsplit_nicks_hide_threshold =
+ settings_get_int("netsplit_nicks_hide_threshold");
+ if (netsplit_nicks_hide_threshold < netsplit_max_nicks)
+ netsplit_max_nicks = netsplit_nicks_hide_threshold;
+}
+
+void fe_netsplit_init(void)
+{
+ settings_add_int("misc", "netsplit_max_nicks", 10);
+ settings_add_int("misc", "netsplit_nicks_hide_threshold", 15);
+ split_tag = -1;
+ printing_splits = FALSE;
+
+ read_settings();
+ signal_add("netsplit new", (SIGNAL_FUNC) sig_netsplit_servers);
+ signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+ command_bind_irc("netsplit", NULL, (SIGNAL_FUNC) cmd_netsplit);
+}
+
+void fe_netsplit_deinit(void)
+{
+ if (split_tag != -1) {
+ g_source_remove(split_tag);
+ signal_remove("print starting", (SIGNAL_FUNC) sig_print_starting);
+ }
+
+ signal_remove("netsplit new", (SIGNAL_FUNC) sig_netsplit_servers);
+ signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
+ command_unbind("netsplit", (SIGNAL_FUNC) cmd_netsplit);
+}
diff --git a/src/fe-common/irc/fe-sasl.c b/src/fe-common/irc/fe-sasl.c
new file mode 100644
index 0000000..72fec58
--- /dev/null
+++ b/src/fe-common/irc/fe-sasl.c
@@ -0,0 +1,53 @@
+/*
+ fe-sasl.c : irssi
+
+ Copyright (C) 2015-2017 The Lemon Man
+
+ 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 <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/irc/core/sasl.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+
+static void sig_sasl_success(IRC_SERVER_REC *server)
+{
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_SASL_SUCCESS);
+}
+
+static void sig_sasl_failure(IRC_SERVER_REC *server, const char *reason)
+{
+ printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_SASL_ERROR, reason);
+}
+
+void fe_sasl_init(void)
+{
+ signal_add("server sasl success", (SIGNAL_FUNC) sig_sasl_success);
+ signal_add("server sasl failure", (SIGNAL_FUNC) sig_sasl_failure);
+}
+
+void fe_sasl_deinit(void)
+{
+ signal_remove("server sasl success", (SIGNAL_FUNC) sig_sasl_success);
+ signal_remove("server sasl failure", (SIGNAL_FUNC) sig_sasl_failure);
+}
diff --git a/src/fe-common/irc/fe-whois.c b/src/fe-common/irc/fe-whois.c
new file mode 100644
index 0000000..b0eeb19
--- /dev/null
+++ b/src/fe-common/irc/fe-whois.c
@@ -0,0 +1,456 @@
+/* Copyright (C) 1999-2004 Timo Sirainen */
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/levels.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/settings.h>
+#include <irssi/src/core/recode.h>
+
+#include <irssi/src/irc/core/irc-servers.h>
+
+#include <irssi/src/fe-common/core/printtext.h>
+
+static void event_whois(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *user, *host, *realname, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 6, NULL, &nick, &user,
+ &host, NULL, &realname);
+ recoded = recode_in(SERVER(server), realname, nick);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS, nick, user, host, recoded);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_whois_special(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *str;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3 | PARAM_FLAG_GETREST, NULL, &nick, &str);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_SPECIAL, nick, str);
+ g_free(params);
+}
+
+static void event_whois_idle(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *secstr, *signonstr, *rest, *timestr;
+ long days, hours, mins, secs;
+ time_t signon;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 5 | PARAM_FLAG_GETREST, NULL,
+ &nick, &secstr, &signonstr, &rest);
+
+ secs = atol(secstr);
+ signon = strstr(rest, "signon time") == NULL ? 0 :
+ (time_t) atol(signonstr);
+
+ days = secs/3600/24;
+ hours = (secs%(3600*24))/3600;
+ mins = (secs%3600)/60;
+ secs %= 60;
+
+ if (signon == 0)
+ printformat(server, nick, MSGLEVEL_CRAP, IRCTXT_WHOIS_IDLE,
+ nick, days, hours, mins, secs);
+ else {
+ timestr = my_asctime(signon);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_IDLE_SIGNON,
+ nick, days, hours, mins, secs, timestr);
+ g_free(timestr);
+ }
+ g_free(params);
+}
+
+static void event_whois_server(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *whoserver, *desc;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 4, NULL, &nick, &whoserver, &desc);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_SERVER, nick, whoserver, desc);
+ g_free(params);
+}
+
+static void event_whois_oper(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *type;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &type);
+
+ /* Bugfix: http://bugs.irssi.org/?do=details&task_id=99
+ * Author: Geert Hauwaerts <geert@irssi.org>
+ * Date: Wed Sep 15 20:17:24 CEST 2004
+ */
+
+ if ((!strncmp(type, "is an ", 6)) || (!strncmp(type, "is a ", 5))) {
+ type += 5;
+ if (*type == ' ') type++;
+ }
+
+ if (*type == '\0')
+ type = "IRC Operator";
+
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_OPER, nick, type);
+ g_free(params);
+}
+
+static void event_whois_modes(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *modes;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3 | PARAM_FLAG_GETREST,
+ NULL, &nick, &modes);
+ if (!strncmp(modes, "is using modes ", 15))
+ modes += 15;
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_MODES, nick, modes);
+ g_free(params);
+}
+
+static void event_whois_realhost(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *txt_real, *txt_hostname, *hostname;
+
+ g_return_if_fail(data != NULL);
+
+ /* <yournick> real hostname <nick> <hostname> */
+ params = event_get_params(data, 5, NULL, &nick, &txt_real,
+ &txt_hostname, &hostname);
+ if (g_strcmp0(txt_real, "real") != 0 ||
+ g_strcmp0(txt_hostname, "hostname") != 0) {
+ /* <yournick> <nick> :... from <hostname> */
+ g_free(params);
+ params = event_get_params(data, 3, NULL, &nick, &hostname);
+
+ hostname = strstr(hostname, "from ");
+ if (hostname != NULL) hostname += 5;
+ }
+
+ if (hostname != NULL) {
+ if (!strncmp(hostname, "*@", 2))
+ hostname += 2;
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_REALHOST, nick, hostname, "");
+ } else {
+ event_whois_special(server, data);
+ }
+ g_free(params);
+}
+
+static void event_whois_usermode326(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *usermode;
+
+ g_return_if_fail(data != NULL);
+
+ /* <yournick> <nick> :has oper privs: <mode> */
+ params = event_get_params(data, 3, NULL, &nick, &usermode);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_USERMODE, nick, usermode);
+ g_free(params);
+}
+
+static void event_whois_realhost327(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *hostname, *ip, *text;
+
+ g_return_if_fail(data != NULL);
+
+ /* <yournick> <hostname> <ip> :Real hostname/IP */
+ params = event_get_params(data, 5, NULL, &nick, &hostname, &ip, &text);
+ if (*text != '\0') {
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_REALHOST, nick, hostname, ip);
+ } else {
+ event_whois_special(server, data);
+ }
+ g_free(params);
+}
+
+static void event_whois_realhost338(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *arg1, *arg2, *arg3;
+
+ g_return_if_fail(data != NULL);
+
+ /*
+ * :<server> 338 <yournick> <nick> <user>@<host> <ip> :Actual user@host, actual IP
+ * (ircu) or
+ * :<server> 338 <yournick> <nick> <ip> :actually using host
+ * (ratbox)
+ */
+ params = event_get_params(data, 5, NULL, &nick, &arg1, &arg2, &arg3);
+ if (*arg3 != '\0') {
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_REALHOST, nick, arg1, arg2);
+ } else if (*arg2 != '\0') {
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_REALHOST, nick, arg1, "");
+ } else {
+ event_whois_special(server, data);
+ }
+ g_free(params);
+}
+
+static void event_whois_usermode(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *txt_usermodes, *nick, *usermode;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 4, NULL, &txt_usermodes,
+ &nick, &usermode);
+
+ if (g_strcmp0(txt_usermodes, "usermodes") == 0) {
+ /* <yournick> usermodes <nick> usermode */
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_USERMODE, nick, usermode);
+ } else {
+ event_whois_special(server, data);
+ }
+ g_free(params);
+}
+
+static void hide_safe_channel_id(IRC_SERVER_REC *server, char *chans)
+{
+ const char *idchan, *nick_flags;
+ char *p, *dest, *end, id;
+ int count, length, chanstart;
+
+ if (!server->isupport_sent)
+ idchan = "!:5";
+ else {
+ idchan = g_hash_table_lookup(server->isupport, "IDCHAN");
+ if (idchan == NULL)
+ return;
+ }
+ nick_flags = server->get_nick_flags(SERVER(server));
+
+ while (*idchan != '\0') {
+ id = *idchan;
+ if (idchan[1] != ':')
+ return;
+
+ length = strtoul(idchan+2, &end, 10);
+ if (*end == ',')
+ end++;
+ else if (*end != '\0')
+ return;
+ idchan = end;
+
+ count = 0;
+ chanstart = TRUE;
+ for (dest = p = chans; *p != '\0'; p++) {
+ if (count > 0)
+ count--;
+ else {
+ if (*p == ' ')
+ chanstart = TRUE;
+ else {
+ if (chanstart && *p == id)
+ count = length;
+ chanstart = chanstart && strchr(nick_flags, *p);
+ }
+ *dest++ = *p;
+ }
+ }
+ *dest = '\0';
+ }
+}
+
+static void event_whois_channels(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *chans, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &chans);
+
+ /* sure - we COULD print the channel names as-is, but since the
+ colors, bolds, etc. are mostly just to fool people, I think we
+ should show the channel names as they REALLY are so they could
+ even be joined without any extra tricks. */
+ chans = show_lowascii(chans);
+ if (settings_get_bool("whois_hide_safe_channel_id"))
+ hide_safe_channel_id(server, chans);
+ recoded = recode_in(SERVER(server), chans, nick);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_CHANNELS, nick, recoded);
+ g_free(chans);
+
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_whois_away(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *awaymsg, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &awaymsg);
+ recoded = recode_in(SERVER(server), awaymsg, nick);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_AWAY, nick, recoded);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_end_of_whois(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &nick);
+ if (server->whois_found) {
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_END_OF_WHOIS, nick);
+ }
+ g_free(params);
+}
+
+static void event_whois_auth(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *text;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 3, NULL, &nick, &text);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOIS_EXTRA, nick, text);
+ g_free(params);
+}
+
+static void event_whowas(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick, *user, *host, *realname, *recoded;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 6, NULL, &nick, &user,
+ &host, NULL, &realname);
+ recoded = recode_in(SERVER(server), realname, nick);
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_WHOWAS, nick, user, host, recoded);
+ g_free(params);
+ g_free(recoded);
+}
+
+static void event_end_of_whowas(IRC_SERVER_REC *server, const char *data)
+{
+ char *params, *nick;
+
+ g_return_if_fail(data != NULL);
+
+ params = event_get_params(data, 2, NULL, &nick);
+ if (server->whowas_found) {
+ printformat(server, nick, MSGLEVEL_CRAP,
+ IRCTXT_END_OF_WHOWAS, nick);
+ }
+ g_free(params);
+}
+
+struct whois_event_table {
+ int num;
+ void (*func)(IRC_SERVER_REC *, const char *);
+};
+
+static struct whois_event_table events[] = {
+ { 312, event_whois_server },
+ { 326, event_whois_usermode326 },
+ { 327, event_whois_realhost327 },
+ { 338, event_whois_realhost338 },
+ { 379, event_whois_modes },
+ { 378, event_whois_realhost },
+ { 377, event_whois_usermode },
+ { 317, event_whois_idle },
+ { 330, event_whois_auth },
+ { 319, event_whois_channels },
+ { 0, NULL }
+};
+
+static void event_whois_default(IRC_SERVER_REC *server, const char *data)
+{
+ int i, num;
+
+ num = atoi(current_server_event);
+ for (i = 0; events[i].num != 0; i++) {
+ if (events[i].num == num) {
+ events[i].func(server, data);
+ return;
+ }
+ }
+
+ event_whois_special(server, data);
+}
+
+void fe_whois_init(void)
+{
+ settings_add_bool("lookandfeel", "whois_hide_safe_channel_id", TRUE);
+
+ signal_add("event 311", (SIGNAL_FUNC) event_whois);
+ signal_add("event 312", (SIGNAL_FUNC) event_whois_server);
+ /* readding this events fixes the printing of /whois -yes *
+ Bug http://bugs.irssi.org/?do=details&task_id=123 */
+ signal_add("event 317", (SIGNAL_FUNC) event_whois_idle);
+ signal_add("event 319", (SIGNAL_FUNC) event_whois_channels);
+ signal_add("event 313", (SIGNAL_FUNC) event_whois_oper);
+ signal_add("event 330", (SIGNAL_FUNC) event_whois_auth);
+ signal_add("whois account", (SIGNAL_FUNC) event_whois_auth);
+ signal_add("event 377", (SIGNAL_FUNC) event_whois_usermode);
+ signal_add("event 378", (SIGNAL_FUNC) event_whois_realhost);
+ signal_add("event 379", (SIGNAL_FUNC) event_whois_modes);
+ signal_add("event 327", (SIGNAL_FUNC) event_whois_realhost327);
+ signal_add("event 326", (SIGNAL_FUNC) event_whois_usermode326);
+ signal_add("event 338", (SIGNAL_FUNC) event_whois_realhost338);
+ signal_add("whois away", (SIGNAL_FUNC) event_whois_away);
+ signal_add("whois oper", (SIGNAL_FUNC) event_whois_oper);
+ signal_add("whowas away", (SIGNAL_FUNC) event_whois_away);
+ signal_add("whois default event", (SIGNAL_FUNC) event_whois_default);
+ signal_add("event 318", (SIGNAL_FUNC) event_end_of_whois);
+ signal_add("event 314", (SIGNAL_FUNC) event_whowas);
+ signal_add("event 369", (SIGNAL_FUNC) event_end_of_whowas);
+}
+
+void fe_whois_deinit(void)
+{
+ signal_remove("event 311", (SIGNAL_FUNC) event_whois);
+ signal_remove("event 312", (SIGNAL_FUNC) event_whois_server);
+ signal_remove("event 317", (SIGNAL_FUNC) event_whois_idle);
+ signal_remove("event 319", (SIGNAL_FUNC) event_whois_channels);
+ signal_remove("event 313", (SIGNAL_FUNC) event_whois_oper);
+ signal_remove("event 330", (SIGNAL_FUNC) event_whois_auth);
+ signal_remove("whois account", (SIGNAL_FUNC) event_whois_auth);
+ signal_remove("event 377", (SIGNAL_FUNC) event_whois_usermode);
+ signal_remove("event 378", (SIGNAL_FUNC) event_whois_realhost);
+ signal_remove("event 379", (SIGNAL_FUNC) event_whois_modes);
+ signal_remove("event 327", (SIGNAL_FUNC) event_whois_realhost327);
+ signal_remove("event 326", (SIGNAL_FUNC) event_whois_usermode326);
+ signal_remove("event 338", (SIGNAL_FUNC) event_whois_realhost338);
+ signal_remove("whois away", (SIGNAL_FUNC) event_whois_away);
+ signal_remove("whois oper", (SIGNAL_FUNC) event_whois_oper);
+ signal_remove("whowas away", (SIGNAL_FUNC) event_whois_away);
+ signal_remove("whois default event", (SIGNAL_FUNC) event_whois_default);
+ signal_remove("event 318", (SIGNAL_FUNC) event_end_of_whois);
+ signal_remove("event 314", (SIGNAL_FUNC) event_whowas);
+ signal_remove("event 369", (SIGNAL_FUNC) event_end_of_whowas);
+}
diff --git a/src/fe-common/irc/irc-completion.c b/src/fe-common/irc/irc-completion.c
new file mode 100644
index 0000000..71e2e0c
--- /dev/null
+++ b/src/fe-common/irc/irc-completion.c
@@ -0,0 +1,41 @@
+/*
+ irc-completion.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/core/signals.h>
+#include <irssi/src/fe-common/core/chat-completion.h>
+
+static void sig_complete_stats(GList **list, WINDOW_REC *window,
+ const char *word, const char *line,
+ int *want_space)
+{
+ *list = completion_get_servers(word);
+ if (*list != NULL) signal_stop();
+}
+
+void irc_completion_init(void)
+{
+ signal_add("complete command stats", (SIGNAL_FUNC) sig_complete_stats);
+}
+
+void irc_completion_deinit(void)
+{
+ signal_remove("complete command stats", (SIGNAL_FUNC) sig_complete_stats);
+}
diff --git a/src/fe-common/irc/irc-modules.c b/src/fe-common/irc/irc-modules.c
new file mode 100644
index 0000000..3bf1f32
--- /dev/null
+++ b/src/fe-common/irc/irc-modules.c
@@ -0,0 +1,4 @@
+void fe_irc_dcc_init(void);void fe_irc_notifylist_init(void);
+void fe_irc_notifylist_deinit(void);void fe_irc_dcc_deinit(void);
+void fe_irc_modules_init(void) { fe_irc_dcc_init(); fe_irc_notifylist_init(); }
+void fe_irc_modules_deinit(void) { fe_irc_notifylist_deinit(); fe_irc_dcc_deinit(); }
diff --git a/src/fe-common/irc/meson.build b/src/fe-common/irc/meson.build
new file mode 100644
index 0000000..1789133
--- /dev/null
+++ b/src/fe-common/irc/meson.build
@@ -0,0 +1,44 @@
+# this file is part of irssi
+
+libfe_common_irc_a = static_library('fe_common_irc',
+ files(
+ 'fe-cap.c',
+ 'fe-common-irc.c',
+ 'fe-ctcp.c',
+ 'fe-events-numeric.c',
+ 'fe-events.c',
+ 'fe-irc-channels.c',
+ 'fe-irc-commands.c',
+ 'fe-irc-messages.c',
+ 'fe-irc-queries.c',
+ 'fe-irc-server.c',
+ 'fe-ircnet.c',
+ 'fe-modes.c',
+ 'fe-netjoin.c',
+ 'fe-netsplit.c',
+ 'fe-sasl.c',
+ 'fe-whois.c',
+ 'irc-completion.c',
+ 'module-formats.c',
+
+ 'irc-modules.c',
+ ),
+ include_directories : rootinc,
+ implicit_include_directories : false,
+ c_args : [
+ def_helpdir,
+ def_themesdir,
+ ],
+ dependencies : dep)
+
+install_headers(
+ files(
+ 'fe-irc-channels.h',
+ 'fe-irc-server.h',
+ 'module-formats.h',
+ 'module.h',
+ ),
+ subdir : incdir / 'src' / 'fe-common' / 'irc')
+
+subdir('dcc')
+subdir('notifylist')
diff --git a/src/fe-common/irc/module-formats.c b/src/fe-common/irc/module-formats.c
new file mode 100644
index 0000000..0adb268
--- /dev/null
+++ b/src/fe-common/irc/module-formats.c
@@ -0,0 +1,184 @@
+/*
+ module-formats.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/core/formats.h>
+
+/* clang-format off */
+FORMAT_REC fecommon_irc_formats[] = {
+ { MODULE_NAME, "IRC", 0 },
+
+ /* ---- */
+ { NULL, "Server", 0 },
+
+ { "netsplit", "{netsplit Netsplit} {server $0} <-> {server $1} quits: $2", 3, { 0, 0, 0 } },
+ { "netsplit_more", "{netsplit Netsplit} {server $0} <-> {server $1} quits: $2 (+$3 more, use /NETSPLIT to show all of them)", 4, { 0, 0, 0, 1 } },
+ { "netsplit_join", "{netjoin Netsplit} over, joins: $0", 1, { 0 } },
+ { "netsplit_join_more", "{netjoin Netsplit} over, joins: $0 (+$1 more)", 2, { 0, 1 } },
+ { "no_netsplits", "There are no net splits", 0 },
+ { "netsplits_header", "%#Nick Channel Server Split server", 0 },
+ { "netsplits_line", "%#$[9]0 $[10]1 $[20]2 $3", 4, { 0, 0, 0, 0 } },
+ { "netsplits_footer", "", 0 },
+ { "network_added", "Network $0 saved", 1, { 0 } },
+ { "network_removed", "Network $0 removed", 1, { 0 } },
+ { "network_not_found", "Network $0 not found", 1, { 0 } },
+ { "network_header", "%#Networks:", 0 },
+ { "network_line", "%#$0: $1", 2, { 0, 0 } },
+ { "network_footer", "", 0 },
+ { "setupserver_header", "%#Server Port Network Settings", 0 },
+ { "setupserver_line", "%#%|$[!20]0 $[5]1 $[10]2 $3", 4, { 0, 1, 0, 0 } },
+ { "setupserver_footer", "", 0 },
+ { "server_waiting_cap_ls", "Waiting for CAP LS response...", 2, { 0, 0 } },
+ { "sasl_success", "SASL authentication succeeded", 0 },
+ { "sasl_error", "Cannot authenticate via SASL ($0)", 1, { 0 } },
+ { "cap_req", "Capabilities requested: $0", 1, { 0 } },
+ { "cap_ls", "Capabilities supported: $0", 1, { 0 } },
+ { "cap_ack", "Capabilities acknowledged: $0", 1, { 0 } },
+ { "cap_nak", "Capabilities refused: $0", 1, { 0 } },
+ { "cap_list", "Capabilities currently enabled: $0", 1, { 0 } },
+ { "cap_new", "Capabilities now available: $0", 1, { 0 } },
+ { "cap_del", "Capabilities removed: $0", 1, { 0 } },
+
+ /* ---- */
+ { NULL, "Channels", 0 },
+
+ { "joinerror_toomany", "Cannot join to channel {channel $0} (You have joined to too many channels)", 1, { 0 } },
+ { "joinerror_full", "Cannot join to channel {channel $0} (Channel is full)", 1, { 0 } },
+ { "joinerror_invite", "Cannot join to channel {channel $0} (You must be invited)", 1, { 0 } },
+ { "joinerror_banned", "Cannot join to channel {channel $0} (You are banned)", 1, { 0 } },
+ { "joinerror_bad_key", "Cannot join to channel {channel $0} (Bad channel key)", 1, { 0 } },
+ { "joinerror_bad_mask", "Cannot join to channel {channel $0} (Bad channel mask)", 1, { 0 } },
+ { "joinerror_secure_only", "Cannot join to channel {channel $0} (Secure clients only)", 1, { 0 } },
+ { "joinerror_unavail", "Cannot join to channel {channel $0} (Channel is temporarily unavailable)", 1, { 0 } },
+ { "joinerror_duplicate", "Channel {channel $0} already exists - cannot create it", 1, { 0 } },
+ { "channel_rejoin", "Channel {channel $0} is temporarily unavailable, this is normally because of netsplits. Irssi will now automatically try to rejoin back to this channel until the join is successful. Use /RMREJOINS command if you wish to abort this.", 1, { 0 } },
+ { "inviting", "Inviting {nick $0} to {channel $1}", 2, { 0, 0 } },
+ { "channel_created", "Channel {channelhilight $0} created $1", 2, { 0, 0 } },
+ { "url", "Home page for {channelhilight $0}: $1", 2, { 0, 0 } },
+ { "topic", "Topic for {channelhilight $0}: $1", 2, { 0, 0 } },
+ { "no_topic", "No topic set for {channelhilight $0}", 1, { 0 } },
+ { "topic_info", "Topic set by {nick $0} {nickhost $2} {comment $1}", 3, { 0, 0, 0 } },
+ { "chanmode_change", "mode/{channelhilight $0} {mode $1} by {nick $2}", 4, { 0, 0, 0, 0 } },
+ { "server_chanmode_change", "{netsplit ServerMode}/{channelhilight $0} {mode $1} by {nick $2}", 3, { 0, 0, 0 } },
+ { "channel_mode", "mode/{channelhilight $0} {mode $1}", 2, { 0, 0 } },
+ { "bantype", "Ban type changed to {channel $0}", 1, { 0 } },
+ { "no_bans", "No bans in channel {channel $0}", 1, { 0 } },
+ { "banlist", "$0 - {channel $1}: ban {ban $2}", 3, { 1, 0, 0 } },
+ { "banlist_long", "$0 - {channel $1}: ban {ban $2} {comment by {nick $3}, $4 secs ago}", 5, { 1, 0, 0, 0, 1 } },
+ { "ebanlist", "{channel $0}: ban exception {ban $1}", 2, { 0, 0 } },
+ { "ebanlist_long", "{channel $0}: ban exception {ban $1} {comment by {nick $2}, $3 secs ago}", 4, { 0, 0, 0, 1 } },
+ { "no_invitelist", "Invite list is empty in channel {channel $0}", 1, { 0 } },
+ { "invitelist", "{channel $0}: invite {ban $1}", 2, { 0, 0 } },
+ { "invitelist_long", "{channel $0}: invite {ban $1} {comment by {nick $2}, $3 secs ago}", 4, { 0, 0, 0, 1 } },
+ { "no_such_channel", "{channel $0}: No such channel", 1, { 0 } },
+ { "channel_synced", "Join to {channel $0} was synced in {hilight $1} secs", 2, { 0, 2 } },
+ { "server_help_start", "$1", 2, { 0, 0 } },
+ { "server_help_txt", "$1", 2, { 0, 0 } },
+ { "server_end_of_help", "$1", 2, { 0, 0 } },
+
+ /* ---- */
+ { NULL, "Nick", 0 },
+
+ { "usermode_change", "Mode change {mode $0} for user {nick $1}", 2, { 0, 0 } },
+ { "user_mode", "Your user mode is {mode $0}", 1, { 0 } },
+ { "away", "You have been marked as being away", 0 },
+ { "unaway", "You are no longer marked as being away", 0 },
+ { "nick_away", "{nick $0} is away: $1", 2, { 0, 0 } },
+ { "no_such_nick", "{nick $0}: No such nick/channel", 1, { 0 } },
+ { "nick_in_use", "Nick {nick $0} is already in use", 1, { 0 } },
+ { "nick_unavailable", "Nick {nick $0} is temporarily unavailable", 1, { 0 } },
+ { "your_nick_owned", "Your nick is in use by {nick $3} {comment $1@$2}", 4, { 0, 0, 0, 0 } },
+
+ /* ---- */
+ { NULL, "Who queries", 0 },
+
+ { "whois", "{nick $0} {nickhost $1@$2}%:{whois ircname $3}", 4, { 0, 0, 0, 0 } },
+ { "whowas", "{nick $0} {nickhost $1@$2}%:{whois was $3}", 4, { 0, 0, 0, 0 } },
+ { "whois_idle", "{whois idle %|$1 days $2 hours $3 mins $4 secs}", 5, { 0, 1, 1, 1, 1 } },
+ { "whois_idle_signon", "{whois idle %|$1 days $2 hours $3 mins $4 secs {comment signon: $5}}", 6, { 0, 1, 1, 1, 1, 0 } },
+ { "whois_server", "{whois server %|$1 {comment $2}}", 3, { 0, 0, 0 } },
+ { "whois_oper", "{whois {hilight $1}}", 2, { 0, 0 } },
+ { "whois_modes", "{whois modes $1}", 2, { 0, 0 } },
+ { "whois_realhost", "{whois hostname $1-}", 3, { 0, 0, 0 } },
+ { "whois_usermode", "{whois usermode $1}", 2, { 0, 0 } },
+ { "whois_channels", "{whois channels %|$1}", 2, { 0, 0 } },
+ { "whois_away", "{whois away %|$1}", 2, { 0, 0 } },
+ { "whois_special", "{whois %|$1}", 2, { 0, 0 } },
+ { "whois_extra", "{whois account %|$1}", 2, { 0, 0 } },
+ { "end_of_whois", "End of WHOIS", 1, { 0 } },
+ { "end_of_whowas", "End of WHOWAS", 1, { 0 } },
+ { "whois_not_found", "There is no such nick $0", 1, { 0 } },
+ { "who", "%#{channelhilight $[-10]0} %|{nick $[!9]1} $[!3]2 $[!2]3 $4@$5 {comment {hilight $6}}", 8, { 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { "end_of_who", "End of /WHO list", 1, { 0 } },
+
+ /* ---- */
+ { NULL, "Your messages", 0 },
+
+ { "own_notice", "{ownnotice notice $0}$1", 2, { 0, 0 } },
+ { "own_action", "{ownaction $0}$1", 3, { 0, 0, 0 } },
+ { "own_action_target", "{ownaction_target $0 $2}$1", 3, { 0, 0, 0 } },
+ { "own_ctcp", "{ownctcp ctcp $0}$1 $2", 3, { 0, 0, 0 } },
+
+ /* ---- */
+ { NULL, "Received messages", 0 },
+
+ { "notice_server", "{servernotice $0}$1", 2, { 0, 0 } },
+ { "notice_public", "{notice $0{pubnotice_channel $1}}$2", 3, { 0, 0, 0 } },
+ { "notice_private", "{notice $0{pvtnotice_host $1}}$2", 3, { 0, 0, 0 } },
+ { "action_private", "{pvtaction $0}$2", 3, { 0, 0, 0 } },
+ { "action_private_query", "{pvtaction_query $0}$2", 3, { 0, 0, 0 } },
+ { "action_public", "{pubaction $0}$1", 2, { 0, 0 } },
+ { "action_public_channel", "{pubaction $0{msgchannel $1}}$2", 3, { 0, 0, 0 } },
+
+ /* ---- */
+ { NULL, "CTCPs", 0 },
+
+ { "ctcp_reply", "CTCP {hilight $0} reply from {nick $1}: $2", 3, { 0, 0, 0 } },
+ { "ctcp_reply_channel", "CTCP {hilight $0} reply from {nick $1} in channel {channel $3}: $2", 4, { 0, 0, 0, 0 } },
+ { "ctcp_ping_reply", "CTCP {hilight PING} reply from {nick $0}: $1.$[-3.0]2 seconds", 3, { 0, 2, 2 } },
+ { "ctcp_requested", "{ctcp {hilight $0} {comment $1} requested CTCP {hilight $2} from {nick $4}}: $3", 5, { 0, 0, 0, 0, 0 } },
+ { "ctcp_requested_unknown", "{ctcp {hilight $0} {comment $1} requested unknown CTCP {hilight $2} from {nick $4}}: $3", 5, { 0, 0, 0, 0, 0 } },
+
+ /* ---- */
+ { NULL, "Other server events", 0 },
+
+ { "online", "Users online: {hilight $0}", 1, { 0 } },
+ { "pong", "PONG received from $0: $1", 2, { 0, 0 } },
+ { "wallops", "{wallop WALLOP {wallop_nick $0}} $1", 2, { 0, 0 } },
+ { "action_wallops", "{wallop WALLOP {wallop_action $0}} $1", 2, { 0, 0 } },
+ { "kill", "You were {error killed} by {nick $0} {nickhost $1} {reason $2} {comment Path: $3}", 4, { 0, 0, 0, 0 } },
+ { "kill_server", "You were {error killed} by {server $0} {reason $1} {comment Path: $2}", 3, { 0, 0, 0 } },
+ { "error", "{error ERROR} $0", 1, { 0 } },
+ { "unknown_mode", "Unknown mode character $0", 1, { 0 } },
+ { "default_event", "$1", 3, { 0, 0, 0 } },
+ { "default_event_server", "[$0] $1", 3, { 0, 0, 0 } },
+
+ /* ---- */
+ { NULL, "Misc", 0 },
+
+ { "silenced", "Silenced {nick $0}", 1, { 0 } },
+ { "unsilenced", "Unsilenced {nick $0}", 1, { 0 } },
+ { "silence_line", "{nick $0}: silence {ban $1}", 2, { 0, 0 } },
+ { "ask_oper_pass", "Operator password:", 0 },
+ { "accept_list", "Accepted users: {hilight $0}", 1, { 0 } },
+
+ { NULL, NULL, 0 }
+};
+/* clang-format on */
diff --git a/src/fe-common/irc/module-formats.h b/src/fe-common/irc/module-formats.h
new file mode 100644
index 0000000..a9d29cb
--- /dev/null
+++ b/src/fe-common/irc/module-formats.h
@@ -0,0 +1,154 @@
+#include <irssi/src/fe-common/core/formats.h>
+
+/* clang-format off */
+enum {
+ IRCTXT_MODULE_NAME,
+
+ IRCTXT_FILL_1,
+
+ IRCTXT_NETSPLIT,
+ IRCTXT_NETSPLIT_MORE,
+ IRCTXT_NETSPLIT_JOIN,
+ IRCTXT_NETSPLIT_JOIN_MORE,
+ IRCTXT_NO_NETSPLITS,
+ IRCTXT_NETSPLITS_HEADER,
+ IRCTXT_NETSPLITS_LINE,
+ IRCTXT_NETSPLITS_FOOTER,
+ IRCTXT_NETWORK_ADDED,
+ IRCTXT_NETWORK_REMOVED,
+ IRCTXT_NETWORK_NOT_FOUND,
+ IRCTXT_NETWORK_HEADER,
+ IRCTXT_NETWORK_LINE,
+ IRCTXT_NETWORK_FOOTER,
+ IRCTXT_SETUPSERVER_HEADER,
+ IRCTXT_SETUPSERVER_LINE,
+ IRCTXT_SETUPSERVER_FOOTER,
+ IRCTXT_SERVER_WAITING_CAP_LS,
+ IRCTXT_SASL_SUCCESS,
+ IRCTXT_SASL_ERROR,
+ IRCTXT_CAP_REQ,
+ IRCTXT_CAP_LS,
+ IRCTXT_CAP_ACK,
+ IRCTXT_CAP_NAK,
+ IRCTXT_CAP_LIST,
+ IRCTXT_CAP_NEW,
+ IRCTXT_CAP_DEL,
+
+ IRCTXT_FILL_2,
+
+ IRCTXT_JOINERROR_TOOMANY,
+ IRCTXT_JOINERROR_FULL,
+ IRCTXT_JOINERROR_INVITE,
+ IRCTXT_JOINERROR_BANNED,
+ IRCTXT_JOINERROR_BAD_KEY,
+ IRCTXT_JOINERROR_BAD_MASK,
+ IRCTXT_JOINERROR_SECURE_ONLY,
+ IRCTXT_JOINERROR_UNAVAIL,
+ IRCTXT_JOINERROR_DUPLICATE,
+ IRCTXT_CHANNEL_REJOIN,
+ IRCTXT_INVITING,
+ IRCTXT_CHANNEL_CREATED,
+ IRCTXT_CHANNEL_URL,
+ IRCTXT_TOPIC,
+ IRCTXT_NO_TOPIC,
+ IRCTXT_TOPIC_INFO,
+ IRCTXT_CHANMODE_CHANGE,
+ IRCTXT_SERVER_CHANMODE_CHANGE,
+ IRCTXT_CHANNEL_MODE,
+ IRCTXT_BANTYPE,
+ IRCTXT_NO_BANS,
+ IRCTXT_BANLIST,
+ IRCTXT_BANLIST_LONG,
+ IRCTXT_EBANLIST,
+ IRCTXT_EBANLIST_LONG,
+ IRCTXT_NO_INVITELIST,
+ IRCTXT_INVITELIST,
+ IRCTXT_INVITELIST_LONG,
+ IRCTXT_NO_SUCH_CHANNEL,
+ IRCTXT_CHANNEL_SYNCED,
+ IRCTXT_SERVER_HELP_START,
+ IRCTXT_SERVER_HELP_TXT,
+ IRCTXT_SERVER_END_OF_HELP,
+
+ IRCTXT_FILL_4,
+
+ IRCTXT_USERMODE_CHANGE,
+ IRCTXT_USER_MODE,
+ IRCTXT_AWAY,
+ IRCTXT_UNAWAY,
+ IRCTXT_NICK_AWAY,
+ IRCTXT_NO_SUCH_NICK,
+ IRCTXT_NICK_IN_USE,
+ IRCTXT_NICK_UNAVAILABLE,
+ IRCTXT_YOUR_NICK_OWNED,
+
+ IRCTXT_FILL_5,
+
+ IRCTXT_WHOIS,
+ IRCTXT_WHOWAS,
+ IRCTXT_WHOIS_IDLE,
+ IRCTXT_WHOIS_IDLE_SIGNON,
+ IRCTXT_WHOIS_SERVER,
+ IRCTXT_WHOIS_OPER,
+ IRCTXT_WHOIS_MODES,
+ IRCTXT_WHOIS_REALHOST,
+ IRCTXT_WHOIS_USERMODE,
+ IRCTXT_WHOIS_CHANNELS,
+ IRCTXT_WHOIS_AWAY,
+ IRCTXT_WHOIS_SPECIAL,
+ IRCTXT_WHOIS_EXTRA,
+ IRCTXT_END_OF_WHOIS,
+ IRCTXT_END_OF_WHOWAS,
+ IRCTXT_WHOIS_NOT_FOUND,
+ IRCTXT_WHO,
+ IRCTXT_END_OF_WHO,
+
+ IRCTXT_FILL_6,
+
+ IRCTXT_OWN_NOTICE,
+ IRCTXT_OWN_ACTION,
+ IRCTXT_OWN_ACTION_TARGET,
+ IRCTXT_OWN_CTCP,
+
+ IRCTXT_FILL_7,
+
+ IRCTXT_NOTICE_SERVER,
+ IRCTXT_NOTICE_PUBLIC,
+ IRCTXT_NOTICE_PRIVATE,
+ IRCTXT_ACTION_PRIVATE,
+ IRCTXT_ACTION_PRIVATE_QUERY,
+ IRCTXT_ACTION_PUBLIC,
+ IRCTXT_ACTION_PUBLIC_CHANNEL,
+
+ IRCTXT_FILL_8,
+
+ IRCTXT_CTCP_REPLY,
+ IRCTXT_CTCP_REPLY_CHANNEL,
+ IRCTXT_CTCP_PING_REPLY,
+ IRCTXT_CTCP_REQUESTED,
+ IRCTXT_CTCP_REQUESTED_UNKNOWN,
+
+ IRCTXT_FILL_10,
+
+ IRCTXT_ONLINE,
+ IRCTXT_PONG,
+ IRCTXT_WALLOPS,
+ IRCTXT_ACTION_WALLOPS,
+ IRCTXT_KILL,
+ IRCTXT_KILL_SERVER,
+ IRCTXT_ERROR,
+ IRCTXT_UNKNOWN_MODE,
+ IRCTXT_DEFAULT_EVENT,
+ IRCTXT_DEFAULT_EVENT_SERVER,
+
+ IRCTXT_FILL_11,
+
+ IRCTXT_SILENCED,
+ IRCTXT_UNSILENCED,
+ IRCTXT_SILENCE_LINE,
+ IRCTXT_ASK_OPER_PASS,
+ IRCTXT_ACCEPT_LIST
+};
+/* clang-format on */
+
+extern FORMAT_REC fecommon_irc_formats[];
diff --git a/src/fe-common/irc/module.h b/src/fe-common/irc/module.h
new file mode 100644
index 0000000..ad63c95
--- /dev/null
+++ b/src/fe-common/irc/module.h
@@ -0,0 +1,4 @@
+#include <irssi/src/common.h>
+#include <irssi/src/irc/core/irc.h>
+
+#define MODULE_NAME "fe-common/irc"
diff --git a/src/fe-common/irc/notifylist/Makefile.am b/src/fe-common/irc/notifylist/Makefile.am
new file mode 100644
index 0000000..5eecb5f
--- /dev/null
+++ b/src/fe-common/irc/notifylist/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LIBRARIES = libfe_irc_notifylist.a
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DHELPDIR=\""$(datadir)/irssi/help"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+libfe_irc_notifylist_a_SOURCES = \
+ fe-notifylist.c \
+ module-formats.c
+
+pkginc_fe_common_irc_notifylistdir=$(pkgincludedir)/src/fe-common/irc/notifylist
+pkginc_fe_common_irc_notifylist_HEADERS = \
+ module.h \
+ module-formats.h
+
+EXTRA_DIST = meson.build
diff --git a/src/fe-common/irc/notifylist/Makefile.in b/src/fe-common/irc/notifylist/Makefile.in
new file mode 100644
index 0000000..733e022
--- /dev/null
+++ b/src/fe-common/irc/notifylist/Makefile.in
@@ -0,0 +1,725 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/fe-common/irc/notifylist
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \
+ $(top_srcdir)/m4/glibtests.m4 $(top_srcdir)/m4/libgcrypt.m4 \
+ $(top_srcdir)/m4/libotr.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am \
+ $(pkginc_fe_common_irc_notifylist_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/irssi-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libfe_irc_notifylist_a_AR = $(AR) $(ARFLAGS)
+libfe_irc_notifylist_a_LIBADD =
+am_libfe_irc_notifylist_a_OBJECTS = fe-notifylist.$(OBJEXT) \
+ module-formats.$(OBJEXT)
+libfe_irc_notifylist_a_OBJECTS = $(am_libfe_irc_notifylist_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES =
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/fe-notifylist.Po \
+ ./$(DEPDIR)/module-formats.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libfe_irc_notifylist_a_SOURCES)
+DIST_SOURCES = $(libfe_irc_notifylist_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)"
+HEADERS = $(pkginc_fe_common_irc_notifylist_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHAT_MODULES = @CHAT_MODULES@
+COMMON_LIBS = @COMMON_LIBS@
+COMMON_NOUI_LIBS = @COMMON_NOUI_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FUZZER_LIBS = @FUZZER_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOTR_CFLAGS = @LIBOTR_CFLAGS@
+LIBOTR_LIBS = @LIBOTR_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+OTR_CFLAGS = @OTR_CFLAGS@
+OTR_LDFLAGS = @OTR_LDFLAGS@
+OTR_LINK_FLAGS = @OTR_LINK_FLAGS@
+OTR_LINK_LIBS = @OTR_LINK_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL_CFLAGS = @PERL_CFLAGS@
+PERL_EXTRA_OPTS = @PERL_EXTRA_OPTS@
+PERL_FE_LINK_LIBS = @PERL_FE_LINK_LIBS@
+PERL_LDFLAGS = @PERL_LDFLAGS@
+PERL_LINK_FLAGS = @PERL_LINK_FLAGS@
+PERL_LINK_LIBS = @PERL_LINK_LIBS@
+PERL_MM_OPT = @PERL_MM_OPT@
+PERL_MM_PARAMS = @PERL_MM_PARAMS@
+PERL_STATIC_LIBS = @PERL_STATIC_LIBS@
+PERL_USE_LIB = @PERL_USE_LIB@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROG_LIBS = @PROG_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TEXTUI_LIBS = @TEXTUI_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+installed_test_metadir = @installed_test_metadir@
+installed_testdir = @installed_testdir@
+irc_MODULES = @irc_MODULES@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+otr_module_lib = @otr_module_lib@
+otr_static_lib = @otr_static_lib@
+pdfdir = @pdfdir@
+perl_module_fe_lib = @perl_module_fe_lib@
+perl_module_lib = @perl_module_lib@
+perl_static_fe_lib = @perl_static_fe_lib@
+perl_static_lib = @perl_static_lib@
+perlpath = @perlpath@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sedpath = @sedpath@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LIBRARIES = libfe_irc_notifylist.a
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DHELPDIR=\""$(datadir)/irssi/help"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\"
+
+libfe_irc_notifylist_a_SOURCES = \
+ fe-notifylist.c \
+ module-formats.c
+
+pkginc_fe_common_irc_notifylistdir = $(pkgincludedir)/src/fe-common/irc/notifylist
+pkginc_fe_common_irc_notifylist_HEADERS = \
+ module.h \
+ module-formats.h
+
+EXTRA_DIST = meson.build
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/fe-common/irc/notifylist/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/fe-common/irc/notifylist/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libfe_irc_notifylist.a: $(libfe_irc_notifylist_a_OBJECTS) $(libfe_irc_notifylist_a_DEPENDENCIES) $(EXTRA_libfe_irc_notifylist_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libfe_irc_notifylist.a
+ $(AM_V_AR)$(libfe_irc_notifylist_a_AR) libfe_irc_notifylist.a $(libfe_irc_notifylist_a_OBJECTS) $(libfe_irc_notifylist_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libfe_irc_notifylist.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fe-notifylist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module-formats.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_fe_common_irc_notifylistHEADERS: $(pkginc_fe_common_irc_notifylist_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_fe_common_irc_notifylist_HEADERS)'; test -n "$(pkginc_fe_common_irc_notifylistdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_fe_common_irc_notifylistHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_fe_common_irc_notifylist_HEADERS)'; test -n "$(pkginc_fe_common_irc_notifylistdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_fe_common_irc_notifylistdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/fe-notifylist.Po
+ -rm -f ./$(DEPDIR)/module-formats.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_fe_common_irc_notifylistHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/fe-notifylist.Po
+ -rm -f ./$(DEPDIR)/module-formats.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_fe_common_irc_notifylistHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_fe_common_irc_notifylistHEADERS \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-pkginc_fe_common_irc_notifylistHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/fe-common/irc/notifylist/fe-notifylist.c b/src/fe-common/irc/notifylist/fe-notifylist.c
new file mode 100644
index 0000000..68b98a0
--- /dev/null
+++ b/src/fe-common/irc/notifylist/fe-notifylist.c
@@ -0,0 +1,250 @@
+/*
+ fe-notifylist.c : irssi
+
+ Copyright (C) 1999-2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/irc/notifylist/module-formats.h>
+#include <irssi/src/core/signals.h>
+#include <irssi/src/core/commands.h>
+#include <irssi/src/core/misc.h>
+#include <irssi/src/core/chatnets.h>
+#include <irssi/src/lib-config/iconfig.h>
+#include <irssi/src/core/settings.h>
+
+#include <irssi/src/core/levels.h>
+#include <irssi/src/irc/core/irc-servers.h>
+#include <irssi/src/irc/core/irc-chatnets.h>
+#include <irssi/src/irc/notifylist/notifylist.h>
+
+#include <irssi/src/fe-common/core/themes.h>
+#include <irssi/src/fe-common/core/printtext.h>
+
+/* add the nick of a hostmask to list if it isn't there already */
+static GSList *mask_add_once(GSList *list, const char *mask)
+{
+ char *str, *ptr;
+
+ g_return_val_if_fail(mask != NULL, NULL);
+
+ ptr = strchr(mask, '!');
+ str = ptr == NULL ? g_strdup(mask) :
+ g_strndup(mask, (int) (ptr-mask));
+
+ if (i_slist_find_icase_string(list, str) == NULL)
+ return g_slist_append(list, str);
+
+ g_free(str);
+ return list;
+}
+
+/* search for online people, print them and update offline list */
+static void print_notify_onserver(IRC_SERVER_REC *server, GSList *nicks,
+ GSList **offline, const char *desc)
+{
+ GSList *tmp;
+ GString *str;
+
+ g_return_if_fail(IS_IRC_SERVER(server));
+ g_return_if_fail(offline != NULL);
+ g_return_if_fail(desc != NULL);
+
+ str = g_string_new(NULL);
+ for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
+ char *nick = tmp->data;
+
+ if (!notifylist_ison_server(server, nick))
+ continue;
+
+ g_string_append_printf(str, "%s, ", nick);
+ *offline = g_slist_remove(*offline, nick);
+ }
+
+ if (str->len > 0) {
+ g_string_truncate(str, str->len-2);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_ONLINE, desc, str->str);
+ }
+
+ g_string_free(str, TRUE);
+}
+
+/* show the notify list, displaying who is on which net */
+static void cmd_notify_show(void)
+{
+ GSList *nicks, *offline, *tmp;
+ IRC_SERVER_REC *server;
+
+ if (notifies == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NOTIFY_LIST_EMPTY);
+ return;
+ }
+
+ /* build a list containing only the nicks */
+ nicks = NULL;
+ for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
+ NOTIFYLIST_REC *rec = tmp->data;
+
+ nicks = mask_add_once(nicks, rec->mask);
+ }
+ offline = g_slist_copy(nicks);
+
+ /* print the notifies on specific ircnets */
+ for (tmp = chatnets; tmp != NULL; tmp = tmp->next) {
+ IRC_CHATNET_REC *rec = tmp->data;
+
+ if (!IS_IRCNET(rec))
+ continue;
+
+ server = (IRC_SERVER_REC *) server_find_chatnet(rec->name);
+ if (!IS_IRC_SERVER(server))
+ continue;
+
+ print_notify_onserver(server, nicks, &offline, rec->name);
+ }
+
+ /* print the notifies on servers without a specified ircnet */
+ for (tmp = servers; tmp != NULL; tmp = tmp->next) {
+ server = tmp->data;
+
+ if (!IS_IRC_SERVER(server) || server->connrec->chatnet != NULL)
+ continue;
+ print_notify_onserver(server, nicks, &offline, server->tag);
+ }
+
+ /* print offline people */
+ if (offline != NULL) {
+ GString *str;
+
+ str = g_string_new(NULL);
+ for (tmp = offline; tmp != NULL; tmp = tmp->next)
+ g_string_append_printf(str, "%s, ", (char *) tmp->data);
+
+ g_string_truncate(str, str->len-2);
+ printformat(NULL,NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_OFFLINE, str->str);
+ g_string_free(str, TRUE);
+
+ g_slist_free(offline);
+ }
+
+ g_slist_foreach(nicks, (GFunc) g_free, NULL);
+ g_slist_free(nicks);
+}
+
+static void notifylist_print(NOTIFYLIST_REC *rec)
+{
+ char *ircnets;
+
+ ircnets = rec->ircnets == NULL ? NULL :
+ g_strjoinv(",", rec->ircnets);
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NOTIFY_LIST,
+ rec->mask, ircnets != NULL ? ircnets : "",
+ rec->away_check ? "-away" : "");
+
+ g_free_not_null(ircnets);
+}
+
+static void cmd_notifylist_show(void)
+{
+ if (notifies == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NOTIFY_LIST_EMPTY);
+ } else {
+ g_slist_foreach(notifies, (GFunc) notifylist_print, NULL);
+ }
+}
+
+static void cmd_notify(const char *data)
+{
+ if (*data == '\0') {
+ cmd_notify_show();
+ signal_stop();
+ }
+
+ if (g_ascii_strncasecmp(data, "-list", 4) == 0) {
+ cmd_notifylist_show();
+ signal_stop();
+ }
+}
+
+static void notifylist_joined(IRC_SERVER_REC *server, const char *nick,
+ const char *username, const char *host,
+ const char *realname, const char *awaymsg)
+{
+ g_return_if_fail(nick != NULL);
+
+ printformat(server, nick, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NOTIFY_JOIN, nick, username, host, realname,
+ server->connrec->chatnet == NULL ? "IRC" : server->connrec->chatnet);
+}
+
+static void notifylist_left(IRC_SERVER_REC *server, const char *nick,
+ const char *username, const char *host,
+ const char *realname, const char *awaymsg)
+{
+ g_return_if_fail(nick != NULL);
+
+ printformat(server, nick, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOTIFY_PART,
+ nick, username, host, realname,
+ server->connrec->chatnet == NULL ? "IRC" : server->connrec->chatnet);
+}
+
+static void notifylist_away(IRC_SERVER_REC *server, const char *nick,
+ const char *username, const char *host,
+ const char *realname, const char *awaymsg)
+{
+ g_return_if_fail(nick != NULL);
+
+ if (awaymsg != NULL) {
+ printformat(server, nick, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NOTIFY_AWAY, nick, username, host, realname, awaymsg,
+ server->connrec->chatnet == NULL ? "IRC" : server->connrec->chatnet);
+ } else {
+ printformat(server, nick, MSGLEVEL_CLIENTNOTICE,
+ IRCTXT_NOTIFY_UNAWAY, nick, username, host, realname,
+ server->connrec->chatnet == NULL ? "IRC" : server->connrec->chatnet);
+ }
+}
+
+void fe_irc_notifylist_init(void)
+{
+ theme_register(fecommon_irc_notifylist_formats);
+
+ command_bind("notify", NULL, (SIGNAL_FUNC) cmd_notify);
+ signal_add("notifylist joined", (SIGNAL_FUNC) notifylist_joined);
+ signal_add("notifylist left", (SIGNAL_FUNC) notifylist_left);
+ signal_add("notifylist away changed", (SIGNAL_FUNC) notifylist_away);
+
+ command_set_options("notify", "list");
+
+ settings_check();
+ module_register("notifylist", "fe-irc");
+}
+
+void fe_irc_notifylist_deinit(void)
+{
+ theme_unregister();
+
+ command_unbind("notify", (SIGNAL_FUNC) cmd_notify);
+ signal_remove("notifylist joined", (SIGNAL_FUNC) notifylist_joined);
+ signal_remove("notifylist left", (SIGNAL_FUNC) notifylist_left);
+ signal_remove("notifylist away changed", (SIGNAL_FUNC) notifylist_away);
+}
+
+MODULE_ABICHECK(fe_irc_notifylist)
diff --git a/src/fe-common/irc/notifylist/meson.build b/src/fe-common/irc/notifylist/meson.build
new file mode 100644
index 0000000..2e66c78
--- /dev/null
+++ b/src/fe-common/irc/notifylist/meson.build
@@ -0,0 +1,21 @@
+# this file is part of irssi
+
+libfe_irc_notifylist_a = static_library('fe_irc_notifylist',
+ files(
+ 'fe-notifylist.c',
+ 'module-formats.c',
+ ),
+ include_directories : rootinc,
+ implicit_include_directories : false,
+ c_args : [
+ def_helpdir,
+ def_sysconfdir,
+ ],
+ dependencies : dep)
+
+install_headers(
+ files(
+ 'module-formats.h',
+ 'module.h',
+ ),
+ subdir : incdir / 'src' / 'fe-common' / 'irc' / 'notifylist')
diff --git a/src/fe-common/irc/notifylist/module-formats.c b/src/fe-common/irc/notifylist/module-formats.c
new file mode 100644
index 0000000..12f41fb
--- /dev/null
+++ b/src/fe-common/irc/notifylist/module-formats.c
@@ -0,0 +1,41 @@
+/*
+ module-formats.c : irssi
+
+ Copyright (C) 2000 Timo Sirainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "module.h"
+#include <irssi/src/fe-common/core/formats.h>
+
+FORMAT_REC fecommon_irc_notifylist_formats[] =
+{
+ { MODULE_NAME, "Notifylist", 0 },
+
+ /* ---- */
+ { NULL, "Notifylist", 0 },
+
+ { "notify_join", "{nick $0} [$1@$2] [{hilight $3}] has joined to $4", 5, { 0, 0, 0, 0, 0 } },
+ { "notify_part", "{nick $0} has left $4", 5, { 0, 0, 0, 0, 0 } },
+ { "notify_away", "{nick $0} [$5] [$1@$2] [{hilight $3}] is now away: $4", 6, { 0, 0, 0, 0, 0, 0 } },
+ { "notify_unaway", "{nick $0} [$4] [$1@$2] [{hilight $3}] is now unaway", 5, { 0, 0, 0, 0, 0 } },
+ { "notify_online", "On $0: {hilight $1}", 2, { 0, 0 } },
+ { "notify_offline", "Offline: $0", 1, { 0 } },
+ { "notify_list", "$0: $1 $2", 4, { 0, 0, 0, 0 } },
+ { "notify_list_empty", "The notify list is empty", 0 },
+
+ { NULL, NULL, 0 },
+};
diff --git a/src/fe-common/irc/notifylist/module-formats.h b/src/fe-common/irc/notifylist/module-formats.h
new file mode 100644
index 0000000..ff3085e
--- /dev/null
+++ b/src/fe-common/irc/notifylist/module-formats.h
@@ -0,0 +1,18 @@
+#include <irssi/src/fe-common/core/formats.h>
+
+enum {
+ IRCTXT_MODULE_NAME,
+
+ IRCTXT_FILL_1,
+
+ IRCTXT_NOTIFY_JOIN,
+ IRCTXT_NOTIFY_PART,
+ IRCTXT_NOTIFY_AWAY,
+ IRCTXT_NOTIFY_UNAWAY,
+ IRCTXT_NOTIFY_ONLINE,
+ IRCTXT_NOTIFY_OFFLINE,
+ IRCTXT_NOTIFY_LIST,
+ IRCTXT_NOTIFY_LIST_EMPTY
+};
+
+extern FORMAT_REC fecommon_irc_notifylist_formats[];
diff --git a/src/fe-common/irc/notifylist/module.h b/src/fe-common/irc/notifylist/module.h
new file mode 100644
index 0000000..0e5ca45
--- /dev/null
+++ b/src/fe-common/irc/notifylist/module.h
@@ -0,0 +1,4 @@
+#include <irssi/src/common.h>
+#include <irssi/src/irc/core/irc.h>
+
+#define MODULE_NAME "fe-common/irc/notifylist"