Compare commits

..

1 Commits

Author SHA1 Message Date
cd72f2a55b Python: Use iterator for get_list() 2013-09-25 21:11:24 -04:00
417 changed files with 132177 additions and 133012 deletions

46
.gitignore vendored
View File

@ -2,49 +2,47 @@
# Unix generated files
.deps/
.libs/
.dirstamp
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
/build-aux/
compile
confdefs.h
conftest
conftest.c
conftest.err
config.*
config-win32.h
config.guess
config.h.in
config.h
config.log
config.status
config.sub
configure
configure.tmp
depcomp
doxygen*.tmp
html/
install-sh
intl/
libtool
ltmain.sh
m4/
missing
plugins/perl/irc.pm.h
plugins/perl/xchat.pm.h
plugins/perl/hexchat.pm.h
po/Makefile.in.in
po/POTFILES
po/remove-potcdate.sed
po/stamp-*
osx/Info.plist
data/man/hexchat.1
data/pkgconfig/hexchat-plugin.pc
data/misc/hexchat.appdata.xml
data/misc/hexchat.desktop
data/misc/hexchat.desktop.in
data/misc/htm.desktop
po/stamp-po
share/pkgconfig/hexchat-plugin.pc
src/common/dbus/example
src/common/dbus/marshallers.h
src/common/dbus/org.hexchat.service.service
src/common/dbus/remote-object-glue.h
src/common/make-te
src/common/marshal.*
src/common/textenums.h
src/common/textevents.h
src/fe-gtk/hexchat
src/fe-gtk/hexchat.rc
src/fe-gtk/resources.c
src/fe-gtk/resources.h
src/fe-text/hexchat-text
src/htm/Main.resources
src/htm/thememan.exe
@ -59,31 +57,19 @@ stamp-h1
*.gmo
*.mo
*.po~
*.pot
*.patch
tags
src/**/*.plist
# Win32 generated files
plugins/wmpa/wmpa_h.h
plugins/wmpa/wmpa_i.c
src/pixmaps/inline_pngs.h
src/htm/obj/*
win32/ipch/*
win32/ext/perl/perl-x86-cache
win32/ext/perl/perl-x86-SetupFiles
win32/ext/perl/perl-x64-cache
win32/ext/perl/perl-x64-SetupFiles
win32/installer/hexchat.iss
resource.h
*.opensdf
*.sdf
*.suo
*.user
*.exe
#OSX
osx/HexChat.app
osx/.HexChat.app
po/.intltool-merge-cache
*.zip
*.dmg
*.VC.db
*.VC.opendb

View File

@ -1,10 +0,0 @@
Berke Viktor <github.bviktor@outlook.com> <berkeviktor@aol.com>
Berke Viktor <github.bviktor@outlook.com> <bviktor@hexchat.org>
Berke Viktor <github.bviktor@outlook.com> <bviktor@outlook.com>
Berke Viktor <github.bviktor@outlook.com> berkeviktor@aol.com
Patrick Griffis <tingping@tingping.se> TingPing <tingping@fedoraproject.org>
Patrick Griffis <tingping@tingping.se> TingPing <tingping@tingping.se>
Patrick Griffis <tingping@tingping.se> TingPing <tngpng@gmail.com>
Patrick Griffis <tingping@tingping.se> TingPing <TingPing@users.noreply.github.com>
Arnav Singh <arnavion@gmail.com> Arnavion
Eustachy Kapusta <Eustachy.kapusta@gmail.com> tomek

View File

@ -1,36 +1,14 @@
sudo: required
dist: trusty
language: c
cache: apt
compiler: clang
script:
- ./autogen.sh --enable-textfe --with-theme-manager --enable-static-analysis
- make V=1 -j$(nproc)
compiler: gcc
before_script:
- sudo apt-get build-dep -qq xchat
- sudo apt-get install -qq libnotify-dev libproxy-dev libpci-dev libcanberra-dev monodevelop
script:
- ./autogen.sh
- ./configure --enable-textfe --with-theme-manager
- make
notifications:
irc:
channels: "chat.freenode.net#hexchat-devel"
template: "Build %{build_url} (%{commit} in %{branch}) by %{author}: %{message}"
template: "Build #%{build_number} (%{commit}) by %{author}: %{message}"
on_success: change
matrix:
fast_finish: true
addons:
apt:
packages:
- automake
- autoconf-archive
- imagemagick
- intltool
- libcanberra-dev
- libdbus-glib-1-dev
- libglib2.0-dev
- libgtk2.0-dev
- libluajit-5.1-dev
- libnotify-dev
- libpci-dev
- libperl-dev
- libproxy-dev
- libssl-dev
- libtool
- monodevelop
- mono-devel
- python-dev

View File

@ -2,6 +2,7 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = po src plugins data
SUBDIRS = po intl src plugins man share
EXTRA_DIST = autogen.sh
EXTRA_DIST = autogen.sh Doxyfile readme.md

View File

@ -1,32 +1,113 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
#!/bin/bash
have_automake=false
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
(test -f $srcdir/src/common/hexchat.c) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the top-level directory"
exit 1
}
if [ "$1" = "--copy" ]; then
shift
aclocal --force --install || exit 1
intltoolize --force --copy --automake || exit 1
autoreconf --force --install --include=m4 -Wno-portability || exit 1
if automake --version < /dev/null > /dev/null 2>&1 ; then
automake_version=`automake --version | grep 'automake (GNU automake)' | sed 's/^[^0-9]*\(.*\)/\1/'`
case $automake_version in
1.2*|1.3*|1.4|1.4*|1.5*|1.6*|1.7*|1.8*)
;;
*)
have_automake=true
;;
esac
fi
if $have_automake ; then
AUTOMAKE="automake"
ACLOCAL="aclocal"
else
intltoolize --automake || exit 1
autoreconf --install --symlink --include=m4 -Wno-portability || exit 1
if automake-1.9 --version < /dev/null > /dev/null 2>&1 ; then
AUTOMAKE="automake-1.9"
ACLOCAL="aclocal-1.9"
else
echo "automake missing or too old. This requires at least automake 1.9"
exit 1
fi
fi
if [ "$NOCONFIGURE" = "" ]; then
$srcdir/configure "$@" || exit 1
# ------ START GETTEXT ------
if [ "$1" = "--help" ]; then exit 0 else
echo "Now type \`make\' to compile" || exit 1
fi
else
echo "Skipping configure process."
echo searching for GNU gettext intl directory...
dirs="/usr/share /usr/local/share /opt/share /usr /usr/local /opt /usr/gnu/share /opt/local /opt/local/share"
found=0
for try in $dirs; do
echo -n " -> $try/gettext/intl... "
if test -d $try/gettext/intl; then
echo found it
found=1
break
fi
echo no
done
if test "$found" != 1; then
echo ERROR: Cannot find gettext/intl directory.
echo ERROR: Install GNU gettext in /usr or /usr/local prefix.
exit 7
fi;
echo copying gettext intl files...
if test -f $try/gettext/mkinstalldirs; then
ln -s $try/gettext/mkinstalldirs mkinstalldirs
fi
intldir="$try/gettext/intl"
if test ! -d intl; then
mkdir intl
fi
olddir=`pwd`
cd $intldir
for file in *; do
if test $file != COPYING.LIB-2.0 && test $file != COPYING.LIB-2.1; then
rm -f $olddir/intl/$file
cp $intldir/$file $olddir/intl/
fi
done
cp -f $try/gettext/po/Makefile.in.in $olddir/po/
cd $olddir
if test -f intl/plural.c; then
sleep 2
touch intl/plural.c
fi
set +x
# ------ END GETTEXT ------
echo running $ACLOCAL...
$ACLOCAL $ACLOCAL_FLAGS
if test "$?" != "0"; then
echo aclocal failed, stopping.
exit 2
fi
echo running libtoolize...
libtoolize --copy --force --install
if test "$?" != "0"; then
echo libtoolize failed, stopping.
exit 3
fi
echo running autoheader...
autoheader
if test "$?" != "0"; then
echo autoheader failed, stopping.
exit 4
fi
echo running $AUTOMAKE...
$AUTOMAKE -a -c
if test "$?" != "0"; then
echo automake failed, stopping.
exit 5
fi
echo running autoconf...
autoconf
if test "$?" != "0"; then
echo autoconf failed, stopping.
exit 6
fi
echo if no errors occured, run ./configure
exit 0
#autogen.sh generates:
# aclocal.m4 Makefile.in config.guess config.sub ltmain.sh
# configure install-sh missing mkinstalldirs depcomp
#
#configure generates:
# config.status libtool Makefile.in

View File

@ -1,14 +1,18 @@
#define LOCALEDIR ".\\share\\locale"
#define ENABLE_NLS
#define USE_GMODULE
#define USE_PLUGIN
#define USE_OPENSSL
#define USE_LIBSEXY
#define USE_IPV6
#define HAVE_ISO_CODES
#define ISO_CODES_PREFIX ".\\"
#define ISO_CODES_LOCALEDIR LOCALEDIR
#define PACKAGE_NAME "hexchat"
#define PACKAGE_VERSION "<#= [string]::Join('.', $versionParts) #>"
#define PACKAGE_VERSION "2.9.6"
#define HEXCHATLIBDIR ".\\plugins"
#define HEXCHATSHAREDIR "."
#define OLD_PERL
#define GETTEXT_PACKAGE "hexchat"
#define PACKAGE_TARNAME "hexchat-<#= [string]::Join('.', $versionParts) #>"
#define PACKAGE_TARNAME "hexchat-2.9.6"
#ifndef USE_IPV6
#define socklen_t int
#endif

672
config.rpath Normal file
View File

@ -0,0 +1,672 @@
#! /bin/sh
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
# Copyright 1996-2010 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
# This file 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.
#
# The first argument passed to this file is the canonical host specification,
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
# should be set by the caller.
#
# The set of defined variables is at the end of this script.
# Known limitations:
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
# than 256 bytes, otherwise the compiler driver will dump core. The only
# known workaround is to choose shorter directory names for the build
# directory and/or the installation directory.
# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
shrext=.so
host="$1"
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
# Code taken from libtool.m4's _LT_CC_BASENAME.
for cc_temp in $CC""; do
case $cc_temp in
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
\-*) ;;
*) break;;
esac
done
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
# Code taken from libtool.m4's _LT_COMPILER_PIC.
wl=
if test "$GCC" = yes; then
wl='-Wl,'
else
case "$host_os" in
aix*)
wl='-Wl,'
;;
darwin*)
case $cc_basename in
xlc*)
wl='-Wl,'
;;
esac
;;
mingw* | cygwin* | pw32* | os2* | cegcc*)
;;
hpux9* | hpux10* | hpux11*)
wl='-Wl,'
;;
irix5* | irix6* | nonstopux*)
wl='-Wl,'
;;
newsos6)
;;
linux* | k*bsd*-gnu)
case $cc_basename in
ecc*)
wl='-Wl,'
;;
icc* | ifort*)
wl='-Wl,'
;;
lf95*)
wl='-Wl,'
;;
pgcc | pgf77 | pgf90)
wl='-Wl,'
;;
ccc*)
wl='-Wl,'
;;
como)
wl='-lopt='
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
wl='-Wl,'
;;
esac
;;
esac
;;
osf3* | osf4* | osf5*)
wl='-Wl,'
;;
rdos*)
;;
solaris*)
wl='-Wl,'
;;
sunos4*)
wl='-Qoption ld '
;;
sysv4 | sysv4.2uw2* | sysv4.3*)
wl='-Wl,'
;;
sysv4*MP*)
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
wl='-Wl,'
;;
unicos*)
wl='-Wl,'
;;
uts4*)
;;
esac
fi
# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
hardcode_libdir_flag_spec=
hardcode_libdir_separator=
hardcode_direct=no
hardcode_minus_L=no
case "$host_os" in
cygwin* | mingw* | pw32* | cegcc*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
if test "$GCC" != yes; then
with_gnu_ld=no
fi
;;
interix*)
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
openbsd*)
with_gnu_ld=no
;;
esac
ld_shlibs=yes
if test "$with_gnu_ld" = yes; then
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
# Unlike libtool, we use -rpath here, not --rpath, since the documented
# option of GNU ld is called -rpath, not --rpath.
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
case "$host_os" in
aix[3-9]*)
# On AIX/PPC, the GNU linker is very broken
if test "$host_cpu" != ia64; then
ld_shlibs=no
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
# that the semantics of dynamic libraries on AmigaOS, at least up
# to version 4, is to share data among multiple programs linked
# with the same dynamic library. Since this doesn't match the
# behavior of shared libraries on other platforms, we cannot use
# them.
ld_shlibs=no
;;
beos*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
cygwin* | mingw* | pw32* | cegcc*)
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
interix[3-9]*)
hardcode_direct=no
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
gnu* | linux* | k*bsd*-gnu)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
netbsd*)
;;
solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs=no
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
ld_shlibs=no
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
else
ld_shlibs=no
fi
;;
esac
;;
sunos4*)
hardcode_direct=yes
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
esac
if test "$ld_shlibs" = no; then
hardcode_libdir_flag_spec=
fi
else
case "$host_os" in
aix3*)
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
if test "$GCC" = yes; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
fi
;;
aix[4-9]*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
for ld_flag in $LDFLAGS; do
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
aix_use_runtimelinking=yes
break
fi
done
;;
esac
fi
hardcode_direct=yes
hardcode_libdir_separator=':'
if test "$GCC" = yes; then
case $host_os in aix4.[012]|aix4.[012].*)
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" && \
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
hardcode_direct=unsupported
hardcode_minus_L=yes
hardcode_libdir_flag_spec='-L$libdir'
hardcode_libdir_separator=
fi
;;
esac
fi
# Begin _LT_AC_SYS_LIBPATH_AIX.
echo 'int main () { return 0; }' > conftest.c
${CC} ${LDFLAGS} conftest.c -o conftest
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
if test -z "$aix_libpath"; then
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
fi
if test -z "$aix_libpath"; then
aix_libpath="/usr/lib:/lib"
fi
rm -f conftest.c conftest
# End _LT_AC_SYS_LIBPATH_AIX.
if test "$aix_use_runtimelinking" = yes; then
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
else
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
fi
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# see comment about different semantics on the GNU ld section
ld_shlibs=no
;;
bsdi[45]*)
;;
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec=' '
libext=lib
;;
darwin* | rhapsody*)
hardcode_direct=no
if test "$GCC" = yes ; then
:
else
case $cc_basename in
xlc*)
;;
*)
ld_shlibs=no
;;
esac
fi
;;
dgux*)
hardcode_libdir_flag_spec='-L$libdir'
;;
freebsd1*)
ld_shlibs=no
;;
freebsd2.2*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
freebsd2*)
hardcode_direct=yes
hardcode_minus_L=yes
;;
freebsd* | dragonfly*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
hpux9*)
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
hpux10*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
fi
;;
hpux11*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
case $host_cpu in
hppa*64*|ia64*)
hardcode_direct=no
;;
*)
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
esac
fi
;;
irix5* | irix6* | nonstopux*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
netbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
newsos6)
hardcode_direct=yes
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
else
case "$host_os" in
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
hardcode_libdir_flag_spec='-R$libdir'
;;
*)
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
esac
fi
else
ld_shlibs=no
fi
;;
os2*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
osf3*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
osf4* | osf5*)
if test "$GCC" = yes; then
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
else
# Both cc and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
fi
hardcode_libdir_separator=:
;;
solaris*)
hardcode_libdir_flag_spec='-R$libdir'
;;
sunos4*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_direct=yes
hardcode_minus_L=yes
;;
sysv4)
case $host_vendor in
sni)
hardcode_direct=yes # is this really true???
;;
siemens)
hardcode_direct=no
;;
motorola)
hardcode_direct=no #Motorola manual says yes, but my tests say they lie
;;
esac
;;
sysv4.3*)
;;
sysv4*MP*)
if test -d /usr/nec; then
ld_shlibs=yes
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
;;
sysv5* | sco3.2v5* | sco5v6*)
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
hardcode_libdir_separator=':'
;;
uts4*)
hardcode_libdir_flag_spec='-L$libdir'
;;
*)
ld_shlibs=no
;;
esac
fi
# Check dynamic linker characteristics
# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
# only about the one the linker finds when passed -lNAME. This is the last
# element of library_names_spec in libtool.m4, or possibly two of them if the
# linker has special search rules.
library_names_spec= # the last element of library_names_spec in libtool.m4
libname_spec='lib$name'
case "$host_os" in
aix3*)
library_names_spec='$libname.a'
;;
aix[4-9]*)
library_names_spec='$libname$shrext'
;;
amigaos*)
library_names_spec='$libname.a'
;;
beos*)
library_names_spec='$libname$shrext'
;;
bsdi[45]*)
library_names_spec='$libname$shrext'
;;
cygwin* | mingw* | pw32* | cegcc*)
shrext=.dll
library_names_spec='$libname.dll.a $libname.lib'
;;
darwin* | rhapsody*)
shrext=.dylib
library_names_spec='$libname$shrext'
;;
dgux*)
library_names_spec='$libname$shrext'
;;
freebsd1*)
;;
freebsd* | dragonfly*)
case "$host_os" in
freebsd[123]*)
library_names_spec='$libname$shrext$versuffix' ;;
*)
library_names_spec='$libname$shrext' ;;
esac
;;
gnu*)
library_names_spec='$libname$shrext'
;;
hpux9* | hpux10* | hpux11*)
case $host_cpu in
ia64*)
shrext=.so
;;
hppa*64*)
shrext=.sl
;;
*)
shrext=.sl
;;
esac
library_names_spec='$libname$shrext'
;;
interix[3-9]*)
library_names_spec='$libname$shrext'
;;
irix5* | irix6* | nonstopux*)
library_names_spec='$libname$shrext'
case "$host_os" in
irix5* | nonstopux*)
libsuff= shlibsuff=
;;
*)
case $LD in
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
*) libsuff= shlibsuff= ;;
esac
;;
esac
;;
linux*oldld* | linux*aout* | linux*coff*)
;;
linux* | k*bsd*-gnu)
library_names_spec='$libname$shrext'
;;
knetbsd*-gnu)
library_names_spec='$libname$shrext'
;;
netbsd*)
library_names_spec='$libname$shrext'
;;
newsos6)
library_names_spec='$libname$shrext'
;;
nto-qnx*)
library_names_spec='$libname$shrext'
;;
openbsd*)
library_names_spec='$libname$shrext$versuffix'
;;
os2*)
libname_spec='$name'
shrext=.dll
library_names_spec='$libname.a'
;;
osf3* | osf4* | osf5*)
library_names_spec='$libname$shrext'
;;
rdos*)
;;
solaris*)
library_names_spec='$libname$shrext'
;;
sunos4*)
library_names_spec='$libname$shrext$versuffix'
;;
sysv4 | sysv4.3*)
library_names_spec='$libname$shrext'
;;
sysv4*MP*)
library_names_spec='$libname$shrext'
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
library_names_spec='$libname$shrext'
;;
uts4*)
library_names_spec='$libname$shrext'
;;
esac
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
# How to pass a linker flag through the compiler.
wl="$escaped_wl"
# Static library suffix (normally "a").
libext="$libext"
# Shared library suffix (normally "so").
shlibext="$shlibext"
# Format of library name prefix.
libname_spec="$escaped_libname_spec"
# Library names that the linker finds when passed -lNAME.
library_names_spec="$escaped_library_names_spec"
# Flag to hardcode \$libdir into a binary during linking.
# This must work even if \$libdir does not exist.
hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
# Whether we need a single -rpath flag with a separated argument.
hardcode_libdir_separator="$hardcode_libdir_separator"
# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
# resulting binary.
hardcode_direct="$hardcode_direct"
# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
# resulting binary.
hardcode_minus_L="$hardcode_minus_L"
EOF

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
SUBDIRS =
if DO_PLUGIN
SUBDIRS += pkgconfig
endif
if DO_GTK
SUBDIRS += icons misc man
else
if WITH_TM
SUBDIRS += misc
endif
endif
EXTRA_DIST = \
hexchat.gresource.xml

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/icons">
<file alias="hexchat.png" preprocess="to-pixdata" compressed="true">icons/hexchat.png</file>
<file alias="book.png" preprocess="to-pixdata" compressed="true">icons/book.png</file>
<file alias="ulist_voice.png" preprocess="to-pixdata" compressed="true">icons/ulist_voice.png</file>
<file alias="ulist_halfop.png" preprocess="to-pixdata" compressed="true">icons/ulist_halfop.png</file>
<file alias="ulist_op.png" preprocess="to-pixdata" compressed="true">icons/ulist_op.png</file>
<file alias="ulist_owner.png" preprocess="to-pixdata" compressed="true">icons/ulist_owner.png</file>
<file alias="ulist_founder.png" preprocess="to-pixdata" compressed="true">icons/ulist_founder.png</file>
<file alias="ulist_netop.png" preprocess="to-pixdata" compressed="true">icons/ulist_netop.png</file>
<file alias="tray_fileoffer.png" preprocess="to-pixdata" compressed="true">icons/tray_fileoffer.png</file>
<file alias="tray_highlight.png" preprocess="to-pixdata" compressed="true">icons/tray_highlight.png</file>
<file alias="tray_message.png" preprocess="to-pixdata" compressed="true">icons/tray_message.png</file>
<file alias="tree_channel.png" preprocess="to-pixdata">icons/tree_channel.png</file>
<file alias="tree_dialog.png" preprocess="to-pixdata" compressed="true">icons/tree_dialog.png</file>
<file alias="tree_server.png" preprocess="to-pixdata" compressed="true">icons/tree_server.png</file>
<file alias="tree_util.png" preprocess="to-pixdata" compressed="true">icons/tree_util.png</file>
</gresource>
</gresources>

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
height="64"
width="64">
<metadata>
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Guglielmi David</dc:title>
</cc:Agent>
</dc:creator>
<cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
<dc:rights>
<cc:Agent>
<dc:title>Peter Zelezny</dc:title>
</cc:Agent>
</dc:rights>
<dc:contributor>
<cc:Agent>
<dc:title>Samuel Messner</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:requires rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires rdf:resource="http://web.resource.org/cc/SourceCode" />
<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs>
<linearGradient id="hexchatGradient" x1="0" y1="1" x2="0" y2="0">
<stop id="hgRedStop" offset="0" style="stop-color: #FF2600; stop-opacity: 1;" />
<stop id="hgYellowStop" offset="1" style="stop-color: #FFD600; stop-opacity: 1;" />
</linearGradient>
<filter inkscape:collect="always" id="dropshadow">
<feGaussianBlur inkscape:collect="always" stdDeviation="1.9736701" id="dropshadowGaussian" />
</filter>
</defs>
<path
style="fill: #000000; fill-opacity: 1;"
d="m 31.62506,4.4248023 c -7.285288,0.0713 -14.595323,0.526836 -15.96875,1.3125 C 12.909458,7.3086297 -0.0321942,29.523731 6.0185229e-5,32.612303 0.0323162,35.700876 13.470952,57.688808 16.25006,59.206053 c 2.779105,1.517245 29.159399,1.258827 31.90625,-0.3125 2.746852,-1.571328 15.688504,-23.786428 15.65625,-26.875 C 63.7803,28.929981 50.372918,6.9107967 47.59381,5.3935523 46.204258,4.6349293 38.910347,4.3535003 31.62506,4.4248023 z m -0.1875,9.2500007 c 3.386631,-0.03246 6.676687,0.05409 8.75,0.28125 l -8.71875,9.71875 -9.0625,-9.5 c 2.055746,-0.283043 5.521157,-0.466366 9.03125,-0.5 z m 17.34375,9.84375 c 2.298293,3.744897 4.302354,7.392556 4.3125,8.34375 0.01126,1.055883 -2.358157,5.507241 -4.875,9.6875 l -9.03125,-8.03125 z m -34.46875,0.25 8.75,9.75 -8.1875,7.875 c -2.482342,-3.992634 -4.707927,-8.110307 -4.71875,-9.125 -0.01021,-0.95736 1.927117,-4.687748 4.15625,-8.5 z m 17.15625,16.90625 9.8125,9.21875 c -4.111037,0.67314 -16.108253,0.781873 -19.46875,0.125 z"
id="outline"
sodipodi:nodetypes="ssssssssscccscsccccccsccccc" />
<path
style="fill: url(#hexchatGradient); fill-opacity: 1;"
d="m 31.25006,6.4873027 c -6.857093,0.06521 -13.707297,0.469014 -15,1.1875 -2.585405,1.4369712 -14.780358,21.7692653 -14.75,24.5937503 0.03036,2.824486 12.665486,22.924987 15.28125,24.3125 2.615763,1.387513 27.445846,1.186972 30.03125,-0.25 2.585405,-1.436972 14.780359,-21.769265 14.75,-24.59375 C 61.5322,28.912818 48.897074,8.7810649 46.28131,7.3935527 44.973429,6.6997957 38.107152,6.4220967 31.25006,6.4873027 z m 0.0625,5.0625003 c 5.36199,-0.05245 10.696035,0.19201 11.71875,0.75 0.06132,0.03346 0.143803,0.127745 0.21875,0.1875 l -11.28125,12.59375 -0.5,0.53125 -0.46875,-0.53125 -11.75,-12.3125 c 0.10903,-0.09884 0.228263,-0.201843 0.3125,-0.25 1.010846,-0.577879 6.38801,-0.916306 11.75,-0.96875 z m 18.0625,9.46875 c 2.883844,4.661341 5.612556,9.652893 5.625,10.84375 0.01348,1.290331 -3.064699,7.087557 -6.09375,12.09375 l -11.09375,-9.90625 -0.53125,-0.46875 0.5,-0.46875 11.59375,-12.09375 z m -35.78125,0.03125 10.84375,12.0625 0.4375,0.46875 -0.46875,0.4375 -10.28125,9.90625 c -3.04689,-4.86606 -6.049362,-10.36778 -6.0625,-11.625 -0.01271,-1.216102 2.689239,-6.451996 5.53125,-11.25 z m 17.875,17.78125 0.4375,0.4375 12.34375,11.59375 c -0.318014,0.365376 -0.587006,0.638955 -0.78125,0.75 -2.02169,1.155758 -21.423322,1.397228 -23.46875,0.28125 -0.228202,-0.124506 -0.601742,-0.47821 -1,-0.9375 l 12,-11.6875 0.46875,-0.4375 z"
id="coloredX" />
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink"
height="64"
width="64">
<metadata>
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Guglielmi David</dc:title>
</cc:Agent>
</dc:creator>
<cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
<dc:rights>
<cc:Agent>
<dc:title>Peter Zelezny</dc:title>
</cc:Agent>
</dc:rights>
<dc:contributor>
<cc:Agent>
<dc:title>Samuel Messner</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:requires rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires rdf:resource="http://web.resource.org/cc/SourceCode" />
<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs>
<linearGradient id="hexchatGradient" x1="0" y1="0" x2="0" y2="1">
<stop id="hgYellowStop" offset="0" style="stop-color: #FFD600" />
<stop id="hgRedStop" offset="1" style="stop-color: #FF2600" />
</linearGradient>
</defs>
<use xlink:href="#outline" style="opacity:0.15" transform="translate(0,2)" id="shadow" />
<path
style="fill:#000000; fill-opacity: 1;"
d="M 31.71875,4.1088109 C 24.433462,4.1801109 17.123427,4.6356469 15.75,5.4213109 13.003148,6.9926379 0.06149557,29.207739 0.09374996,32.296311 0.12600597,35.384884 13.564642,57.372816 16.34375,58.890061 19.122855,60.407306 45.503149,60.148888 48.25,58.577561 50.996852,57.006233 63.938504,34.791133 63.90625,31.702561 63.87399,28.613989 50.466608,6.5948049 47.6875,5.0775609 46.297948,4.3189379 39.004037,4.0375089 31.71875,4.1088109 Z m -0.1875,9.2500001 c 3.386631,-0.03246 6.676687,0.05409 8.75,0.28125 l -8.71875,9.71875 -9.0625,-9.5 c 2.055746,-0.283043 5.521157,-0.466366 9.03125,-0.5 z m 17.34375,9.84375 c 2.298293,3.744897 4.302354,7.392556 4.3125,8.34375 0.01126,1.055883 -2.358157,5.507241 -4.875,9.6875 l -9.03125,-8.03125 z m -34.46875,0.25 8.75,9.75 -8.1875,7.875 c -2.482342,-3.992634 -4.707927,-8.110307 -4.71875,-9.125 -0.01021,-0.95736 1.927117,-4.687748 4.15625,-8.5 z m 17.15625,16.90625 9.8125,9.21875 c -4.111037,0.67314 -16.108253,0.781873 -19.46875,0.125 z"
id="outline" />
<path
style="fill:url(#hexchatGradient); fill-opacity: 1;"
d="m 31.34375,6.1713109 c -6.857093,0.06521 -13.707297,0.469014 -15,1.1875 C 13.758345,8.7957819 1.5633917,29.128076 1.5937497,31.952561 c 0.03036,2.824486 12.6654863,22.924987 15.2812503,24.3125 2.615763,1.387513 27.445846,1.186972 30.03125,-0.25 2.585405,-1.436972 14.780359,-21.769265 14.75,-24.59375 C 61.62589,28.596826 48.990764,8.4650729 46.375,7.0775609 45.067119,6.3838039 38.200842,6.1061049 31.34375,6.1713109 Z m 0.0625,5.0625001 c 5.36199,-0.05245 10.696035,0.19201 11.71875,0.75 0.06132,0.03346 0.143803,0.127745 0.21875,0.1875 l -11.28125,12.59375 -0.5,0.53125 -0.46875,-0.53125 -11.75,-12.3125 c 0.10903,-0.09884 0.228263,-0.201843 0.3125,-0.25 1.010846,-0.577879 6.38801,-0.916306 11.75,-0.96875 z m 18.0625,9.46875 c 2.883844,4.661341 5.612556,9.652893 5.625,10.84375 0.01348,1.290331 -3.064699,7.087557 -6.09375,12.09375 l -11.09375,-9.90625 -0.53125,-0.46875 0.5,-0.46875 11.59375,-12.09375 z m -35.78125,0.03125 10.84375,12.0625 0.4375,0.46875 -0.46875,0.4375 -10.28125,9.90625 c -3.04689,-4.86606 -6.0493623,-10.36778 -6.0625003,-11.625 -0.01271,-1.216102 2.6892393,-6.451996 5.5312503,-11.25 z m 17.875,17.78125 0.4375,0.4375 12.34375,11.59375 c -0.318014,0.365376 -0.587006,0.638955 -0.78125,0.75 -2.02169,1.155758 -21.423322,1.397228 -23.46875,0.28125 -0.228202,-0.124506 -0.601742,-0.47821 -1,-0.9375 l 12,-11.6875 0.46875,-0.4375 z"
id="coloredX" />
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,3 +0,0 @@
man_MANS = hexchat.1
EXTRA_DIST = hexchat.1.in

View File

@ -1,50 +0,0 @@
appdatadir = $(datadir)/appdata
appdata_in_files =
if DO_GTK
appdata_in_files += hexchat.appdata.xml.in
endif
appdata_DATA = $(appdata_in_files:.xml.in=.xml)
@INTLTOOL_XML_RULE@
if USE_DBUS
exec_command = 'hexchat --existing %U'
else
exec_command = 'hexchat %U'
endif
hexchat.desktop.in: hexchat.desktop.in.in
$(AM_V_GEN)sed -e s!\@exec_command\@!$(exec_command)! < $< > $@
data_desktopdir = $(datadir)/applications
data_desktop_in_files =
if DO_GTK
data_desktop_in_files += hexchat.desktop.in
endif
if WITH_TM
data_desktop_in_files += htm.desktop.in
mime_DATA = htm-mime.xml
mimedir = $(datadir)/mime/packages
endif
data_desktop_DATA = $(data_desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_DESKTOP_RULE@
UPDATE_MIME_DATABASE = update-mime-database "$(datadir)/mime" || :
UPDATE_DESKTOP_DATABASE = update-desktop-database -q "$(datadir)/applications" || :
install-data-hook:
$(UPDATE_MIME_DATABASE);
$(UPDATE_DESKTOP_DATABASE);
uninstall-hook:
$(UPDATE_MIME_DATABASE);
$(UPDATE_DESKTOP_DATABASE);
EXTRA_DIST = hexchat.appdata.xml.in hexchat.desktop.in.in htm.desktop.in htm-mime.xml
CLEANFILES = $(appdata_DATA) $(data_desktop_DATA) hexchat.desktop.in

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>hexchat.desktop</id>
<name>HexChat</name>
<developer_name>HexChat</developer_name>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-2.0+</project_license>
<translation type="gettext">hexchat</translation>
<summary>IRC Client</summary>
<description>
<_p>HexChat is an easy to use yet extensible IRC Client. It allows you to securely join multiple networks and talk to users privately or in channels using a customizable interface. You can even transfer files.</_p>
<_p>HexChat supports features such as: DCC, SASL, proxies, spellcheck, alerts, logging, custom themes, and Python/Perl scripts.</_p>
</description>
<url type="homepage">http://hexchat.github.io</url>
<url type="bugtracker">https://github.com/hexchat/hexchat</url>
<url type="translate">https://www.transifex.com/hexchat/hexchat</url>
<url type="donation">https://goo.gl/jESZvU</url>
<url type="help">https://hexchat.readthedocs.io/en/latest/</url>
<screenshots>
<screenshot type="default">
<image>http://i.imgur.com/tLMguQz.png</image>
<_caption>Main Chat Window</_caption>
</screenshot>
</screenshots>
<releases>
<release date="2016-12-10" version="2.12.4">
<description>
<p>This is another bug fix release:</p>
<ul>
<li>Fix issue with timers causing ping timeouts</li>
<li>Fix building against OpenSSL 1.1</li>
<li>Fix /exec output printing invalid utf8</li>
<li>Replace doat plugin with an internal command</li>
<li>Change how tab colors interact with plugins</li>
<li>Enable filtering the beep character by default</li>
</ul>
</description>
</release>
<release date="2016-10-22" version="2.12.3">
<description>
<p>This is a minor bug fix release just cleaning up a few issues:</p>
<ul>
<li>Fix crash with bad translations</li>
<li>Add new mhop command</li>
<li>Change ping timeout to 60 by default</li>
</ul>
</description>
</release>
</releases>
<kudos>
<kudo>UserDocs</kudo>
<kudo>HiDpiIcon</kudo>
<kudo>Notifications</kudo>
</kudos>
<update_contact>tingping_at_fedoraproject.org</update_contact>
</component>

View File

@ -1,18 +0,0 @@
[Desktop Entry]
_Name=HexChat
_GenericName=IRC Client
_Comment=Chat with other people online
_Keywords=IM;Chat;
Exec=@exec_command@
Icon=hexchat
Terminal=false
Type=Application
Categories=GTK;Network;IRCClient;
StartupNotify=true
X-GNOME-UsesNotifications=true
MimeType=x-scheme-handler/irc;x-scheme-handler/ircs;
Actions=SafeMode;
[Desktop Action SafeMode]
_Name=Open Safe Mode
Exec=hexchat --no-auto --no-plugins

View File

@ -1,124 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE])
#
# DESCRIPTION
#
# Check for the presence of an --enable-debug option to configure, with
# the specified default value used when the option is not present. Return
# the value in the variable $ax_enable_debug.
#
# Specifying 'yes' adds '-g -O0' to the compilation flags for all
# languages. Specifying 'info' adds '-g' to the compilation flags.
# Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to
# the linking flags. Otherwise, nothing is added.
#
# Define the variables listed in the second argument if debug is enabled,
# defaulting to no variables. Defines the variables listed in the third
# argument if debug is disabled, defaulting to NDEBUG. All lists of
# variables should be space-separated.
#
# If debug is not enabled, ensure AC_PROG_* will not add debugging flags.
# Should be invoked prior to any AC_PROG_* compiler checks.
#
# IS-RELEASE can be used to change the default to 'no' when making a
# release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it
# uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE
# macro, there is no need to pass this parameter.
#
# AX_IS_RELEASE([git-directory])
# AX_CHECK_ENABLE_DEBUG()
#
# LICENSE
#
# Copyright (c) 2011 Rhys Ulerich <rhys.ulerich@gmail.com>
# Copyright (c) 2014, 2015 Philip Withnall <philip@tecnocode.co.uk>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved.
#serial 5
AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[
AC_BEFORE([$0],[AC_PROG_CC])dnl
AC_BEFORE([$0],[AC_PROG_CXX])dnl
AC_BEFORE([$0],[AC_PROG_F77])dnl
AC_BEFORE([$0],[AC_PROG_FC])dnl
AC_MSG_CHECKING(whether to enable debugging)
ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1])))
ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],,
[$ax_is_release],
[$4])))
# If this is a release, override the default.
AS_IF([test "$ax_enable_debug_is_release" = "yes"],
[ax_enable_debug_default="no"])
m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))])
m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))])
AC_ARG_ENABLE(debug,
[AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])],
[],enable_debug=$ax_enable_debug_default)
# empty mean debug yes
AS_IF([test "x$enable_debug" = "x"],
[enable_debug="yes"])
# case of debug
AS_CASE([$enable_debug],
[yes],[
AC_MSG_RESULT(yes)
CFLAGS="${CFLAGS} -g -O0"
CXXFLAGS="${CXXFLAGS} -g -O0"
FFLAGS="${FFLAGS} -g -O0"
FCFLAGS="${FCFLAGS} -g -O0"
OBJCFLAGS="${OBJCFLAGS} -g -O0"
],
[info],[
AC_MSG_RESULT(info)
CFLAGS="${CFLAGS} -g"
CXXFLAGS="${CXXFLAGS} -g"
FFLAGS="${FFLAGS} -g"
FCFLAGS="${FCFLAGS} -g"
OBJCFLAGS="${OBJCFLAGS} -g"
],
[profile],[
AC_MSG_RESULT(profile)
CFLAGS="${CFLAGS} -g -pg"
CXXFLAGS="${CXXFLAGS} -g -pg"
FFLAGS="${FFLAGS} -g -pg"
FCFLAGS="${FCFLAGS} -g -pg"
OBJCFLAGS="${OBJCFLAGS} -g -pg"
LDFLAGS="${LDFLAGS} -pg"
],
[
AC_MSG_RESULT(no)
dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags
dnl by setting any unset environment flag variables
AS_IF([test "x${CFLAGS+set}" != "xset"],
[CFLAGS=""])
AS_IF([test "x${CXXFLAGS+set}" != "xset"],
[CXXFLAGS=""])
AS_IF([test "x${FFLAGS+set}" != "xset"],
[FFLAGS=""])
AS_IF([test "x${FCFLAGS+set}" != "xset"],
[FCFLAGS=""])
AS_IF([test "x${OBJCFLAGS+set}" != "xset"],
[OBJCFLAGS=""])
])
dnl Define various variables if debugging is disabled.
dnl assert.h is a NOP if NDEBUG is defined, so define it by default.
AS_IF([test "x$enable_debug" = "xyes"],
[m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])],
[m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])])
ax_enable_debug=$enable_debug
])

View File

@ -1,69 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_is_release.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_IS_RELEASE(POLICY)
#
# DESCRIPTION
#
# Determine whether the code is being configured as a release, or from
# git. Set the ax_is_release variable to 'yes' or 'no'.
#
# If building a release version, it is recommended that the configure
# script disable compiler errors and debug features, by conditionalising
# them on the ax_is_release variable. If building from git, these
# features should be enabled.
#
# The POLICY parameter specifies how ax_is_release is determined. It can
# take the following values:
#
# * git-directory: ax_is_release will be 'no' if a '.git' directory exists
# * minor-version: ax_is_release will be 'no' if the minor version number
# in $PACKAGE_VERSION is odd; this assumes
# $PACKAGE_VERSION follows the 'major.minor.micro' scheme
# * micro-version: ax_is_release will be 'no' if the micro version number
# in $PACKAGE_VERSION is odd; this assumes
# $PACKAGE_VERSION follows the 'major.minor.micro' scheme
# * always: ax_is_release will always be 'yes'
# * never: ax_is_release will always be 'no'
#
# Other policies may be added in future.
#
# LICENSE
#
# Copyright (c) 2015 Philip Withnall <philip@tecnocode.co.uk>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved.
#serial 3
AC_DEFUN([AX_IS_RELEASE],[
AC_BEFORE([AC_INIT],[$0])
m4_case([$1],
[git-directory],[
# $is_release = (.git directory does not exist)
AS_IF([test -d .git],[ax_is_release=no],[ax_is_release=yes])
],
[minor-version],[
# $is_release = ($minor_version is even)
minor_version=`echo "$PACKAGE_VERSION" | sed 's/[[^.]][[^.]]*.\([[^.]][[^.]]*\).*/\1/'`
AS_IF([test "$(( $minor_version % 2 ))" -ne 0],
[ax_is_release=no],[ax_is_release=yes])
],
[micro-version],[
# $is_release = ($micro_version is even)
micro_version=`echo "$PACKAGE_VERSION" | sed 's/[[^.]]*\.[[^.]]*\.\([[^.]]*\).*/\1/'`
AS_IF([test "$(( $micro_version % 2 ))" -ne 0],
[ax_is_release=no],[ax_is_release=yes])
],
[always],[ax_is_release=yes],
[never],[ax_is_release=no],
[
AC_MSG_ERROR([Invalid policy. Valid policies: git-directory, minor-version.])
])
])

View File

@ -1,327 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PYTHON_DEVEL([version])
#
# DESCRIPTION
#
# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
# in your configure.ac.
#
# This macro checks for Python and tries to get the include path to
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
# variables. It also exports $(PYTHON_EXTRA_LIBS) and
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
#
# You can search for some particular version of Python by passing a
# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
# note that you *have* to pass also an operator along with the version to
# match, and pay special attention to the single quotes surrounding the
# version number. Don't use "PYTHON_VERSION" for this: that environment
# variable is declared as precious and thus reserved for the end-user.
#
# This macro should work for all versions of Python >= 2.1.0. As an end
# user, you can disable the check for the python version by setting the
# PYTHON_NOVERSIONCHECK environment variable to something else than the
# empty string.
#
# If you need to use this macro for an older Python version, please
# contact the authors. We're always open for feedback.
#
# LICENSE
#
# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2009 Alan W. Irwin
# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2009 Andrew Collier
# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
# Copyright (c) 2013 Daniel Mullner <muellner@math.stanford.edu>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 18
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
AC_DEFUN([AX_PYTHON_DEVEL],[
#
# Allow the use of a (user set) custom python version
#
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
version to use, for example '2.3'. This string
will be appended to the Python interpreter
canonical name.])
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
if test -z "$PYTHON"; then
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
PYTHON_VERSION=""
fi
#
# Check for a version of Python >= 2.1.0
#
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
ac_supports_python_ver=`$PYTHON -c "import sys; \
ver = sys.version.split ()[[0]]; \
print (ver >= '2.1.0')"`
if test "$ac_supports_python_ver" != "True"; then
if test -z "$PYTHON_NOVERSIONCHECK"; then
AC_MSG_RESULT([no])
AC_MSG_FAILURE([
This version of the AC@&t@_PYTHON_DEVEL macro
doesn't work properly with versions of Python before
2.1.0. You may need to re-run configure, setting the
variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
to something else than an empty string.
])
else
AC_MSG_RESULT([skip at user request])
fi
else
AC_MSG_RESULT([yes])
fi
#
# if the macro parameter ``version'' is set, honour it
#
if test -n "$1"; then
AC_MSG_CHECKING([for a version of Python $1])
ac_supports_python_ver=`$PYTHON -c "import sys; \
ver = sys.version.split ()[[0]]; \
print (ver $1)"`
if test "$ac_supports_python_ver" = "True"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([this package requires Python $1.
If you have it installed, but it isn't the default Python
interpreter in your system path, please pass the PYTHON_VERSION
variable to configure. See ``configure --help'' for reference.
])
PYTHON_VERSION=""
fi
fi
#
# Check if you have distutils, else fail
#
AC_MSG_CHECKING([for the distutils Python package])
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
if test -z "$ac_distutils_result"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot import Python module "distutils".
Please check your Python installation. The error was:
$ac_distutils_result])
PYTHON_VERSION=""
fi
#
# Check for Python include path
#
AC_MSG_CHECKING([for Python include path])
if test -z "$PYTHON_CPPFLAGS"; then
python_path=`$PYTHON -c "import distutils.sysconfig; \
print (distutils.sysconfig.get_python_inc ());"`
plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
if test -n "${python_path}"; then
if test "${plat_python_path}" != "${python_path}"; then
python_path="-I$python_path -I$plat_python_path"
else
python_path="-I$python_path"
fi
fi
PYTHON_CPPFLAGS=$python_path
fi
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
AC_SUBST([PYTHON_CPPFLAGS])
#
# Check for Python library path
#
AC_MSG_CHECKING([for Python library path])
if test -z "$PYTHON_LIBS"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
ac_python_version=`cat<<EOD | $PYTHON -
# join all versioning strings, on some systems
# major/minor numbers could be in different list elements
from distutils.sysconfig import *
e = get_config_var('VERSION')
if e is not None:
print(e)
EOD`
if test -z "$ac_python_version"; then
if test -n "$PYTHON_VERSION"; then
ac_python_version=$PYTHON_VERSION
else
ac_python_version=`$PYTHON -c "import sys; \
print (sys.version[[:3]])"`
fi
fi
# Make the versioning information available to the compiler
AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
[If available, contains the Python version number currently in use.])
# First, the library directory:
ac_python_libdir=`cat<<EOD | $PYTHON -
# There should be only one
import distutils.sysconfig
e = distutils.sysconfig.get_config_var('LIBDIR')
if e is not None:
print (e)
EOD`
# Now, for the library:
ac_python_library=`cat<<EOD | $PYTHON -
import distutils.sysconfig
c = distutils.sysconfig.get_config_vars()
if 'LDVERSION' in c:
print ('python'+c[['LDVERSION']])
else:
print ('python'+c[['VERSION']])
EOD`
# This small piece shamelessly adapted from PostgreSQL python macro;
# credits goes to momjian, I think. I'd like to put the right name
# in the credits, if someone can point me in the right direction... ?
#
if test -n "$ac_python_libdir" -a -n "$ac_python_library"
then
# use the official shared library
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
PYTHON_LIBS="-L$ac_python_libdir -l$ac_python_library"
else
# old way: use libpython from python_configdir
ac_python_libdir=`$PYTHON -c \
"from distutils.sysconfig import get_python_lib as f; \
import os; \
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
fi
if test -z "PYTHON_LIBS"; then
AC_MSG_ERROR([
Cannot determine location of your Python DSO. Please check it was installed with
dynamic libraries enabled, or try setting PYTHON_LIBS by hand.
])
fi
fi
AC_MSG_RESULT([$PYTHON_LIBS])
AC_SUBST([PYTHON_LIBS])
#
# Check for site packages
#
AC_MSG_CHECKING([for Python site-packages path])
if test -z "$PYTHON_SITE_PKG"; then
PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
print (distutils.sysconfig.get_python_lib(0,0));"`
fi
AC_MSG_RESULT([$PYTHON_SITE_PKG])
AC_SUBST([PYTHON_SITE_PKG])
#
# libraries which must be linked in when embedding
#
AC_MSG_CHECKING(python extra libraries)
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
#
# linking flags needed when embedding
#
AC_MSG_CHECKING(python extra linking flags)
if test -z "$PYTHON_EXTRA_LIBS"; then
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print (conf('LINKFORSHARED'))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
AC_SUBST(PYTHON_EXTRA_LIBS)
#
# final check to see if everything compiles alright
#
AC_MSG_CHECKING([consistency of all components of python development environment])
# save current global flags
ac_save_LIBS="$LIBS"
ac_save_LDFLAGS="$LDFLAGS"
ac_save_CPPFLAGS="$CPPFLAGS"
LIBS="$ac_save_LIBS $PYTHON_LIBS $PYTHON_EXTRA_LIBS $PYTHON_EXTRA_LIBS"
LDFLAGS="$ac_save_LDFLAGS $PYTHON_EXTRA_LDFLAGS"
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
AC_LANG_PUSH([C])
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <Python.h>]],
[[Py_Initialize();]])
],[pythonexists=yes],[pythonexists=no])
AC_LANG_POP([C])
# turn back to default flags
CPPFLAGS="$ac_save_CPPFLAGS"
LIBS="$ac_save_LIBS"
LDFLAGS="$ac_save_LDFLAGS"
AC_MSG_RESULT([$pythonexists])
if test ! "x$pythonexists" = "xyes"; then
AC_MSG_FAILURE([
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
via the LIBS environment variable.
Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
============================================================================
ERROR!
You probably have to install the development version of the Python package
for your distribution. The exact name of this package varies among them.
============================================================================
])
PYTHON_VERSION=""
fi
#
# all done!
#
])

View File

@ -1,8 +0,0 @@
analysis_verbose = $(analysis_verbose_$(V))
analysis_verbose_ = $(analysis_verbose_$(AM_DEFAULT_VERBOSITY))
analysis_verbose_0 = @echo " CCSA " $@; $(COMPILE) --analyze $< -o $@;
analysis_verbose_1 = $(COMPILE) --analyze $< -o $@;
%.plist: %.c
$(analysis_verbose)

1
man/Makefile.am Normal file
View File

@ -0,0 +1 @@
man_MANS = hexchat.1

View File

@ -1,4 +1,4 @@
.TH HEXCHAT "1" "April 2013" "HexChat @VERSION@" "User Commands"
.TH HEXCHAT "1" "April 2013" "HexChat 2.9.6" "User Commands"
.SH NAME
HexChat \- IRC Client
.SH DESCRIPTION

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>HexChat</string>
<key>CFBundleGetInfoString</key>
<string>@VERSION@</string>
<key>CFBundleIconFile</key>
<string>hexchat.icns</string>
<key>CFBundleIdentifier</key>
<string>org.hexchat</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>@VERSION@</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>@VERSION@</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>LSMinimumSystemVersion</key>
<string>10.4</string>
</dict>
</plist>

435
osx/gtkrc
View File

@ -1,435 +0,0 @@
# Mac Theme for Xamarin composed by Lanedo GmbH
# Copyright 2012 Xamarin Inc.
# Authors:
# Christian Kellner <christian.kellner@lanedo.com>
# Carlos Garnacho <carlos.garnacho@lanedo.com>
#
# Modified by HexChat
#
gtk-color-scheme =
"bg_color: #f5f5f5
fg_color: #000
base_color: #fff
text_color: #000
selected_bg_color: #0066FF
selected_fg_color: #fff
tooltip_bg_color: #fafaba
tooltip_fg_color: #000"
gtk-button-images = 0
gtk-menu-images = 0
gtk-toolbar-style = 0
gtk-enable-mnemonics = 0
gtk-icon-sizes = "gtk-small-toolbar=16,16:gtk-large-toolbar=22,22"
gtk-toolbar-icon-size = large-toolbar
gtk-auto-mnemonics = 1
gtk-error-bell = 0
gtk-show-input-method-menu = 0
gtk-key-theme-name="Mac"
style "default" {
xthickness = 1
ythickness = 1
### colours
bg[NORMAL] = @bg_color
bg[PRELIGHT] = @bg_color
bg[SELECTED] = @selected_bg_color
bg[INSENSITIVE] = @bg_color
bg[ACTIVE] = @bg_color
fg[NORMAL] = @fg_color
fg[PRELIGHT] = @fg_color
fg[SELECTED] = @selected_fg_color
fg[INSENSITIVE] = darker (@bg_color)
fg[ACTIVE] = @fg_color
text[NORMAL] = @text_color
text[PRELIGHT] = @text_color
text[SELECTED] = @selected_fg_color
text[INSENSITIVE] = darker (@bg_color)
text[ACTIVE] = @text_color
base[NORMAL] = @base_color
base[PRELIGHT] = @selected_bg_color
base[SELECTED] = @selected_bg_color
base[INSENSITIVE] = @bg_color
base[ACTIVE] = shade (1.3, @selected_bg_color)
### style properties
GtkWidget::new-tooltip-style = 1
GtkEntry::honors-transparent-bg-hint = 1
GtkEntry::inner-border = { 2, 2, 2, 2 }
GtkButton::child-displacement-x = 0
GtkButton::child-displacement-y = 0
GtkButton::default-border = { 0, 0, 0, 0 }
GtkButton::inner-border = { 2, 2, 4, 4 }
GtkButtonBox::child-min-width = 70
GtkButtonBox::child-min-height = 22
GtkTreeView::odd-row-color = "#f0f4f9"
GtkScrolledWindow::scrollbar-spacing = 0
GtkScrolledWindow::scrollbars-within-bevel = 1
GtkScale::slider-length = 14
GtkRange::trough-side-details = 1
GtkTreeView::expander-size = 8
GtkExpander::expander-size = 8
GtkComboBox::arrow-size = 12
GtkMenu::vertical-padding = 4
GtkMenuItem::horizontal-padding = 9
GtkMenuItem::toggle-spacing = 0
GtkSeparatorMenuItem::horizontal-padding = 2
engine "xamarin" {
arrowstyle = 2
rgba = TRUE
roundness = 3
glazestyle = 0
menustyle = 0
menuitemstyle = 0
menubaritemstyle = 0
comboboxstyle = 1
spinbuttonstyle = 1
colorize_scrollbar = FALSE
progressbarstyle = 0
trough_shades = { 0.842, 0.886 }
}
}
style "wide" = "default" {
xthickness = 2
ythickness = 2
}
style "wider" = "default" {
xthickness = 3
ythickness = 3
}
style "button" {
xthickness = 2
ythickness = 2
bg[NORMAL] = @bg_color
bg[PRELIGHT] = shade(1.1, @bg_color)
bg[ACTIVE] = @bg_color
bg[INSENSITIVE] = @bg_color
GtkWidget::focus-padding = 0
engine "quartz" {
}
}
style "combo-box-button" {
xthickness = 2
ythickness = 4
bg[NORMAL] = @base_color
bg[PRELIGHT] = shade(1.1, @base_color)
bg[ACTIVE] = @base_color
bg[INSENSITIVE] = @base_color
GtkWidget::focus-padding = 0
engine "xamarin" {
contrast = 1.0
gradient_shades = {0.99, 0.98, 0.97, 0.96}
focus_color = shade(0.6, @base_color)
textstyle = 1
}
}
style "dialog-button" = "default" {
xthickness = 3
ythickness = 2
font_name = "Lucida Grande 13"
GtkWidget::draw-border = { 2, 2, 2, 2 }
GtkWidget::focus-line-width = 1
GtkButton::inner-border = { 8, 8, 0, 3 }
engine "quartz" {
buttontype = "aqua"
}
}
style "toggle-button" = "button" {
bg[NORMAL] = @base_color
bg[PRELIGHT] = shade(0.98, @base_color)
}
style "menu" {
xthickness = 0
ythickness = 0
font_name = "Lucida Grande 14"
bg[PRELIGHT] = @selected_fg_color
fg[PRELIGHT] = @selected_fg_color
text[PRELIGHT] = @selected_fg_color
engine "quartz" {
}
}
style "menu-item" = "menu" {
ythickness = 2
GtkWidget::draw-border = { 0, 0, 0, 2 }
}
style "menu-separator" = "menu-item" {
ythickness = 3
}
style "toolbar" = "default"
{
bg[NORMAL] = "#ddd"
engine "xamarin" {
toolbarstyle = 2
}
}
style "toolbar-button"
{
engine "xamarin" {
contrast = 1.0
focus_color = @bg_color
}
}
style "tooltip"
{
xthickness = 5
ythickness = 5
fg[NORMAL] = @tooltip_fg_color
bg[NORMAL] = @tooltip_bg_color
engine "xamarin" {
roundness = 0
}
}
style "treeview" = "default"
{
GtkTreeView::odd-row-color = "#f5f5f5"
base[SELECTED] = "#2b5dcd"
base[ACTIVE] = "#cacaca"
text[SELECTED] = "#FFF"
text[ACTIVE] = "#000"
font_name = "Lucida Grande 12"
engine "quartz" {
}
}
style "tree-header"
{
ythickness = 0
bg[NORMAL] = "#f2f2f2"
font_name = "Lucida Grande 11"
GtkWidget::focus-line-width = 0
GtkWidget::draw-border = { 1, 1, 1, 1 }
GtkButton::inner-border = { 3, 3, 1, 3 }
engine "quartz" {
}
}
style "icon-view" = "default"
{
bg[SELECTED] = "#f5f7fa"
base[SELECTED] = "#f5f7fa"
fg[SELECTED] = "#000"
text[SELECTED] = "#000"
}
style "toolbar-combo-box" = "default"
{
fg[NORMAL] = "#616161"
text[NORMAL] = @fg_color
bg[NORMAL] = "#fff"
base[NORMAL] = "#fff"
ythickness = 4
xthickness = 2
engine "xamarin" {
comboboxstyle = 0
arrowstyle = 2
}
}
style "combo-box" = "default"
{
fg[NORMAL] = "#616161"
xthickness = 2
ythickness = 4
engine "xamarin" {
arrowstyle = 4
}
}
style "combo-box-entry" = "combo-box"
{
engine "xamarin" {
arrowstyle = 3
}
}
style "combo-box-label" = "combo-box"
{
fg[NORMAL] = "#595959"
}
style "combo-box-menu" = "menu" {
font_name = "Lucida Grande 12"
}
style "notebook" = "default"
{
GtkNotebook::tab-overlap = 1
#bg[ACTIVE] = @base_color
bg[NORMAL] = @base_color
engine "xamarin" {
gradient_shades = { 0.945, 0.945, 0.945, 0.685 }
}
}
style "radio-or-check-box"
{
ythickness = 6
#GtkCheckButton::indicator-size = 14
GtkCheckButton::indicator-spacing = 4
engine "quartz" {
}
}
style "entry" = "default"
{
xthickness = 2
ythickness = 2
GtkEntry::inner-border = { 2, 2, 2, 2 }
base[INSENSITIVE] = shade(1.02, @bg_color)
engine "quartz" {
}
}
style "search-entry" = "wider"
{
xthickness = 6
ythickness = 4
bg[NORMAL] = @base_color
}
style "scrollbar" = "default"
{
GtkScrollbar::has-forward-stepper = 0
GtkScrollbar::has-backward-stepper = 0
GtkRange::slider-width = 15
GtkRange::trough-border = 0
GtkRange::trough-side-details = 0
engine "quartz" {
}
}
style "progressbar" = "default"
{
engine "quartz" {
}
}
style "scrolled-window" = "default"
{
xthickness = 1
ythickness = 1
}
style "scale" = "default"
{
bg[SELECTED] = @selected_bg_color
engine "xamarin" {
roundness = 7
}
}
style "spin-button" = "wider"
{
fg[NORMAL] = "#616161"
ythickness = 4
GtkEntry::inner-border = { 2, 2, 1, 1 }
engine "xamarin" {
arrowstyle = 3
}
}
### Apply the styles
class "GtkWidget" style "default"
class "GtkEntry" style "entry"
class "GtkSpinButton" style "spin-button"
class "GtkFrame" style "wider"
class "GtkRange" style "wide"
class "GtkSeparator" style "wide"
class "GtkScrollbar" style "scrollbar"
class "GtkProgressBar" style "progressbar"
class "GtkScrolledWindow" style "scrolled-window"
class "GtkNotebook" style "notebook"
class "GtkButton" style "button"
class "GtkToggleButton" style "toggle-button"
class "GtkScale" style "scale"
#widget "*GtkEntry" style "entry"
widget "*search-entry*" style "search-entry"
widget "*GtkTextView" style "entry"
widget_class "<GtkDialog>*<GtkCheckButton>" style "radio-or-check-box"
widget_class "<GtkDialog>.<GtkVBox>.<GtkButtonBox>.<GtkButton>*" style "dialog-button"
widget_class "<GtkDialog>.<GtkVBox>.<GtkHBox>.<GtkButtonBox>.<GtkButton>*" style "dialog-button"
widget "*.toggleFindInFiles" style "toggle-button"
widget "*.toggleReplaceInFiles" style "toggle-button"
widget_class "*<GtkMenu>*" style "menu"
widget_class "*<GtkMenuItem>*" style "menu-item"
widget_class "*<GtkSeparatorMenuItem>" style "menu-separator"
widget "*.gtk-combobox-popup-menu*" style "combo-box-menu"
widget_class "*<GtkToolbar>*" style "toolbar"
widget_class "*ToolButton*" style "toolbar-button"
widget_class "*.<GtkTreeView>*" style "treeview"
widget_class "*.GtkTreeView.GtkButton" style "tree-header"
widget_class "*.GtkList.GtkButton" style "tree-header"
widget_class "*<GtkIconView>" style "icon-view"
widget_class "*.<GtkComboBox>.*" style "combo-box"
widget_class "*.<GtkComboBoxText>.*" style "combo-box-entry"
widget_class "*.<GtkComboBoxEntry>.*" style "combo-box-entry"
widget_class "*.<GtkComboBoxText>.<GtkEntry>" style "combo-box-entry"
widget_class "*.<GtkComboBoxEntry>.<GtkEntry>" style "combo-box-entry"
widget_class "*.<GtkComboBoxText>.<GtkToggleButton>" style "combo-box-button"
widget_class "*.<GtkComboBoxEntry>.<GtkToggleButton>" style "combo-box-button"
widget_class "*.<GtkComboBox>.*.GtkLabel" style "combo-box-label"
# Comboboxes within toolbars
widget_class "*.<GtkToolbar>.*.<GtkComboBox>.*" style "toolbar-combo-box"
widget "*MainToolbar*.GtkComboBox.*" style "toolbar-combo-box"
widget "gtk-tooltip*" style "tooltip"

View File

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<app-bundle>
<meta>
<prefix name="default">/usr/local</prefix>
<prefix name="enchant">/usr/local/opt/enchant-applespell</prefix>
<destination overwrite="yes">${project}</destination>
<run-install-name-tool/>
<launcher-script>${project}/launcher.sh</launcher-script >
<gtk>gtk+-2.0</gtk>
</meta>
<plist>${project}/Info.plist</plist>
<main-binary>
${prefix}/bin/hexchat
</main-binary>
<binary>
${prefix}/lib/hexchat/plugins/*.so
</binary>
<binary>
${prefix:enchant}/lib/libenchant.dylib
</binary>
<binary>
${prefix:enchant}/lib/enchant/libenchant_applespell.so
</binary>
<binary>
${prefix}/lib/${gtkdir}/modules/*.so
</binary>
<binary>
${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/engines/libquartz.so
</binary>
<binary>
${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/engines/libxamarin.so
</binary>
<binary>
${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so
</binary>
<binary>
${prefix}/lib/gdk-pixbuf-2.0/${pkg:${gtk}:gtk_binary_version}/loaders/*.so
</binary>
<binary>
${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/
</binary>
<data>
${prefix}/share/themes/Mac/gtk-2.0-key/gtkrc
</data>
<translations name="gtk20">
${prefix}/share/locale
</translations>
<translations name="hexchat">
${prefix}/share/locale
</translations>
<data dest="${bundle}/Contents/Resources/etc/${gtkdir}/gtkrc">
${project}/gtkrc
</data>
<data dest="${bundle}/Contents/Resources">
${project}/hexchat.icns
</data>
</app-bundle>

Binary file not shown.

View File

@ -1,174 +0,0 @@
#!/bin/sh
if test "x$GTK_DEBUG_LAUNCHER" != x; then
set -x
fi
if test "x$GTK_DEBUG_GDB" != x; then
EXEC="gdb --args"
else
EXEC=exec
fi
name=`basename "$0"`
tmp="$0"
tmp=`dirname "$tmp"`
tmp=`dirname "$tmp"`
bundle=`dirname "$tmp"`
bundle_contents="$bundle"/Contents
bundle_res="$bundle_contents"/Resources
bundle_lib="$bundle_res"/lib
bundle_bin="$bundle_res"/bin
bundle_data="$bundle_res"/share
bundle_etc="$bundle_res"/etc
export PREFIX="$bundle_res"
export DYLD_LIBRARY_PATH="$bundle_lib"
export XDG_CONFIG_DIRS="$bundle_etc"/xdg
export XDG_DATA_DIRS="$bundle_data"
export GTK_DATA_PREFIX="$bundle_res"
export GTK_EXE_PREFIX="$bundle_res"
export GTK_PATH="$bundle_res"
export GTK2_RC_FILES="$bundle_etc/gtk-2.0/gtkrc"
export GTK_IM_MODULE_FILE="$bundle_etc/gtk-2.0/gtk.immodules"
export GDK_PIXBUF_MODULE_FILE="$bundle_etc/gtk-2.0/gdk-pixbuf.loaders"
export PANGO_LIBDIR="$bundle_lib"
export PANGO_SYSCONFDIR="$bundle_etc"
export OPENSSL_CONF="/System/Library/OpenSSL/openssl.cnf"
export HEXCHAT_LIBDIR="$bundle_lib/hexchat/plugins"
APP=name
I18NDIR="$bundle_data/locale"
# Set the locale-related variables appropriately:
unset LANG LC_MESSAGES LC_MONETARY LC_COLLATE
# Has a language ordering been set?
# If so, set LC_MESSAGES and LANG accordingly; otherwise skip it.
# First step uses sed to clean off the quotes and commas, to change - to _, and change the names for the chinese scripts from "Hans" to CN and "Hant" to TW.
APPLELANGUAGES=`defaults read .GlobalPreferences AppleLanguages | sed -En -e 's/\-/_/' -e 's/Hant/TW/' -e 's/Hans/CN/' -e 's/[[:space:]]*\"?([[:alnum:]_]+)\"?,?/\1/p' `
if test "$APPLELANGUAGES"; then
# A language ordering exists.
# Test, item per item, to see whether there is an corresponding locale.
for L in $APPLELANGUAGES; do
#test for exact matches:
if test -f "$I18NDIR/${L}/LC_MESSAGES/$APP.mo"; then
export LANG=$L
break
fi
#This is a special case, because often the original strings are in US
#English and there is no translation file.
if test "x$L" == "xen_US"; then
export LANG=$L
break
fi
#OK, now test for just the first two letters:
if test -f "$I18NDIR/${L:0:2}/LC_MESSAGES/$APP.mo"; then
export LANG=${L:0:2}
break
fi
#Same thing, but checking for any english variant.
if test "x${L:0:2}" == "xen"; then
export LANG=$L
break
fi;
done
fi
unset APPLELANGUAGES L
# If we didn't get a language from the language list, try the Collation preference, in case it's the only setting that exists.
APPLECOLLATION=`defaults read .GlobalPreferences AppleCollationOrder`
if test -z ${LANG} -a -n $APPLECOLLATION; then
if test -f "$I18NDIR/${APPLECOLLATION:0:2}/LC_MESSAGES/$APP.mo"; then
export LANG=${APPLECOLLATION:0:2}
fi
fi
if test ! -z $APPLECOLLATION; then
export LC_COLLATE=$APPLECOLLATION
fi
unset APPLECOLLATION
# Continue by attempting to find the Locale preference.
APPLELOCALE=`defaults read .GlobalPreferences AppleLocale`
if test -f "$I18NDIR/${APPLELOCALE:0:5}/LC_MESSAGES/$APP.mo"; then
if test -z $LANG; then
export LANG="${APPLELOCALE:0:5}"
fi
elif test -z $LANG -a -f "$I18NDIR/${APPLELOCALE:0:2}/LC_MESSAGES/$APP.mo"; then
export LANG="${APPLELOCALE:0:2}"
fi
#Next we need to set LC_MESSAGES. If at all possilbe, we want a full
#5-character locale to avoid the "Locale not supported by C library"
#warning from Gtk -- even though Gtk will translate with a
#two-character code.
if test -n $LANG; then
#If the language code matches the applelocale, then that's the message
#locale; otherwise, if it's longer than two characters, then it's
#probably a good message locale and we'll go with it.
if test $LANG == ${APPLELOCALE:0:5} -o $LANG != ${LANG:0:2}; then
export LC_MESSAGES=$LANG
#Next try if the Applelocale is longer than 2 chars and the language
#bit matches $LANG
elif test $LANG == ${APPLELOCALE:0:2} -a $APPLELOCALE > ${APPLELOCALE:0:2}; then
export LC_MESSAGES=${APPLELOCALE:0:5}
#Fail. Get a list of the locales in $PREFIX/share/locale that match
#our two letter language code and pick the first one, special casing
#english to set en_US
elif test $LANG == "en"; then
export LC_MESSAGES="en_US"
else
LOC=`find $PREFIX/share/locale -name $LANG???`
for L in $LOC; do
export LC_MESSAGES=$L
done
fi
else
#All efforts have failed, so default to US english
export LANG="en_US"
export LC_MESSAGES="en_US"
fi
CURRENCY=`echo $APPLELOCALE | sed -En 's/.*currency=([[:alpha:]]+).*/\1/p'`
if test "x$CURRENCY" != "x"; then
#The user has set a special currency. Gtk doesn't install LC_MONETARY files, but Apple does in /usr/share/locale, so we're going to look there for a locale to set LC_CURRENCY to.
if test -f /usr/local/share/$LC_MESSAGES/LC_MONETARY; then
if test -a `cat /usr/local/share/$LC_MESSAGES/LC_MONETARY` == $CURRENCY; then
export LC_MONETARY=$LC_MESSAGES
fi
fi
if test -z "$LC_MONETARY"; then
FILES=`find /usr/share/locale -name LC_MONETARY -exec grep -H $CURRENCY {} \;`
if test -n "$FILES"; then
export LC_MONETARY=`echo $FILES | sed -En 's%/usr/share/locale/([[:alpha:]_]+)/LC_MONETARY.*%\1%p'`
fi
fi
fi
#No currency value means that the AppleLocale governs:
if test -z "$LC_MONETARY"; then
LC_MONETARY=${APPLELOCALE:0:5}
fi
#For Gtk, which only looks at LC_ALL:
export LC_ALL=$LC_MESSAGES
unset APPLELOCALE FILES LOC
if test -f "$bundle_lib/charset.alias"; then
export CHARSETALIASDIR="$bundle_lib"
fi
# Extra arguments can be added in environment.sh.
EXTRA_ARGS=
if test -f "$bundle_res/environment.sh"; then
source "$bundle_res/environment.sh"
fi
# Strip out the argument added by the OS.
if /bin/expr "x$1" : '^x-psn_' > /dev/null; then
shift 1
fi
$EXEC "$bundle_contents/MacOS/$name-bin" "$@" $EXTRA_ARGS

View File

@ -1,11 +0,0 @@
#!/bin/sh
rm -rf HexChat.app
rm -f *.app.zip
python $HOME/.local/bin/gtk-mac-bundler hexchat.bundle
echo "Compressing bundle"
#hdiutil create -format UDBZ -srcdir HexChat.app -quiet HexChat-2.9.6.1-$(git rev-parse --short master).dmg
zip -9rXq ./HexChat-$(git describe --tags).app.zip ./HexChat.app

38
plugins/Make.plugin Normal file
View File

@ -0,0 +1,38 @@
# Makefile stub for creating standalone plugin distributions.
plugin_dist: pg_dist pg_dist/config.status
pgi=`cd $(srcdir)/.. && pwd`; cd pg_dist; \
$(MAKE) $(AM_MAKEFLAGS) PLUGIN_INCLUDES=-I$$pgi distcheck dist
pg_dist: pg_distdir pg_dist/configure.in pg_dist/install-sh
cd pg_dist \
&& libtoolize --copy --force --automake \
&& automake --copy --add-missing --foreign \
&& autoconf -l ../$(top_srcdir)
pg_distdir: $(DISTFILES)
test -d pg_dist || mkdir pg_dist
for dfile in $(DISTFILES); do \
test -f $$dfile && cp $$dfile pg_dist \
|| test -f $(srcdir)/$$dfile && cp $(srcdir)/$$dfile pg_dist; done
sed '/Make.plugin/d' < $(srcdir)/Makefile.am > pg_dist/Makefile.am
pg_dist/configure.in: $(srcdir)/../plugin-conf.in
rm -f pg_dist/configure.in
test -f $(srcdir)/config.stub \
&& cat $(srcdir)/config.stub > pg_dist/configure.in || true
cat $(srcdir)/../plugin-conf.in | \
sed 's%@PLUGIN_VERSION@%$(PLUGIN_VERSION)%; \
s%@PLUGIN@%$(PLUGIN)%' >> pg_dist/configure.in
pg_dist/install-sh: pg_distdir
cp $(top_srcdir)/install-sh pg_dist
pg_dist/config.status: pg_dist/configure
cd pg_dist \
&& test -f config.status && $(SHELL) ./config.status --recheck \
|| $(SHELL) ./configure --enable-maintainer-mode
DISTCLEANFILES = pg_dist/* pg_dist
#

View File

@ -1,6 +1,7 @@
if DO_LUA
lua = lua
endif
# temp. solution while mailcheck & xdcc arn't in SUBDIRS
EXTRA_DIST = Make.plugin plugin-conf.in xdcc/xdcc.c xdcc/Makefile.am
# noinst_HEADERS = hexchat-plugin.h
if DO_PYTHON
pythondir = python
@ -10,6 +11,10 @@ if DO_PERL
perldir = perl
endif
if DO_DOAT
doatdir = doat
endif
if DO_FISHLIM
fishlimdir = fishlim
endif
@ -22,4 +27,5 @@ if DO_SYSINFO
sysinfodir = sysinfo
endif
SUBDIRS = $(lua) $(pythondir) $(perldir) $(checksumdir) $(fishlimdir) $(sysinfodir)
#SUBDIRS = . $(pythondir) $(perldir) mailcheck xdcc
SUBDIRS = . $(pythondir) $(perldir) $(checksumdir) $(doatdir) $(fishlimdir) $(sysinfodir)

View File

@ -2,7 +2,6 @@ libdir = $(hexchatlibdir)
lib_LTLIBRARIES = checksum.la
checksum_la_SOURCES = checksum.c
checksum_la_LDFLAGS = $(PLUGIN_LDFLAGS) -module
checksum_la_LIBADD = $(GLIB_LIBS)
checksum_la_CPPFLAGS = -I$(top_srcdir)/src/common
checksum_la_CFLAGS = $(GLIB_CFLAGS)
checksum_la_LDFLAGS = -avoid-version -module
checksum_la_LIBADD =
AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/../../src/common

View File

@ -20,194 +20,217 @@
* THE SOFTWARE.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/sha.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#ifdef WIN32
#ifndef snprintf
#define snprintf _snprintf
#endif
#define stat _stat64
#else
/* for INT_MAX */
#include <limits.h>
#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#include "hexchat-plugin.h"
#define BUFSIZE 32768
#define DEFAULT_LIMIT 256 /* default size is 256 MiB */
#define SHA256_DIGEST_LENGTH 32
#define SHA256_BUFFER_LENGTH 65
static hexchat_plugin *ph; /* plugin handle */
static char name[] = "Checksum";
static char desc[] = "Calculate checksum for DCC file transfers";
static char version[] = "3.1";
/* Use of OpenSSL SHA256 interface: http://adamlamers.com/?p=5 */
static void
set_limit (char *size)
sha256_hash_string (unsigned char hash[SHA256_DIGEST_LENGTH], char outputBuffer[65])
{
int limit = atoi (size);
if (limit > 0 && limit < INT_MAX)
int i;
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
if (hexchat_pluginpref_set_int (ph, "limit", limit))
hexchat_printf (ph, "Checksum: File size limit has successfully been set to: %d MiB\n", limit);
sprintf (outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
#if 0
static void
sha256 (char *string, char outputBuffer[65])
{
int i;
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init (&sha256);
SHA256_Update (&sha256, string, strlen (string));
SHA256_Final (hash, &sha256);
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf (outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
#endif
static int
sha256_file (char *path, char outputBuffer[65])
{
int bytesRead;
unsigned char *buffer;
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
FILE *file = fopen (path, "rb");
if (!file)
{
return -534;
}
SHA256_Init (&sha256);
buffer = malloc (BUFSIZE);
bytesRead = 0;
if (!buffer)
{
fclose (file);
return ENOMEM;
}
while ((bytesRead = fread (buffer, 1, BUFSIZE, file)))
{
SHA256_Update (&sha256, buffer, bytesRead);
}
SHA256_Final (hash, &sha256);
sha256_hash_string (hash, outputBuffer);
fclose (file);
free (buffer);
return 0;
}
static void
set_limit (char* size)
{
int buffer = atoi (size);
if (buffer > 0 && buffer < INT_MAX)
{
if (hexchat_pluginpref_set_int (ph, "limit", buffer))
{
hexchat_printf (ph, "File size limit has successfully been set to: %d MiB\n", buffer);
}
else
hexchat_printf (ph, "Checksum: File access error while saving!\n");
{
hexchat_printf (ph, "File access error while saving!\n");
}
}
else
{
hexchat_printf (ph, "Checksum: Invalid input!\n");
hexchat_printf (ph, "Invalid input!\n");
}
}
static int
get_limit (void)
get_limit ()
{
int size = hexchat_pluginpref_get_int (ph, "limit");
if (size <= 0 || size >= INT_MAX)
if (size <= -1 || size >= INT_MAX)
{
return DEFAULT_LIMIT;
}
else
{
return size;
}
}
static gboolean
check_limit (GFile *file)
static void
print_limit ()
{
GFileInfo *file_info;
goffset file_size;
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (!file_info)
return FALSE;
file_size = g_file_info_get_size (file_info);
g_object_unref (file_info);
if (file_size > get_limit () * 1048576ll)
return FALSE;
return TRUE;
}
static gboolean
sha256_from_stream (GFileInputStream *file_stream, char out_buf[])
{
GChecksum *checksum;
gssize bytes_read;
guint8 digest[SHA256_DIGEST_LENGTH];
gsize digest_len = sizeof(digest);
guchar buffer[BUFSIZE];
gsize i;
checksum = g_checksum_new (G_CHECKSUM_SHA256);
while ((bytes_read = g_input_stream_read (G_INPUT_STREAM (file_stream), buffer, sizeof (buffer), NULL, NULL)))
{
if (bytes_read == -1)
{
g_checksum_free (checksum);
return FALSE;
}
g_checksum_update (checksum, buffer, bytes_read);
}
g_checksum_get_digest (checksum, digest, &digest_len);
g_checksum_free (checksum);
for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
/* out_buf will be exactly SHA256_BUFFER_LENGTH including null */
g_sprintf (out_buf + (i * 2), "%02x", digest[i]);
}
return TRUE;
}
static gboolean
sha256_from_file (char *filename, char out_buf[])
{
GFileInputStream *file_stream;
char *filename_fs;
GFile *file;
filename_fs = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
if (!filename_fs)
{
hexchat_printf (ph, "Checksum: Invalid filename (%s)\n", filename);
return FALSE;
}
file = g_file_new_for_path (filename_fs);
g_free (filename_fs);
if (!file)
{
hexchat_printf (ph, "Checksum: Failed to open %s\n", filename);
return FALSE;
}
if (!check_limit (file))
{
hexchat_printf (ph, "Checksum: %s is larger than size limit. You can increase it with /CHECKSUM SET.\n", filename);
g_object_unref (file);
return FALSE;
}
file_stream = g_file_read (file, NULL, NULL);
if (!file_stream)
{
hexchat_printf (ph, "Checksum: Failed to read file %s\n", filename);
g_object_unref (file);
return FALSE;
}
if (!sha256_from_stream (file_stream, out_buf))
{
hexchat_printf (ph, "Checksum: Failed to generate checksum for %s\n", filename);
g_object_unref (file_stream);
g_object_unref (file);
return FALSE;
}
g_object_unref (file_stream);
g_object_unref (file);
return TRUE;
hexchat_printf (ph, "File size limit for checksums: %d MiB", get_limit ());
}
static int
dccrecv_cb (char *word[], void *userdata)
{
const char *dcc_completed_dir;
char *filename, checksum[SHA256_BUFFER_LENGTH];
int result;
struct stat buffer; /* buffer for storing file info */
char sum[65]; /* buffer for checksum */
const char *file;
char *cfile;
/* Print in the privmsg tab of the sender */
hexchat_set_context (ph, hexchat_find_context (ph, NULL, word[3]));
if (hexchat_get_prefs (ph, "dcc_completed_dir", &dcc_completed_dir, NULL) == 1 && dcc_completed_dir[0] != '\0')
filename = g_build_filename (dcc_completed_dir, word[1], NULL);
else
filename = g_strdup (word[2]);
if (sha256_from_file (filename, checksum))
if (hexchat_get_prefs (ph, "dcc_completed_dir", &file, NULL) == 1 && file[0] != 0)
{
hexchat_printf (ph, "SHA-256 checksum for %s (local): %s\n", word[1], checksum);
cfile = g_strconcat (file, G_DIR_SEPARATOR_S, word[1], NULL);
}
else
{
cfile = g_strdup(word[2]);
}
g_free (filename);
result = stat (cfile, &buffer);
if (result == 0) /* stat returns 0 on success */
{
if (buffer.st_size <= (unsigned long long) get_limit () * 1048576)
{
sha256_file (cfile, sum); /* file is the full filename even if completed dir set */
/* try to print the checksum in the privmsg tab of the sender */
hexchat_set_context (ph, hexchat_find_context (ph, NULL, word[3]));
hexchat_printf (ph, "SHA-256 checksum for %s (local): %s\n", word[1], sum);
}
else
{
hexchat_set_context (ph, hexchat_find_context (ph, NULL, word[3]));
hexchat_printf (ph, "SHA-256 checksum for %s (local): (size limit reached, no checksum calculated, you can increase it with /CHECKSUM INC)\n", word[1]);
}
}
else
{
hexchat_printf (ph, "File access error!\n");
}
g_free (cfile);
return HEXCHAT_EAT_NONE;
}
static int
dccoffer_cb (char *word[], void *userdata)
{
char checksum[SHA256_BUFFER_LENGTH];
int result;
struct stat buffer; /* buffer for storing file info */
char sum[65]; /* buffer for checksum */
/* Print in the privmsg tab of the receiver */
hexchat_set_context (ph, hexchat_find_context (ph, NULL, word[3]));
if (sha256_from_file (word[3], checksum))
result = stat (word[3], &buffer);
if (result == 0) /* stat returns 0 on success */
{
hexchat_commandf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): %s", word[2], word[1], checksum);
if (buffer.st_size <= (unsigned long long) get_limit () * 1048576)
{
sha256_file (word[3], sum); /* word[3] is the full filename */
hexchat_commandf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): %s", word[2], word[1], sum);
}
else
{
hexchat_set_context (ph, hexchat_find_context (ph, NULL, word[3]));
hexchat_printf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): (size limit reached, no checksum calculated)", word[2], word[1]);
}
}
else
{
hexchat_printf (ph, "File access error!\n");
}
return HEXCHAT_EAT_NONE;
@ -218,7 +241,7 @@ checksum (char *word[], char *word_eol[], void *userdata)
{
if (!g_ascii_strcasecmp ("GET", word[2]))
{
hexchat_printf (ph, "File size limit for checksums: %d MiB", get_limit ());
print_limit ();
}
else if (!g_ascii_strcasecmp ("SET", word[2]))
{
@ -231,7 +254,7 @@ checksum (char *word[], char *word_eol[], void *userdata)
hexchat_printf (ph, " SET <filesize> - set the maximum file size (in MiB) to be hashed\n");
}
return HEXCHAT_EAT_ALL;
return HEXCHAT_EAT_NONE;
}
int
@ -249,7 +272,7 @@ hexchat_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **p
hexchat_pluginpref_set_int (ph, "limit", DEFAULT_LIMIT);
}
hexchat_hook_command (ph, "CHECKSUM", HEXCHAT_PRI_NORM, checksum, "Usage: /CHECKSUM GET|SET", NULL);
hexchat_hook_command (ph, "CHECKSUM", HEXCHAT_PRI_NORM, checksum, "Usage: /CHECKSUM GET|SET", 0);
hexchat_hook_print (ph, "DCC RECV Complete", HEXCHAT_PRI_NORM, dccrecv_cb, NULL);
hexchat_hook_print (ph, "DCC Offer", HEXCHAT_PRI_NORM, dccoffer_cb, NULL);

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
@ -20,19 +19,57 @@
<RootNamespace>checksum</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
<PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcchecksum</TargetName>
<OutDir>$(HexChatRel)plugins\</OutDir>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcchecksum</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>checksum.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
@ -40,10 +77,19 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>checksum.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
@ -56,4 +102,6 @@
<None Include="checksum.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

332
plugins/dns/dns.c Normal file
View File

@ -0,0 +1,332 @@
/* HexChat Win32 DNS Plugin
* Copyright (C) 2003-2004 Peter Zelezny.
* Copyright (C) 2012 Berke Viktor.
*
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* Requires MS Visual Studio and IPV6 headers to compile (run nmake).
* Compiling with gcc (mingw) will fail due to missing gai_strerror.
*/
#define DNS_VERSION "2.4"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define USE_IPV6
#ifdef WIN32
#ifdef USE_IPV6
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <winsock2.h>
#endif
#include <io.h>
#else
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#endif
#include "hexchat-plugin.h"
#include "thread.h"
#define HELP "Usage: DNS <nickname|hostname|numerical address>\n"
#define HEAD "\0034[DNS]\017\t"
#define PIPE_READ 0
#define PIPE_WRITE 1
#define MAX_HOSTNAME 128
static hexchat_plugin *ph;
static thread *active_thread = NULL;
static int
waitline (void *source, char *buf, int bufsize)
{
int i = 0;
int len;
while(1)
{
len = 1;
/* we can't read() here, due to glib's giowin32 */
if (ph->hexchat_read_fd (ph, source, buf + i, &len) != 0)
{
return -1;
}
if (buf[i] == '\n' || bufsize == i + 1)
{
buf[i] = 0;
return i;
}
i++;
}
}
static void *
thread_function (void *ud)
{
#ifdef USE_IPV6
struct addrinfo *ent;
struct addrinfo *cur;
struct addrinfo hints;
#else
struct hostent *ent;
#endif
thread *th = ud;
int fd = th->pipe_fd[PIPE_WRITE];
int ret;
char ipstring[MAX_HOSTNAME];
char reverse[MAX_HOSTNAME];
// int i;
active_thread = th;
#ifdef USE_IPV6
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC; /* support ipv6 and ipv4 */
hints.ai_flags = AI_CANONNAME;
// hints.ai_socktype = SOCK_STREAM;
ret = getaddrinfo (th->userdata, NULL, &hints, &ent);
if (ret != 0)
{
sprintf (ipstring, "1%d\n", ret); /* failed */
write (fd, ipstring, strlen (ipstring));
// Sleep (3000);
active_thread = NULL;
return 0;
}
// i = 0;
cur = ent;
while (cur)
{
/* find the numeric IP number */
ipstring[0] = 0;
getnameinfo (cur->ai_addr, cur->ai_addrlen,
ipstring, sizeof (ipstring), NULL, 0, NI_NUMERICHOST);
if (cur->ai_canonname)
{
/* force reverse lookup if canonname & ipstring are the same */
if (/*i == 0 &&*/ strcmp (cur->ai_canonname, ipstring) == 0)
goto lamecode;
}
if (cur->ai_canonname)
{
write (fd, "0", 1);
write (fd, ipstring, strlen (ipstring));
write (fd, "\n", 1);
write (fd, cur->ai_canonname, strlen (cur->ai_canonname));
} else
{
lamecode:
// ret = 1;
// if (i == 0)
{
/* reverse lookup */
reverse[0] = 0;
ret = getnameinfo (cur->ai_addr, cur->ai_addrlen,
reverse, sizeof (reverse), NULL, 0, NI_NAMEREQD);
}
write (fd, "0", 1);
write (fd, ipstring, strlen (ipstring));
write (fd, "\n", 1);
if (ret == 0)
write (fd, reverse, strlen (reverse));
}
write (fd, "\n", 1);
// i++;
cur = cur->ai_next;
}
/* tell the parent we're done */
write (fd, "2\n", 2);
freeaddrinfo (ent);
#else
ent = gethostbyname (th->userdata);
if (ent)
{
write (fd, "0", 1);
write (fd, ent->h_name, strlen (ent->h_name));
write (fd, "\n", 1);
write (fd, ent->h_name, strlen (ent->h_name));
write (fd, "\n", 1);
write (fd, "2\n", 2);
} else
{
write (fd, "10\n", 1);
}
#endif
// Sleep (3000);
active_thread = NULL; /* race condition, better than nothing */
return 0;
}
static int
dns_close_pipe (int fd)
{
close (fd);
return 0;
}
/* read messages comming from the child (through the pipe) */
static int
dns_read_cb (int fd, int flags, thread *th, void *source)
{
char buf[512];
char buf2[512];
while (waitline (source, buf, sizeof (buf)))
{
switch (buf[0])
{
case '0': /* got data to show */
waitline (source, buf2, sizeof (buf2));
if (buf2[0] == 0)
hexchat_printf(ph, HEAD"\002Numerical\002: %s\n", buf + 1);
else
hexchat_printf(ph, HEAD"\002Canonical\002: %s \002Numerical\002: %s\n", buf2, buf + 1);
return 1;
case '1': /* failed */
hexchat_printf(ph, HEAD"Lookup failed. %s\n", gai_strerrorA (atoi (buf + 1)));
case '2': /* done */
// close (th->pipe_fd[PIPE_WRITE]);
// close (th->pipe_fd[PIPE_READ]);
hexchat_hook_timer(ph, 3000, dns_close_pipe, (void *)th->pipe_fd[PIPE_WRITE]);
hexchat_hook_timer(ph, 4000, dns_close_pipe, (void *)th->pipe_fd[PIPE_READ]);
free (th->userdata); /* hostname strdup'ed */
free (th);
return 0;
}
}
return 1;
}
/* find hostname from nickname (search the userlist, current chan only) */
static char *
find_nick_host (char *nick)
{
hexchat_list *list;
char *at;
const char *host;
list = hexchat_list_get (ph, "users");
if (!list)
return NULL;
while (hexchat_list_next (ph, list))
{
if (stricmp (nick, hexchat_list_str (ph, list, "nick")) == 0)
{
host = hexchat_list_str (ph, list, "host");
if (host)
{
at = strrchr (host, '@');
if (at)
return at + 1;
}
break;
}
}
return NULL;
}
static int
dns_cmd_cb (char *word[], char *word_eol[], void *ud)
{
thread *th;
char *nickhost;
if (!word[2][0])
{
hexchat_print (ph, HELP);
return HEXCHAT_EAT_ALL;
}
th = thread_new ();
if (th)
{
nickhost = find_nick_host (word[2]);
if (nickhost)
{
hexchat_printf (ph, HEAD"Looking up %s (%s)...\n", nickhost, word[2]);
th->userdata = strdup (nickhost);
} else
{
hexchat_printf (ph, HEAD"Looking up %s...\n", word[2]);
th->userdata = strdup (word[2]);
}
if (thread_start (th, thread_function, th))
{
hexchat_hook_fd(ph, th->pipe_fd[PIPE_READ],
HEXCHAT_FD_READ | HEXCHAT_FD_EXCEPTION | HEXCHAT_FD_NOTSOCKET,
(void *)dns_read_cb, th);
}
}
return HEXCHAT_EAT_ALL;
}
int
hexchat_plugin_deinit (hexchat_plugin *plugin_handle)
{
while (active_thread) /* children will set this var to NULL soon... */
{
Sleep (1000);
}
hexchat_printf (ph, "DNS plugin unloaded\n");
return 1;
}
int
hexchat_plugin_init
(hexchat_plugin *plugin_handle, char **plugin_name,
char **plugin_desc, char **plugin_version, char *arg)
{
/* we need to save this for use with any hexchat_* functions */
ph = plugin_handle;
*plugin_name = "DNS";
*plugin_desc = "Threaded IPv4/6 DNS Command";
*plugin_version = DNS_VERSION;
hexchat_hook_command(ph, "DNS", HEXCHAT_PRI_LOW, dns_cmd_cb, HELP, 0);
hexchat_printf (ph, "DNS plugin loaded\n");
return 1; /* return 1 for success */
}

3
plugins/dns/dns.def Normal file
View File

@ -0,0 +1,3 @@
EXPORTS
hexchat_plugin_init
hexchat_plugin_deinit

111
plugins/dns/dns.vcxproj Normal file
View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{3786FA8C-3E76-45E3-984E-FCCFF44729C9}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>dns</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcdns</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcdns</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DNS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>dns.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;DNS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>dns.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="dns.def" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dns.c" />
<ClCompile Include="thread.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="thread.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -7,7 +7,7 @@
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
@ -15,8 +15,21 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="win8_provider.cpp">
<None Include="dns.def">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dns.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="thread.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
<ItemGroup>
<ClInclude Include="thread.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

34
plugins/dns/thread.c Normal file
View File

@ -0,0 +1,34 @@
#include <io.h>
#include <fcntl.h>
#include "thread.h"
thread *
thread_new (void)
{
thread *th;
th = calloc (1, sizeof (*th));
if (!th)
{
return NULL;
}
if (_pipe (th->pipe_fd, 4096, _O_BINARY) == -1)
{
free (th);
return NULL;
}
return th;
}
int
thread_start (thread *th, void *(*start_routine)(void *), void *arg)
{
DWORD id;
CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, (DWORD *)&id));
th->threadid = id;
return 1;
}

11
plugins/dns/thread.h Normal file
View File

@ -0,0 +1,11 @@
#include <windows.h>
typedef struct
{
DWORD threadid;
int pipe_fd[2];
void *userdata;
} thread;
thread *thread_new (void);
int thread_start (thread *th, void *(*start_routine)(void *), void *arg);

8
plugins/doat/Makefile.am Normal file
View File

@ -0,0 +1,8 @@
libdir = $(hexchatlibdir)
lib_LTLIBRARIES = doat.la
doat_la_SOURCES = doat.c
doat_la_LDFLAGS = -avoid-version -module
doat_la_LIBADD =
AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/../../src/common

94
plugins/doat/doat.c Normal file
View File

@ -0,0 +1,94 @@
/* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING or http://lwsitu.com/xchat/COPYING
* for more details. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "hexchat-plugin.h"
static hexchat_plugin *ph;
static int
parse_command( char *word[], char *word_eol[], void *userdata ) {
char *channel = NULL, *server = NULL, *token = NULL;
/* char *save_ptr1 = NULL;*/
char *str1 = NULL;
char *delimiter = NULL;
hexchat_context *ctx = NULL;
if( word[2] != NULL && word[3] != NULL ) {
for( str1 = word[2]; ; str1 = NULL ) {
/* token = strtok_r( str1, ",", &save_ptr1 );*/
token = strtok( str1, "," );
/* printf( "token: %s\n", token );*/
if( token == NULL ) {
break;
}
channel = strdup( token );
delimiter = strchr( channel, '/' );
server = NULL;
if( delimiter != NULL ) {
*delimiter = '\0';
if( strlen( delimiter + 1 ) > 0 ) {
server = strdup( delimiter + 1 );
}
}
/* /Network form */
if( strlen( channel ) == 0 ) {
free( channel );
channel = NULL;
}
/* printf( "channel[%s] server[%s]\n", channel, server );*/
if( (ctx = hexchat_find_context( ph, server, channel ) ) != NULL ) {
if( hexchat_set_context( ph, ctx ) ) {
hexchat_command( ph, word_eol[3] );
}
}
if( channel != NULL ) {
free( channel );
}
if( server != NULL ) {
free( server );
}
}
}
return HEXCHAT_EAT_HEXCHAT;
}
int
hexchat_plugin_init( hexchat_plugin * plugin_handle, char **plugin_name,
char **plugin_desc, char **plugin_version, char *arg ) {
ph = plugin_handle;
*plugin_name = "Do At";
*plugin_version = "1.0001";
*plugin_desc = "Perform an arbitrary command on multiple channels";
hexchat_hook_command( ph, "doat", HEXCHAT_PRI_NORM, parse_command, "DOAT [channel,list,/network] [command], perform a command on multiple contexts", NULL );
hexchat_print (ph, "Do At plugin loaded\n");
return 1;
}
int
hexchat_plugin_deinit (void)
{
hexchat_print (ph, "Do At plugin unloaded\n");
return 1;
}

3
plugins/doat/doat.def Normal file
View File

@ -0,0 +1,3 @@
EXPORTS
hexchat_plugin_init
hexchat_plugin_deinit

103
plugins/doat/doat.vcxproj Normal file
View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4980AF24-9D42-427D-A8E6-0DF3B97C455D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>doat</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcdoat</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcdoat</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DOAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>doat.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;DOAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>doat.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="doat.c" />
</ItemGroup>
<ItemGroup>
<None Include="doat.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,22 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="notification-winrt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="doat.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="doat.def">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
</Project>

502
plugins/ewc/COPYING Normal file
View File

@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

231
plugins/ewc/ewc.c Normal file
View File

@ -0,0 +1,231 @@
/*
EasyWinampControl - A Winamp "What's playing" plugin for HexChat
Copyright (C) Yann HAMON & contributors
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <windows.h>
#include "hexchat-plugin.h"
static hexchat_plugin *ph; /* plugin handle */
static int enable = 1;
// For example, circularstrstr("winamp", "pwi", 3) would return 5 (the index of p)
int circularstrstr(char* a, char* b, int nb)
{
int equal = 1;
int length;
int pos=-1;
int i, j;
length = strlen(a);
for (i=0; i<length && pos == -1; ++i) {
equal = 1;
for (j=0; j<nb;j++) {
if (a[(i+j)%length] != b[j])
equal = 0;
}
if (equal == 1)
pos = i;
}
return pos;
}
void GetCurrentSongsName(HWND hwndWinamp, char* title, int titlesize)
{
int pos;
char *title2;
int i, j=0;
int length;
char *p;
GetWindowText(hwndWinamp, title, titlesize);
length = strlen(title);
if ((pos = circularstrstr(title, "- Winamp ***", 12)) != -1) {
// The option "scroll song title in taskbar" is on
title2 = (char*) malloc (titlesize*sizeof(char));
for (i=(pos+12)%length; i!=pos; i=(i+1)%length)
title2[j++] = title[i];
title2[j] = '\0';
p = title2;
while (p<title2+titlesize && *p != '.')
p++;
p+=2; // Delete the . and the following white space
strcpy(title, p);
free(title2);
}
else {
p = title;
while (p<title+titlesize && *p != '.')
p++;
p+=2; // Delete the . and the following white space
if (p<title+titlesize)
strncpy(title, p, titlesize-(p-title));
// Delete the trailing "- winamp"
p = title + titlesize - 1;
while (p>title && *p != '-') p--;
*p = '\0';
}
}
// Controlling winamp
static int wcmd_cb(char *word[], char *word_eol[], void *userdata)
{
// Everything's here : http://winamp.com/nsdn/winamp2x/dev/sdk/api.php
// The previous url seems dead, see http://forums.winamp.com/showthread.php?threadid=180297
HWND hwndWinamp = NULL;
if ((hwndWinamp = FindWindow("Winamp v1.x",NULL)) == NULL) {
hexchat_print(ph, "Winamp's window not found - Is winamp really running?\n");
}
else {
if (strcmp(word[1], "") == 0)
hexchat_print(ph, "Usage: wcmd [command]\n");
else if (strcmp(word[2], "next") == 0) {
hexchat_print(ph, "Loading next song...\n");
SendMessage (hwndWinamp, WM_COMMAND, 40048, 0);
}
else if (strcmp(word[2], "prev") == 0) {
hexchat_print(ph, "Loading previous song...\n");
SendMessage (hwndWinamp, WM_COMMAND, 40044, 0);
}
else if (strcmp(word[2], "play") == 0) {
hexchat_print(ph, "Playin'...\n");
SendMessage (hwndWinamp, WM_COMMAND, 40045, 0);
}
else if (strcmp(word[2], "stop") == 0) {
hexchat_print(ph, "Winamp stopped!...\n");
SendMessage (hwndWinamp, WM_COMMAND, 40047, 0);
}
else if (strcmp(word[2], "pause") == 0) {
SendMessage (hwndWinamp, WM_COMMAND, 40046, 0);
}
}
return HEXCHAT_EAT_ALL;
}
// Display current song
static int wp_cb(char *word[], char *word_eol[], void *userdata)
{
HWND hwndWinamp = NULL;
int bitrate, length, elapsed, minutes, seconds, eminutes, eseconds, samplerate, nbchannels;
char elapsedtime[7];
char totaltime[7];
char this_title[1024];
if ((hwndWinamp = FindWindow("Winamp v1.x",NULL)) == NULL)
hexchat_print(ph, "Winamp's window not found - Is winamp really running?\n");
else {
//Winamp's running
// Seems buggy when winamp2's agent is running, and winamp not (or winamp3) -> crashes HexChat.
SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)125);
if ((samplerate = SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)126)) == 0) {
hexchat_print(ph, "Could not get current song's samplerate... !?\n");
return HEXCHAT_EAT_ALL;
}
if ((bitrate = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)126)) == 0) {
hexchat_print(ph, "Could not get current song's bitrate... !?\n");
return HEXCHAT_EAT_ALL;
}
if ((nbchannels = SendMessage(hwndWinamp, WM_USER, (WPARAM)2, (LPARAM)126)) == 0) {
hexchat_print(ph, "Could not get the number of channels... !?\n");
return HEXCHAT_EAT_ALL;
}
if ((length = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)105)) == 0) {
// Could be buggy when streaming audio or video, returned length is unexpected;
// How to detect is Winamp is streaming, and display ??:?? in that case?
hexchat_print(ph, "Could not get current song's length... !?\n");
return HEXCHAT_EAT_ALL;
}
else {
minutes = length/60;
seconds = length%60;
if (seconds>9)
wsprintf(totaltime, "%d:%d", minutes, seconds);
else
wsprintf(totaltime, "%d:0%d", minutes, seconds);
}
if ((elapsed = SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)105)) == 0) {
hexchat_print(ph, "Could not get current song's elapsed time... !?\n");
return HEXCHAT_EAT_ALL;
}
else {
eminutes = (elapsed/1000)/60; /* kinda stupid sounding, but e is for elapsed */
eseconds = (elapsed/1000)%60;
if (eseconds>9)
wsprintf(elapsedtime, "%d:%d", eminutes, eseconds);
else
wsprintf(elapsedtime, "%d:0%d", eminutes, eseconds);
}
if ((bitrate = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)126)) == 0) {
hexchat_print(ph, "Could not get current song's bitrate... !?\n");
return HEXCHAT_EAT_ALL;
}
GetCurrentSongsName(hwndWinamp, this_title, 1024);
hexchat_commandf(ph, "dispcurrsong %d %d %d %s %s %s", samplerate, bitrate, nbchannels, elapsedtime, totaltime, this_title);
}
return HEXCHAT_EAT_ALL; /* eat this command so HexChat and other plugins can't process it */
}
int hexchat_plugin_init(hexchat_plugin *plugin_handle,
char **plugin_name,
char **plugin_desc,
char **plugin_version,
char *arg)
{
/* we need to save this for use with any hexchat_* functions */
ph = plugin_handle;
*plugin_name = "EasyWinampControl";
*plugin_desc = "Some commands to remotely control winamp";
*plugin_version = "1.2";
hexchat_hook_command(ph, "wp", HEXCHAT_PRI_NORM, wp_cb,
"Usage: wp", 0);
hexchat_hook_command(ph, "wcmd", HEXCHAT_PRI_NORM, wcmd_cb,
"Usage: wcmd [play|pause|stop|prev|next]", 0);
hexchat_print(ph, "EasyWinampControl plugin loaded\n");
return 1; /* return 1 for success */
}
int hexchat_plugin_deinit(void)
{
hexchat_print(ph, "EasyWinampControl plugin unloaded\n");
return 1;
}

18
plugins/ewc/makefile.mak Normal file
View File

@ -0,0 +1,18 @@
include "..\..\src\makeinc.mak"
all: ewc.obj ewc.def
link $(LDFLAGS) $(LIBS) /dll /out:xcewc.dll /def:ewc.def ewc.obj
ewc.def:
echo EXPORTS > ewc.def
echo hexchat_plugin_init >> ewc.def
echo hexchat_plugin_deinit >> ewc.def
ewc.obj: ewc.c makefile.mak
cl $(CFLAGS) ewc.c
clean:
del *.obj
del *.dll
del *.exp
del *.lib

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
@ -20,28 +19,75 @@
<RootNamespace>exec</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
<PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcexec</TargetName>
<OutDir>$(HexChatRel)plugins\</OutDir>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcexec</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;EXEC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>exec.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;EXEC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>exec.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
@ -52,4 +98,6 @@
<ClCompile Include="exec.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

16
plugins/fishlim/INSTALL Normal file
View File

@ -0,0 +1,16 @@
Install dependencies (on Debian/Ubuntu):
sudo apt-get install build-essential libglib2.0-dev libssl-dev
Build the plugin with:
make
Install with:
sudo make install

View File

@ -1,10 +1,9 @@
EXTRA_DIST = LICENSE fish.h irc.h keystore.h plugin_hexchat.h dh1080.h
EXTRA_DIST = INSTALL LICENSE README
libdir = $(hexchatlibdir)
lib_LTLIBRARIES = fishlim.la
fishlim_la_SOURCES = fish.c irc.c keystore.c plugin_hexchat.c dh1080.c
fishlim_la_LDFLAGS = $(PLUGIN_LDFLAGS) -module
fishlim_la_LIBADD = $(GLIB_LIBS) $(OPENSSL_LIBS)
fishlim_la_CPPFLAGS = -I$(top_srcdir)/src/common
fishlim_la_CFLAGS = $(GLIB_CFLAGS) $(OPENSSL_CFLAGS)
fishlim_la_SOURCES = fish.c irc.c keystore.c misc.c plugin_hexchat.c
fishlim_la_LDFLAGS = -avoid-version -module
fishlim_la_LIBADD =
AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/../../src/common

View File

@ -1,234 +0,0 @@
/* HexChat
*
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* For Diffie-Hellman key-exchange a 1080bit germain prime is used, the
* generator g=2 renders a field Fp from 1 to p-1. Therefore breaking it
* means to solve a discrete logarithm problem with no less than 1080bit.
*
* Base64 format is used to send the public keys over IRC.
*
* The calculated secret key is hashed with SHA-256, the result is converted
* to base64 for final use with blowfish.
*/
#include "dh1080.h"
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/sha.h>
#include <string.h>
#include <glib.h>
#define DH1080_PRIME_BITS 1080
#define DH1080_PRIME_BYTES 135
#define SHA256_DIGEST_LENGTH 32
#define B64ABC "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#define MEMZERO(x) memset(x, 0x00, sizeof(x))
/* All clients must use the same prime number to be able to keyx */
static const guchar prime1080[DH1080_PRIME_BYTES] =
{
0xFB, 0xE1, 0x02, 0x2E, 0x23, 0xD2, 0x13, 0xE8, 0xAC, 0xFA, 0x9A, 0xE8, 0xB9, 0xDF, 0xAD, 0xA3, 0xEA,
0x6B, 0x7A, 0xC7, 0xA7, 0xB7, 0xE9, 0x5A, 0xB5, 0xEB, 0x2D, 0xF8, 0x58, 0x92, 0x1F, 0xEA, 0xDE, 0x95,
0xE6, 0xAC, 0x7B, 0xE7, 0xDE, 0x6A, 0xDB, 0xAB, 0x8A, 0x78, 0x3E, 0x7A, 0xF7, 0xA7, 0xFA, 0x6A, 0x2B,
0x7B, 0xEB, 0x1E, 0x72, 0xEA, 0xE2, 0xB7, 0x2F, 0x9F, 0xA2, 0xBF, 0xB2, 0xA2, 0xEF, 0xBE, 0xFA, 0xC8,
0x68, 0xBA, 0xDB, 0x3E, 0x82, 0x8F, 0xA8, 0xBA, 0xDF, 0xAD, 0xA3, 0xE4, 0xCC, 0x1B, 0xE7, 0xE8, 0xAF,
0xE8, 0x5E, 0x96, 0x98, 0xA7, 0x83, 0xEB, 0x68, 0xFA, 0x07, 0xA7, 0x7A, 0xB6, 0xAD, 0x7B, 0xEB, 0x61,
0x8A, 0xCF, 0x9C, 0xA2, 0x89, 0x7E, 0xB2, 0x8A, 0x61, 0x89, 0xEF, 0xA0, 0x7A, 0xB9, 0x9A, 0x8A, 0x7F,
0xA9, 0xAE, 0x29, 0x9E, 0xFA, 0x7B, 0xA6, 0x6D, 0xEA, 0xFE, 0xFB, 0xEF, 0xBF, 0x0B, 0x7D, 0x8B
};
static DH *g_dh;
int
dh1080_init (void)
{
g_return_val_if_fail (g_dh == NULL, 0);
if ((g_dh = DH_new()))
{
int codes;
BIGNUM *p, *g;
p = BN_bin2bn (prime1080, DH1080_PRIME_BYTES, NULL);
g = BN_new ();
if (p == NULL || g == NULL)
return 1;
BN_set_word (g, 2);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
g_dh->p = p;
g_dh->g = g;
#else
if (!DH_set0_pqg (g_dh, p, NULL, g))
return 1;
#endif
if (DH_check (g_dh, &codes))
return codes == 0;
}
return 0;
}
void
dh1080_deinit (void)
{
g_clear_pointer (&g_dh, DH_free);
}
static inline int
DH_verifyPubKey (BIGNUM *pk)
{
int codes;
return DH_check_pub_key (g_dh, pk, &codes) && codes == 0;
}
static guchar *
dh1080_decode_b64 (const char *data, gsize *out_len)
{
GString *str = g_string_new (data);
guchar *ret;
if (str->len % 4 == 1 && str->str[str->len - 1] == 'A')
g_string_truncate (str, str->len - 1);
while (str->len % 4 != 0)
g_string_append_c (str, '=');
ret = g_base64_decode_inplace (str->str, out_len);
g_string_free (str, FALSE);
return ret;
}
static char *
dh1080_encode_b64 (const guchar *data, gsize data_len)
{
char *ret = g_base64_encode (data, data_len);
char *p;
if (!(p = strchr (ret, '=')))
{
char *new_ret = g_new(char, strlen(ret) + 2);
strcpy (new_ret, ret);
strcat (new_ret, "A");
g_free (ret);
ret = new_ret;
}
else
{
*p = '\0';
}
return ret;
}
int
dh1080_generate_key (char **priv_key, char **pub_key)
{
guchar buf[DH1080_PRIME_BYTES];
int len;
DH *dh;
const BIGNUM *dh_priv_key, *dh_pub_key;
g_assert (priv_key != NULL);
g_assert (pub_key != NULL);
dh = DHparams_dup (g_dh);
if (!dh)
return 0;
if (!DH_generate_key (dh))
{
DH_free (dh);
return 0;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
dh_pub_key = dh->pub_key;
dh_priv_key = dh->priv_key;
#else
DH_get0_key (dh, &dh_pub_key, &dh_priv_key);
#endif
MEMZERO (buf);
len = BN_bn2bin (dh_priv_key, buf);
*priv_key = dh1080_encode_b64 (buf, len);
MEMZERO (buf);
len = BN_bn2bin (dh_pub_key, buf);
*pub_key = dh1080_encode_b64 (buf, len);
OPENSSL_cleanse (buf, sizeof (buf));
DH_free (dh);
return 1;
}
int
dh1080_compute_key (const char *priv_key, const char *pub_key, char **secret_key)
{
char *pub_key_data;
gsize pub_key_len;
BIGNUM *pk;
DH *dh;
g_assert (secret_key != NULL);
/* Verify base64 strings */
if (strspn (priv_key, B64ABC) != strlen (priv_key)
|| strspn (pub_key, B64ABC) != strlen (pub_key))
return 0;
dh = DHparams_dup (g_dh);
pub_key_data = dh1080_decode_b64 (pub_key, &pub_key_len);
pk = BN_bin2bn (pub_key_data, pub_key_len, NULL);
if (DH_verifyPubKey (pk))
{
guchar shared_key[DH1080_PRIME_BYTES] = { 0 };
guchar sha256[SHA256_DIGEST_LENGTH] = { 0 };
char *priv_key_data;
gsize priv_key_len;
int shared_len;
BIGNUM *priv_key_num;
priv_key_data = dh1080_decode_b64 (priv_key, &priv_key_len);
priv_key_num = BN_bin2bn(priv_key_data, priv_key_len, NULL);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
dh->priv_key = priv_key_num;
#else
DH_set0_key (dh, NULL, priv_key_num);
#endif
shared_len = DH_compute_key (shared_key, pk, dh);
SHA256(shared_key, shared_len, sha256);
*secret_key = dh1080_encode_b64 (sha256, sizeof(sha256));
OPENSSL_cleanse (priv_key_data, priv_key_len);
g_free (priv_key_data);
}
BN_free (pk);
DH_free (dh);
g_free (pub_key_data);
return 1;
}

View File

@ -1,24 +0,0 @@
/* HexChat
*
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#pragma once
int dh1080_generate_key (char **, char **);
int dh1080_compute_key (const char *, const char *, char **);
int dh1080_init (void);
void dh1080_deinit (void);

View File

@ -22,11 +22,6 @@
*/
#ifdef __APPLE__
#define __AVAILABILITYMACROS__
#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#endif
#include <stdlib.h>
#include <string.h>
#include <openssl/blowfish.h>
@ -39,17 +34,17 @@ static const char fish_base64[64] = "./0123456789abcdefghijklmnopqrstuvwxyzABCDE
static const signed char fish_unbase64[256] = {
IB,IB,IB,IB,IB,IB,IB,IB, IB,IB,IB,IB,IB,IB,IB,IB,
IB,IB,IB,IB,IB,IB,IB,IB, IB,IB,IB,IB,IB,IB,IB,IB,
/* ! " # $ % & ' ( ) * + , - . / */
// ! " # $ % & ' ( ) * + , - . /
IB,IB,IB,IB,IB,IB,IB,IB, IB,IB,IB,IB,IB,IB, 0, 1,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
2, 3, 4, 5, 6, 7, 8, 9, 10,11,IB,IB,IB,IB,IB,IB,
/* @ A B C D E F G H I J K L M N O */
// @ A B C D E F G H I J K L M N O
IB,38,39,40,41,42,43,44, 45,46,47,48,49,50,51,52,
/* P Q R S T U V W X Y Z [ \ ] ^ _*/
// P Q R S T U V W X Y Z [ \ ] ^ _
53,54,55,56,57,58,59,60, 61,62,63,IB,IB,IB,IB,IB,
/* ` a b c d e f g h i j k l m n o */
// ` a b c d e f g h i j k l m n o
IB,12,13,14,15,16,17,18, 19,20,21,22,23,24,25,26,
/* p q r s t u v w x y z { | } ~ <del> */
// p q r s t u v w x y z { | } ~ <del>
27,28,29,30,31,32,33,34, 35,36,37,IB,IB,IB,IB,IB,
};
@ -75,11 +70,12 @@ char *fish_encrypt(const char *key, size_t keylen, const char *message) {
messagelen = strlen(message);
if (messagelen == 0) return NULL;
encrypted = g_malloc(((messagelen - 1) / 8) * 12 + 12 + 1); /* each 8-byte block becomes 12 bytes */
encrypted = malloc(((messagelen-1)/8)*12 + 12 + 1); // each 8-byte block becomes 12 bytes
end = encrypted;
if (!encrypted) return NULL;
while (*message) {
/* Read 8 bytes (a Blowfish block) */
// Read 8 bytes (a Blowfish block)
BF_LONG binary[2] = { 0, 0 };
unsigned char c;
for (i = 0; i < 8; i++) {
@ -89,10 +85,10 @@ char *fish_encrypt(const char *key, size_t keylen, const char *message) {
}
message += 8;
/* Encrypt block */
// Encrypt block
BF_encrypt(binary, &bfkey);
/* Emit FiSH-BASE64 */
// Emit FiSH-BASE64
bit = 0;
word = 1;
for (j = 0; j < 12; j++) {
@ -105,7 +101,7 @@ char *fish_encrypt(const char *key, size_t keylen, const char *message) {
}
}
/* Stop if a null terminator was found */
// Stop if a null terminator was found
if (c == '\0') break;
}
*end = '\0';
@ -123,18 +119,19 @@ char *fish_decrypt(const char *key, size_t keylen, const char *data) {
unsigned char d;
BF_set_key(&bfkey, keylen, (const unsigned char*)key);
decrypted = g_malloc(strlen(data) + 1);
decrypted = malloc(strlen(data)+1);
end = decrypted;
if (!decrypted) return NULL;
while (*data) {
/* Convert from FiSH-BASE64 */
// Convert from FiSH-BASE64
BF_LONG binary[2] = { 0, 0 };
bit = 0;
word = 1;
for (i = 0; i < 12; i++) {
d = fish_unbase64[(const unsigned char)*(data++)];
if (d == IB) goto decrypt_end;
binary[word] |= (unsigned long)d << bit;
binary[word] |= d << bit;
bit += 6;
if (i == 5) {
bit = 0;
@ -142,10 +139,10 @@ char *fish_decrypt(const char *key, size_t keylen, const char *data) {
}
}
/* Decrypt block */
// Decrypt block
BF_decrypt(binary, &bfkey);
/* Copy to buffer */
// Copy to buffer
GET_BYTES(end, binary[0]);
GET_BYTES(end, binary[1]);
}
@ -163,14 +160,14 @@ char *fish_encrypt_for_nick(const char *nick, const char *data) {
char *key;
char *encrypted;
/* Look for key */
// Look for key
key = keystore_get_key(nick);
if (!key) return NULL;
/* Encrypt */
// Encrypt
encrypted = fish_encrypt(key, strlen(key), data);
g_free(key);
free(key);
return encrypted;
}
@ -181,14 +178,14 @@ char *fish_encrypt_for_nick(const char *nick, const char *data) {
char *fish_decrypt_from_nick(const char *nick, const char *data) {
char *key;
char *decrypted;
/* Look for key */
// Look for key
key = keystore_get_key(nick);
if (!key) return NULL;
/* Decrypt */
// Decrypt
decrypted = fish_decrypt(key, strlen(key), data);
g_free(key);
free(key);
return decrypted;
}

View File

@ -25,10 +25,9 @@
#ifndef FISH_H
#define FISH_H
#include <stdbool.h>
#include <stddef.h>
#include <glib.h>
char *fish_encrypt(const char *key, size_t keylen, const char *message);
char *fish_decrypt(const char *key, size_t keylen, const char *data);
char *fish_encrypt_for_nick(const char *nick, const char *data);

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
@ -20,19 +19,57 @@
<RootNamespace>fishlim</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
<PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcfishlim</TargetName>
<OutDir>$(HexChatRel)plugins\</OutDir>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcfishlim</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>fishlim.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
@ -40,10 +77,19 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>fishlim.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
@ -53,18 +99,21 @@
<None Include="fishlim.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="dh1080.h" />
<ClInclude Include="bool.h" />
<ClInclude Include="fish.h" />
<ClInclude Include="irc.h" />
<ClInclude Include="keystore.h" />
<ClInclude Include="misc.h" />
<ClInclude Include="plugin_hexchat.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dh1080.c" />
<ClCompile Include="fish.c" />
<ClCompile Include="irc.c" />
<ClCompile Include="keystore.c" />
<ClCompile Include="misc.c" />
<ClCompile Include="plugin_hexchat.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -32,6 +32,9 @@
<ClInclude Include="keystore.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="misc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="plugin_hexchat.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -46,6 +49,9 @@
<ClCompile Include="keystore.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="misc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="plugin_hexchat.c">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -22,9 +22,8 @@
*/
#include "config.h"
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include "irc.h"
/**
@ -32,28 +31,26 @@
* at spaces. The prefix and command is extracted from the message, and
* parameters_offset is set to the index of the first parameter.
*/
gboolean irc_parse_message(const char *words[],
bool irc_parse_message(const char *words[],
const char **prefix, const char **command,
size_t *parameters_offset) {
size_t w = 1;
if (prefix) *prefix = NULL;
if (command) *command = NULL;
/* See if the message starts with a prefix (sender user) */
// See if the message starts with a prefix (sender user)
if (words[w][0] == ':') {
if (prefix) *prefix = &words[w][1];
w++;
}
/* Check command */
if (words[w][0] == '\0') return FALSE;
// Check command
if (words[w][0] == '\0') return false;
if (command) *command = words[w];
w++;
if (parameters_offset)
*parameters_offset = w;
return TRUE;
*parameters_offset = w;
return true;
}
@ -68,15 +65,48 @@ gboolean irc_parse_message(const char *words[],
*/
char *irc_prefix_get_nick(const char *prefix) {
const char *end;
char *nick;
size_t length;
if (!prefix) return NULL;
/* Find end of nick */
// Find end of nick
end = prefix;
while (*end != '\0' && *end != '!' && *end != '@') end++;
/* Allocate string */
// Allocate string
length = end - prefix;
return g_strndup (prefix, length);
nick = malloc(length+1);
if (!nick) return NULL;
// Copy to string
memcpy(nick, prefix, length);
nick[length] = '\0';
return nick;
}
/**
* Compares two nick names. Return 0 if equal. Otherwise the return value is
* less than zero if a is less than b or greater than zero if a is greater
* than b.
*/
int irc_nick_cmp(const char *a, const char *b) {
char ac;
char bc;
char diff;
for (;;) {
ac = *(a++);
bc = *(b++);
// Change into IRC uppercase (see RFC 2812 section 2.2)
if (ac >= 'a' && ac <= '~') ac &= ~0x20;
if (bc >= 'a' && bc <= '~') bc &= ~0x20;
diff = ac - bc;
if (diff) return diff;
if (!ac) return 0;
}
}

View File

@ -25,13 +25,14 @@
#ifndef IRC_H
#define IRC_H
#include <stdbool.h>
#include <stddef.h>
#include <glib.h>
gboolean irc_parse_message(const char *words[],
bool irc_parse_message(const char *words[],
const char **prefix, const char **command,
size_t *parameters_offset);
char *irc_prefix_get_nick(const char *prefix);
int irc_nick_cmp(const char *a, const char *b);
#endif

View File

@ -22,13 +22,12 @@
*/
#include "config.h"
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include "irc.h"
#include "fish.h"
#include "misc.h"
#include "keystore.h"
#include "plugin_hexchat.h"
@ -39,7 +38,7 @@ static char *keystore_password = NULL;
/**
* Opens the key store file: ~/.config/hexchat/addon_fishlim.conf
*/
static GKeyFile *getConfigFile(void) {
static GKeyFile *getConfigFile() {
gchar *filename = get_config_filename();
GKeyFile *keyfile = g_key_file_new();
@ -55,30 +54,14 @@ static GKeyFile *getConfigFile(void) {
/**
* Returns the key store password, or the default.
*/
static const char *get_keystore_password(void) {
static const char *get_keystore_password() {
return (keystore_password != NULL ?
keystore_password :
/* Silly default value... */
// Silly default value...
"blowinikey");
}
static char *escape_nickname(const char *nick) {
char *escaped = g_strdup(nick);
char *p = escaped;
while (*p) {
if (*p == '[')
*p = '~';
else if (*p == ']')
*p = '!';
++p;
}
return escaped;
}
/**
* Gets a value for a nick/channel from addon_fishlim.conf. Unlike
* g_key_file_get_string, this function is case insensitive.
@ -104,21 +87,17 @@ static gchar *get_nick_value(GKeyFile *keyfile, const char *nick, const char *it
* Extracts a key from the key store file.
*/
char *keystore_get_key(const char *nick) {
/* Get the key */
// Get the key
GKeyFile *keyfile = getConfigFile();
char *escaped_nick = escape_nickname(nick);
gchar *value = get_nick_value(keyfile, escaped_nick, "key");
gchar *value = get_nick_value(keyfile, nick, "key");
g_key_file_free(keyfile);
g_free(escaped_nick);
if (!value)
return NULL;
if (!value) return NULL;
if (strncmp(value, "+OK ", 4) != 0) {
/* Key is stored in plaintext */
return value;
// Key is stored in plaintext
return import_glib_string(value);
} else {
/* Key is encrypted */
// Key is encrypted
const char *encrypted = value+4;
const char *password = get_keystore_password();
char *decrypted = fish_decrypt(password, strlen(password), encrypted);
@ -130,10 +109,10 @@ char *keystore_get_key(const char *nick) {
/**
* Deletes a nick and the associated key in the key store file.
*/
static gboolean delete_nick(GKeyFile *keyfile, const char *nick) {
static bool delete_nick(GKeyFile *keyfile, const char *nick) {
gchar **group;
gchar **groups = g_key_file_get_groups(keyfile, NULL);
gboolean ok = FALSE;
bool ok = false;
for (group = groups; *group != NULL; group++) {
if (!irc_nick_cmp(*group, nick)) {
@ -146,100 +125,85 @@ static gboolean delete_nick(GKeyFile *keyfile, const char *nick) {
return ok;
}
#if !GLIB_CHECK_VERSION(2,40,0)
/**
* Writes the key store file to disk.
*/
static gboolean keyfile_save_to_file (GKeyFile *keyfile, char *filename) {
gboolean ok;
/* Serialize */
static bool save_keystore(GKeyFile *keyfile) {
char *filename;
bool ok;
// Serialize
gsize file_length;
gchar *file_data = g_key_file_to_data(keyfile, &file_length, NULL);
if (!file_data)
return FALSE;
/* Write to file */
ok = g_file_set_contents (filename, file_data, file_length, NULL);
g_free(file_data);
return ok;
}
#endif
/**
* Writes the key store file to disk.
*/
static gboolean save_keystore(GKeyFile *keyfile) {
char *filename;
gboolean ok;
if (!file_data) return false;
// Write to file
filename = get_config_filename();
#if !GLIB_CHECK_VERSION(2,40,0)
ok = keyfile_save_to_file (keyfile, filename);
#else
ok = g_key_file_save_to_file (keyfile, filename, NULL);
#endif
g_free (filename);
ok = g_file_set_contents(filename, file_data, file_length, NULL);
g_free(filename);
g_free(file_data);
return ok;
}
/**
* Sets a key in the key store file.
*/
gboolean keystore_store_key(const char *nick, const char *key) {
bool keystore_store_key(const char *nick, const char *key) {
const char *password;
char *encrypted;
char *wrapped;
gboolean ok = FALSE;
bool ok = false;
GKeyFile *keyfile = getConfigFile();
char *escaped_nick = escape_nickname(nick);
/* Remove old key */
delete_nick(keyfile, escaped_nick);
/* Add new key */
// Remove old key
delete_nick(keyfile, nick);
// Add new key
password = get_keystore_password();
if (password) {
/* Encrypt the password */
// Encrypt the password
encrypted = fish_encrypt(password, strlen(password), key);
if (!encrypted) goto end;
/* Prepend "+OK " */
// Prepend "+OK "
wrapped = g_strconcat("+OK ", encrypted, NULL);
g_free(encrypted);
/* Store encrypted in file */
g_key_file_set_string(keyfile, escaped_nick, "key", wrapped);
g_free(wrapped);
// Store encrypted in file
g_key_file_set_string(keyfile, nick, "key", wrapped);
free(wrapped);
} else {
/* Store unencrypted in file */
g_key_file_set_string(keyfile, escaped_nick, "key", key);
// Store unencrypted in file
g_key_file_set_string(keyfile, nick, "key", key);
}
/* Save key store file */
// Save key store file
ok = save_keystore(keyfile);
end:
g_key_file_free(keyfile);
g_free(escaped_nick);
return ok;
}
/**
* Deletes a nick from the key store.
*/
gboolean keystore_delete_nick(const char *nick) {
bool keystore_delete_nick(const char *nick) {
GKeyFile *keyfile = getConfigFile();
char *escaped_nick = escape_nickname(nick);
/* Delete entry */
gboolean ok = delete_nick(keyfile, escaped_nick);
// Delete entry
bool ok = delete_nick(keyfile, nick);
/* Save */
// Save
if (ok) save_keystore(keyfile);
g_key_file_free(keyfile);
g_free(escaped_nick);
return ok;
}
void keystore_secure_free(void *ptr, size_t size) {
secure_erase(ptr, size);
free(ptr);
}

View File

@ -25,13 +25,14 @@
#ifndef KEYSTORE_H
#define KEYSTORE_H
#include <stdbool.h>
#include <stddef.h>
#include <glib.h>
char *keystore_get_key(const char *nick);
gboolean keystore_store_key(const char *nick, const char *key);
gboolean keystore_delete_nick(const char *nick);
bool keystore_store_key(const char *nick, const char *key);
bool keystore_delete_nick(const char *nick);
void keystore_secure_free(void *ptr, size_t size);
#endif

54
plugins/fishlim/misc.c Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include "misc.h"
void secure_erase(void *ptr, size_t size) {
// "volatile" prevents this code from being optimized away
volatile char* volptr = ptr;
while (size--) *volptr++ = 0;
}
/**
* Re-allocates a string with the native allocator.
*/
char *import_glib_string(gchar *gstr) {
size_t size;
char *native;
if (g_mem_is_system_malloc()) return gstr;
size = strlen(gstr)+1;
native = malloc(size);
memcpy(native, gstr, size);
secure_erase(gstr, size);
g_free(gstr);
return native;
}

36
plugins/fishlim/misc.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef MISC_H
#define MISC_H
void secure_erase(void *ptr, size_t size);
#ifdef __G_LIB_H__
char *import_glib_string(gchar *gstr);
#endif
#endif

View File

@ -1,7 +1,6 @@
/*
Copyright (c) 2010-2011 Samuel Lidén Borell <samuel@kodafritt.se>
Copyright (c) 2015 <the.cypher@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -23,84 +22,56 @@
*/
#include "config.h"
#include <glib.h>
#include <stdlib.h>
#include <string.h>
// #pragma GCC visibility push(default)
#include "hexchat-plugin.h"
#define HEXCHAT_MAX_WORDS 32
// #pragma GCC visibility pop
//#define EXPORT __attribute((visibility("default")))
//#define EXPORT
#include "fish.h"
#include "dh1080.h"
#include "keystore.h"
#include "irc.h"
static const char plugin_name[] = "FiSHLiM";
static const char plugin_desc[] = "Encryption plugin for the FiSH protocol. Less is More!";
static const char plugin_version[] = "0.1.0";
static const char plugin_version[] = "0.0.16";
static const char usage_setkey[] = "Usage: SETKEY [<nick or #channel>] <password>, sets the key for a channel or nick";
static const char usage_delkey[] = "Usage: DELKEY <nick or #channel>, deletes the key for a channel or nick";
static const char usage_keyx[] = "Usage: KEYX [<nick>], performs DH1080 key-exchange with <nick>";
static const char usage_topic[] = "Usage: TOPIC+ <topic>, sets a new encrypted topic for the current channel";
static const char usage_notice[] = "Usage: NOTICE+ <nick or #channel> <notice>";
static const char usage_msg[] = "Usage: MSG+ <nick or #channel> <message>";
static hexchat_plugin *ph;
static GHashTable *pending_exchanges;
/**
* Returns the path to the key store file.
*/
gchar *get_config_filename(void) {
char *filename_fs, *filename_utf8;
filename_utf8 = g_build_filename(hexchat_get_info(ph, "configdir"), "addon_fishlim.conf", NULL);
filename_fs = g_filename_from_utf8 (filename_utf8, -1, NULL, NULL, NULL);
g_free (filename_utf8);
return filename_fs;
gchar *get_config_filename() {
return g_build_filename(hexchat_get_info(ph, "configdir"), "addon_fishlim.conf", NULL);
}
static inline gboolean irc_is_query (const char *name) {
const char *chantypes = hexchat_list_str (ph, NULL, "chantypes");
return strchr (chantypes, name[0]) == NULL;
/**
* Appends data to a string. Returns true if there was sufficient memory.
* Frees *s and returns false if an error occurs.
*/
static bool append(char **s, size_t *length, const char *data) {
size_t datalen = strlen(data);
char *extended = realloc(*s, *length + datalen + 1);
if (!extended) {
free(*s);
return false;
}
memcpy(extended + *length, data, datalen + 1);
*s = extended;
*length += datalen;
return true;
}
static hexchat_context *find_context_on_network (const char *name) {
hexchat_list *channels;
hexchat_context *ret = NULL;
int id;
if (hexchat_get_prefs(ph, "id", NULL, &id) != 2)
return NULL;
channels = hexchat_list_get(ph, "channels");
if (!channels)
return NULL;
while (hexchat_list_next(ph, channels)) {
int chan_id = hexchat_list_int(ph, channels, "id");
const char *chan_name = hexchat_list_str(ph, channels, "channel");
if (chan_id == id && chan_name && hexchat_nickcmp (ph, chan_name, name) == 0) {
ret = (hexchat_context*)hexchat_list_str(ph, channels, "context");
break;
}
};
hexchat_list_free(ph, channels);
return ret;
}
int irc_nick_cmp(const char *a, const char *b) {
return hexchat_nickcmp (ph, a, b);
}
/*static int handle_debug(char *word[], char *word_eol[], void *userdata) {
hexchat_printf(ph, "debug incoming: ");
@ -116,26 +87,26 @@ int irc_nick_cmp(const char *a, const char *b) {
*/
static int handle_outgoing(char *word[], char *word_eol[], void *userdata) {
const char *own_nick;
/* Encrypt the message if possible */
// Encrypt the message if possible
const char *channel = hexchat_get_info(ph, "channel");
char *encrypted = fish_encrypt_for_nick(channel, word_eol[1]);
if (!encrypted) return HEXCHAT_EAT_NONE;
/* Display message */
// Display message
own_nick = hexchat_get_info(ph, "nick");
hexchat_emit_print(ph, "Your Message", own_nick, word_eol[1], NULL);
/* Send message */
// Send message
hexchat_commandf(ph, "PRIVMSG %s :+OK %s", channel, encrypted);
g_free(encrypted);
free(encrypted);
return HEXCHAT_EAT_HEXCHAT;
}
/**
* Called when a channel message or private message is received.
*/
static int handle_incoming(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata) {
static int handle_incoming(char *word[], char *word_eol[], void *userdata) {
const char *prefix;
const char *command;
const char *recipient;
@ -143,201 +114,108 @@ static int handle_incoming(char *word[], char *word_eol[], hexchat_event_attrs *
const char *peice;
char *sender_nick;
char *decrypted;
char *message;
size_t w;
size_t ew;
size_t uw;
char prefix_char = 0;
GString *message;
size_t length;
if (!irc_parse_message((const char **)word, &prefix, &command, &w))
return HEXCHAT_EAT_NONE;
/* Topic (command 332) has an extra parameter */
// Topic (command 332) has an extra parameter
if (!strcmp(command, "332")) w++;
/* Look for encrypted data */
// Look for encrypted data
for (ew = w+1; ew < HEXCHAT_MAX_WORDS-1; ew++) {
const char *s = (ew == w+1 ? word[ew]+1 : word[ew]);
if (*s && (s[1] == '+' || s[1] == 'm')) { prefix_char = *(s++); }
else { prefix_char = 0; }
if (strcmp(s, "+OK") == 0 || strcmp(s, "mcps") == 0) goto has_encrypted_data;
}
return HEXCHAT_EAT_NONE;
has_encrypted_data: ;
/* Extract sender nick and recipient nick/channel */
// Extract sender nick and recipient nick/channel
sender_nick = irc_prefix_get_nick(prefix);
recipient = word[w];
/* Try to decrypt with these (the keys are searched for in the key store) */
// Try to decrypt with these (the keys are searched for in the key store)
encrypted = word[ew+1];
decrypted = fish_decrypt_from_nick(recipient, encrypted);
if (!decrypted) decrypted = fish_decrypt_from_nick(sender_nick, encrypted);
/* Check for error */
// Check for error
if (!decrypted) goto decrypt_error;
/* Build unecrypted message */
message = g_string_sized_new (100); /* TODO: more accurate estimation of size */
g_string_append (message, "RECV");
if (attrs->server_time_utc)
{
GTimeVal tv = { (glong)attrs->server_time_utc, 0 };
char *timestamp = g_time_val_to_iso8601 (&tv);
g_string_append (message, " @time=");
g_string_append (message, timestamp);
g_free (timestamp);
}
// Build unecrypted message
message = NULL;
length = 0;
if (!append(&message, &length, "RECV")) goto decrypt_error;
for (uw = 1; uw < HEXCHAT_MAX_WORDS; uw++) {
if (word[uw][0] != '\0')
g_string_append_c (message, ' ');
if (word[uw][0] != '\0' && !append(&message, &length, " ")) goto decrypt_error;
if (uw == ew) {
/* Add the encrypted data */
// Add the encrypted data
peice = decrypted;
uw++; /* Skip "OK+" */
uw++; // Skip "OK+"
if (ew == w+1) {
/* Prefix with colon, which gets stripped out otherwise */
g_string_append_c (message, ':');
// Prefix with colon, which gets stripped out otherwise
if (!append(&message, &length, ":")) goto decrypt_error;
}
if (prefix_char) {
g_string_append_c (message, prefix_char);
}
} else {
/* Add unencrypted data (for example, a prefix from a bouncer or bot) */
// Add unencrypted data (for example, a prefix from a bouncer or bot)
peice = word[uw];
}
g_string_append (message, peice);
if (!append(&message, &length, peice)) goto decrypt_error;
}
g_free(decrypted);
/* Simulate unencrypted message */
/* hexchat_printf(ph, "simulating: %s\n", message->str); */
hexchat_command(ph, message->str);
g_string_free (message, TRUE);
g_free(sender_nick);
free(decrypted);
// Simulate unencrypted message
//hexchat_printf(ph, "simulating: %s\n", message);
hexchat_command(ph, message);
free(message);
free(sender_nick);
return HEXCHAT_EAT_HEXCHAT;
decrypt_error:
g_free(decrypted);
g_free(sender_nick);
free(decrypted);
free(sender_nick);
return HEXCHAT_EAT_NONE;
}
static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) {
const char *dh_message = word[4];
const char *dh_pubkey = word[5];
hexchat_context *query_ctx;
const char *prefix;
gboolean cbc;
char *sender, *secret_key, *priv_key = NULL;
if (!*dh_message || !*dh_pubkey || strlen(dh_pubkey) != 181)
return HEXCHAT_EAT_NONE;
if (!irc_parse_message((const char**)word, &prefix, NULL, NULL) || !prefix)
return HEXCHAT_EAT_NONE;
sender = irc_prefix_get_nick(prefix);
query_ctx = find_context_on_network(sender);
if (query_ctx)
hexchat_set_context(ph, query_ctx);
dh_message++; /* : prefix */
if (*dh_message == '+' || *dh_message == '-')
dh_message++; /* identify-msg */
cbc = g_strcmp0 (word[6], "CBC") == 0;
if (!strcmp(dh_message, "DH1080_INIT")) {
char *pub_key;
if (cbc) {
hexchat_print(ph, "Received key exchange for CBC mode which is not supported.");
goto cleanup;
}
hexchat_printf(ph, "Received public key from %s, sending mine...", sender);
if (dh1080_generate_key(&priv_key, &pub_key)) {
hexchat_commandf(ph, "quote NOTICE %s :DH1080_FINISH %s", sender, pub_key);
g_free(pub_key);
} else {
hexchat_print(ph, "Failed to generate keys");
goto cleanup;
}
} else if (!strcmp (dh_message, "DH1080_FINISH")) {
char *sender_lower = g_ascii_strdown(sender, -1);
/* FIXME: Properly respect irc casing */
priv_key = g_hash_table_lookup(pending_exchanges, sender_lower);
g_hash_table_steal(pending_exchanges, sender_lower);
g_free(sender_lower);
if (cbc) {
hexchat_print(ph, "Received key exchange for CBC mode which is not supported.");
goto cleanup;
}
if (!priv_key) {
hexchat_printf(ph, "Received a key exchange response for unknown user: %s", sender);
goto cleanup;
}
} else {
/* Regular notice */
g_free(sender);
return HEXCHAT_EAT_NONE;
}
if (dh1080_compute_key(priv_key, dh_pubkey, &secret_key)) {
keystore_store_key(sender, secret_key);
hexchat_printf(ph, "Stored new key for %s", sender);
g_free(secret_key);
} else {
hexchat_print(ph, "Failed to create secret key!");
}
cleanup:
g_free(sender);
g_free(priv_key);
return HEXCHAT_EAT_ALL;
}
/**
* Command handler for /setkey
*/
static int handle_setkey(char *word[], char *word_eol[], void *userdata) {
const char *nick;
const char *key;
/* Check syntax */
// Check syntax
if (*word[2] == '\0') {
hexchat_printf(ph, "%s\n", usage_setkey);
return HEXCHAT_EAT_HEXCHAT;
}
if (*word[3] == '\0') {
/* /setkey password */
// /setkey password
nick = hexchat_get_info(ph, "channel");
key = word_eol[2];
} else {
/* /setkey #channel password */
// /setkey #channel password
nick = word[2];
key = word_eol[3];
}
/* Set password */
// Set password
if (keystore_store_key(nick, key)) {
hexchat_printf(ph, "Stored key for %s\n", nick);
} else {
hexchat_printf(ph, "\00305Failed to store key in addon_fishlim.conf\n");
hexchat_printf(ph, "\00305Failed to store key in blow.ini\n", nick, key);
}
return HEXCHAT_EAT_HEXCHAT;
}
@ -346,174 +224,25 @@ static int handle_setkey(char *word[], char *word_eol[], void *userdata) {
*/
static int handle_delkey(char *word[], char *word_eol[], void *userdata) {
const char *nick;
/* Check syntax */
// Check syntax
if (*word[2] == '\0' || *word[3] != '\0') {
hexchat_printf(ph, "%s\n", usage_delkey);
return HEXCHAT_EAT_HEXCHAT;
}
nick = g_strstrip (word_eol[2]);
/* Delete the given nick from the key store */
nick = word_eol[2];
// Delete the given nick from the key store
if (keystore_delete_nick(nick)) {
hexchat_printf(ph, "Deleted key for %s\n", nick);
} else {
hexchat_printf(ph, "\00305Failed to delete key in addon_fishlim.conf!\n");
hexchat_printf(ph, "\00305Failed to delete key in blow.ini!\n", nick);
}
return HEXCHAT_EAT_HEXCHAT;
}
static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
const char *target = word[2];
hexchat_context *query_ctx = NULL;
char *pub_key, *priv_key;
int ctx_type;
if (*target)
query_ctx = find_context_on_network(target);
else {
target = hexchat_get_info(ph, "channel");
query_ctx = hexchat_get_context (ph);
}
if (query_ctx) {
hexchat_set_context(ph, query_ctx);
ctx_type = hexchat_list_int(ph, NULL, "type");
}
if ((query_ctx && ctx_type != 3) || (!query_ctx && !irc_is_query(target))) {
hexchat_print(ph, "You can only exchange keys with individuals");
return HEXCHAT_EAT_ALL;
}
if (dh1080_generate_key(&priv_key, &pub_key)) {
g_hash_table_replace (pending_exchanges, g_ascii_strdown(target, -1), priv_key);
hexchat_commandf(ph, "quote NOTICE %s :DH1080_INIT %s", target, pub_key);
hexchat_printf(ph, "Sent public key to %s, waiting for reply...", target);
g_free(pub_key);
} else {
hexchat_print(ph, "Failed to generate keys");
}
return HEXCHAT_EAT_ALL;
}
/**
* Command handler for /topic+
*/
static int handle_crypt_topic(char *word[], char *word_eol[], void *userdata) {
const char *target;
const char *topic = word_eol[2];
char *buf;
if (!*topic) {
hexchat_print(ph, usage_topic);
return HEXCHAT_EAT_ALL;
}
if (hexchat_list_int(ph, NULL, "type") != 2) {
hexchat_printf(ph, "Please change to the channel window where you want to set the topic!");
return HEXCHAT_EAT_ALL;
}
target = hexchat_get_info(ph, "channel");
buf = fish_encrypt_for_nick(target, topic);
if (buf == NULL) {
hexchat_printf(ph, "/topic+ error, no key found for %s", target);
return HEXCHAT_EAT_ALL;
}
hexchat_commandf(ph, "TOPIC %s +OK %s", target, buf);
g_free(buf);
return HEXCHAT_EAT_ALL;
}
/**
* Command handler for /notice+
*/
static int handle_crypt_notice(char *word[], char *word_eol[], void *userdata)
{
const char *target = word[2];
const char *notice = word_eol[3];
char *buf;
if (!*target || !*notice) {
hexchat_print(ph, usage_notice);
return HEXCHAT_EAT_ALL;
}
buf = fish_encrypt_for_nick(target, notice);
if (buf == NULL) {
hexchat_printf(ph, "/notice+ error, no key found for %s.", target);
return HEXCHAT_EAT_ALL;
}
hexchat_commandf(ph, "quote NOTICE %s :+OK %s", target, buf);
hexchat_emit_print(ph, "Notice Sent", target, notice);
g_free(buf);
return HEXCHAT_EAT_ALL;
}
/**
* Command handler for /msg+
*/
static int handle_crypt_msg(char *word[], char *word_eol[], void *userdata)
{
const char *target = word[2];
const char *message = word_eol[3];
hexchat_context *query_ctx;
char *buf;
if (!*target || !*message) {
hexchat_print(ph, usage_msg);
return HEXCHAT_EAT_ALL;
}
buf = fish_encrypt_for_nick(target, message);
if (buf == NULL) {
hexchat_printf(ph, "/msg+ error, no key found for %s", target);
return HEXCHAT_EAT_ALL;
}
hexchat_commandf(ph, "PRIVMSG %s :+OK %s", target, buf);
query_ctx = find_context_on_network(target);
if (query_ctx) {
hexchat_set_context(ph, query_ctx);
/* FIXME: Mode char */
hexchat_emit_print(ph, "Your Message", hexchat_get_info(ph, "nick"),
message, "", "");
}
else {
hexchat_emit_print(ph, "Message Send", target, message);
}
g_free(buf);
return HEXCHAT_EAT_ALL;
}
static int handle_crypt_me(char *word[], char *word_eol[], void *userdata) {
const char *channel = hexchat_get_info(ph, "channel");
char *buf;
buf = fish_encrypt_for_nick(channel, word_eol[2]);
if (!buf)
return HEXCHAT_EAT_NONE;
hexchat_commandf(ph, "PRIVMSG %s :\001ACTION +OK %s \001", channel, buf);
hexchat_emit_print(ph, "Your Action", hexchat_get_info(ph, "nick"),
word_eol[2], NULL);
g_free(buf);
return HEXCHAT_EAT_ALL;
}
/**
* Returns the plugin name version information.
*/
@ -533,44 +262,30 @@ int hexchat_plugin_init(hexchat_plugin *plugin_handle,
const char **version,
char *arg) {
ph = plugin_handle;
/* Send our info to HexChat */
*name = plugin_name;
*desc = plugin_desc;
*version = plugin_version;
/* Register commands */
hexchat_hook_command(ph, "SETKEY", HEXCHAT_PRI_NORM, handle_setkey, usage_setkey, NULL);
hexchat_hook_command(ph, "DELKEY", HEXCHAT_PRI_NORM, handle_delkey, usage_delkey, NULL);
hexchat_hook_command(ph, "KEYX", HEXCHAT_PRI_NORM, handle_keyx, usage_keyx, NULL);
hexchat_hook_command(ph, "TOPIC+", HEXCHAT_PRI_NORM, handle_crypt_topic, usage_topic, NULL);
hexchat_hook_command(ph, "NOTICE+", HEXCHAT_PRI_NORM, handle_crypt_notice, usage_notice, NULL);
hexchat_hook_command(ph, "MSG+", HEXCHAT_PRI_NORM, handle_crypt_msg, usage_msg, NULL);
hexchat_hook_command(ph, "ME", HEXCHAT_PRI_NORM, handle_crypt_me, NULL, NULL);
/* Add handlers */
hexchat_hook_command(ph, "", HEXCHAT_PRI_NORM, handle_outgoing, NULL, NULL);
hexchat_hook_server(ph, "NOTICE", HEXCHAT_PRI_HIGHEST, handle_keyx_notice, NULL);
hexchat_hook_server_attrs(ph, "NOTICE", HEXCHAT_PRI_NORM, handle_incoming, NULL);
hexchat_hook_server_attrs(ph, "PRIVMSG", HEXCHAT_PRI_NORM, handle_incoming, NULL);
/* hexchat_hook_server(ph, "RAW LINE", HEXCHAT_PRI_NORM, handle_debug, NULL); */
hexchat_hook_server_attrs(ph, "TOPIC", HEXCHAT_PRI_NORM, handle_incoming, NULL);
hexchat_hook_server_attrs(ph, "332", HEXCHAT_PRI_NORM, handle_incoming, NULL);
if (!dh1080_init())
return 0;
pending_exchanges = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
hexchat_hook_server(ph, "NOTICE", HEXCHAT_PRI_NORM, handle_incoming, NULL);
hexchat_hook_server(ph, "PRIVMSG", HEXCHAT_PRI_NORM, handle_incoming, NULL);
//hexchat_hook_server(ph, "RAW LINE", HEXCHAT_PRI_NORM, handle_debug, NULL);
hexchat_hook_server(ph, "TOPIC", HEXCHAT_PRI_NORM, handle_incoming, NULL);
hexchat_hook_server(ph, "332", HEXCHAT_PRI_NORM, handle_incoming, NULL);
hexchat_printf(ph, "%s plugin loaded\n", plugin_name);
/* Return success */
return 1;
}
int hexchat_plugin_deinit(void) {
g_clear_pointer(&pending_exchanges, g_hash_table_destroy);
dh1080_deinit();
hexchat_printf(ph, "%s plugin unloaded\n", plugin_name);
return 1;
}

View File

@ -25,8 +25,7 @@
#ifndef PLUGIN_HEXCHAT_H
#define PLUGIN_HEXCHAT_H
gchar *get_config_filename(void);
int irc_nick_cmp (const char *, const char *);
gchar *get_config_filename();
#endif

91
plugins/fishlim/test.c Normal file
View File

@ -0,0 +1,91 @@
/*
Copyright (c) 2010 Samuel Lidén Borell <samuel@kodafritt.se>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include "fish.h"
// We can't use the HexChat plugin API from here...
gchar *get_config_filename() {
const gchar *homedir = g_get_home_dir();
return g_build_filename(homedir, ".xchat2", "blow.ini", NULL);
}
static int decrypt(int nick_count, char *nicks[]) {
char encrypted[8192];
while (fgets(encrypted, sizeof(encrypted), stdin)) {
char *msg;
for (int i = 0; i < nick_count; i++) {
msg = fish_decrypt_from_nick(nicks[i], encrypted);
if (msg) goto success;
}
fprintf(stderr, "None of the recipients were found in the key store!\n");
return 1;
success:
fprintf(stderr, "Decrypted text >>>%s<<<\n", msg);
}
return 0;
}
static int encrypt(int nick_count, char *nicks[]) {
char message[8192];
while (fgets(message, sizeof(message), stdin)) {
// Remove newline character
char *newline = strchr(message, '\n');
if (newline) *newline = '\0';
bool error = false;
for (int i = 0; i < nick_count; i++) {
char *encrypted = fish_encrypt_for_nick(nicks[i], message);
if (encrypted) {
fprintf(stderr, "Encrypted [%s]: >>>%s<<<\n", nicks[i], encrypted);
} else {
error = true;
}
}
if (error) {
fprintf(stderr, "Some of the recipients were't found in the key store!\n");
return 1;
}
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "usage: %s [-e] nick...\n", argv[0]);
return 2;
}
if (strcmp(argv[1], "-e") == 0) {
return encrypt(argc-2, &argv[2]);
} else {
return decrypt(argc-1, &argv[1]);
}
}

69
plugins/gtkpref/gtkpref.c Normal file
View File

@ -0,0 +1,69 @@
/* HexChat
* Copyright (c) 2011-2012 Berke Viktor.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <windows.h>
#include "hexchat-plugin.h"
static hexchat_plugin *ph; /* plugin handle */
static void
launch_tool ()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory (&si, sizeof (si));
si.cb = sizeof (si);
ZeroMemory (&pi, sizeof (pi));
if (!CreateProcess ( NULL, "gtk2-prefs.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
hexchat_print (ph, "Error launching the GTK+ Preference Tool! Maybe the executable is missing?");
}
CloseHandle (pi.hProcess);
CloseHandle (pi.hThread);
}
int
hexchat_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
{
ph = plugin_handle;
*plugin_name = "GTKPref";
*plugin_desc = "GTK+ Preference Tool Launcher";
*plugin_version = "1.0";
hexchat_hook_command (ph, "GTKPREF", HEXCHAT_PRI_NORM, launch_tool, 0, 0);
hexchat_command (ph, "MENU -ietc\\gtkpref.png ADD \"Settings/GTK+ Preferences\" \"GTKPREF\"");
return 1; /* return 1 for success */
}
int
hexchat_plugin_deinit (void)
{
hexchat_command (ph, "MENU DEL \"Settings/GTK+ Preferences\"");
return 1;
}

View File

@ -0,0 +1,18 @@
include "..\..\src\makeinc.mak"
all: gtkpref.obj gtkpref.def
link $(LDFLAGS) $(LIBS) /dll /out:xcgtkpref.dll /def:gtkpref.def gtkpref.obj
gtkpref.def:
echo EXPORTS > gtkpref.def
echo hexchat_plugin_init >> gtkpref.def
echo hexchat_plugin_deinit >> gtkpref.def
gtkpref.obj: gtkpref.c makefile.mak
cl $(CFLAGS) $(GLIB) /I.. gtkpref.c
clean:
del *.obj
del *.dll
del *.exp
del *.lib

View File

@ -1,9 +0,0 @@
libdir = $(hexchatlibdir)
lib_LTLIBRARIES = lua.la
lua_la_SOURCES = lua.c
lua_la_LDFLAGS = $(PLUGIN_LDFLAGS) -module
lua_la_LIBADD = $(LUA_LIBS) $(GLIB_LIBS)
lua_la_CPPFLAGS = -I$(top_srcdir)/src/common
lua_la_CFLAGS = $(GLIB_CFLAGS) $(LUA_CFLAGS)

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4C0F3940-2EEE-4646-82F7-6CE75B9A72F4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>lua</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
<PropertyGroup>
<TargetName>$(LuaOutput)</TargetName>
<OutDir>$(HexChatRel)plugins\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(Glib);$(LuaInclude);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>"$(LuaLib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(Glib);$(LuaInclude);..\..\src\common;$(HexChatLib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>"$(LuaLib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="lua.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,25 @@
## Process with automake to produce Makefile.in
# To create a standalone tarball of your plugin run the plugin_dist
# target. Note: you must configure the main source tree with
# --enable-maintainer-mode
# These two must be defined.
PLUGIN=mailcheck
PLUGIN_VERSION=0.1
# This file must be in the form PLUGIN-config.h.in, it can be empty but
# must exist
EXTRA_DIST = mailcheck-config.h.in
# Remember to include this line in your Makefile.am
include @top_srcdir@/plugins/Make.plugin
libdir = $(hexchatdir)/plugins
lib_LTLIBRARIES = mailcheck.la
mailcheck_la_SOURCES = mailcheck.c
mailcheck_la_LDFLAGS = -avoid-version -module
INCLUDES = $(COMMON_CFLAGS) $(PLUGIN_INCLUDES)
DISTCLEANFILES = pg_dir/*

View File

@ -0,0 +1,94 @@
/* HexChat 2.0 plugin: Mail checker */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "hexchat-plugin.h"
static hexchat_plugin *ph; /* plugin handle */
static int
mail_items(char *file)
{
FILE *fp;
int items;
char buf[512];
fp = fopen(file, "r");
if(!fp)
return 1;
items = 0;
while(fgets(buf, sizeof buf, fp))
{
if(!strncmp(buf, "From ", 5))
items++;
}
fclose(fp);
return items;
}
static void
xchat_mail_check (void)
{
static int last_size = -1;
int size;
struct stat st;
char buf[512];
char *maildir;
maildir = getenv("MAIL");
if(!maildir)
{
snprintf (buf, sizeof(buf), "/var/spool/mail/%s", getenv("USER"));
maildir = buf;
}
if(stat(maildir, &st) < 0)
return;
size = st.st_size;
if(last_size == -1)
{
last_size = size;
return;
}
if(size > last_size)
{
hexchat_printf(ph,
"-\0033-\0039-\017\tYou have new mail (%d messages, %d bytes total).",
mail_items(maildir), size);
}
last_size = size;
}
static int timeout_cb(void *userdata)
{
xchat_mail_check();
return 1;
}
int hexchat_plugin_init(hexchat_plugin *plugin_handle,
char **plugin_name, char **plugin_desc, char **plugin_version,
char *arg)
{
ph = plugin_handle;
*plugin_name = "MailCheck";
*plugin_desc = "Checks your mailbox every 30 seconds";
*plugin_version = "0.1";
hexchat_hook_timer(ph, 30000, timeout_cb, 0);
return 1;
}

View File

@ -14,27 +14,54 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <glib.h>
/*
typedef int (*MYPROC)(HWND,HWND,char*,char*,BOOL,BOOL);
char *split(char *text, char separator)
int dllProc(char *name, char *data){
HINSTANCE hinstLib;
hinstLib = LoadLibrary("mpcinfo");
//MYPROC proc;
int res;
if (hinstLib != NULL){
//proc = ;
if ((MYPROC) GetProcAddress(hinstLib, name)!=NULL){
res=(MYPROC)(NULL,NULL,data,NULL,TRUE,TRUE);
}
else{fprintf(stderr,"can't get proc: %s\n",name);res=-2;}
}
else{fprintf(stderr,"can't access dll\n");return -1;}
FreeLibrary(hinstLib);
return res;
}
*/
/*
int dllProc(char *name, char *data)
{
int pos = -1;
size_t i;
for (i = 0; i < strlen(text); i++)
static HMODULE lib = NULL;
if (!lib)
{
if (text[i] == separator) {
pos = i;
i = strlen(text) + 1;
lib = LoadLibraryA ("mpcinfo");
if (!lib)
{
return FALSE;
}
FreeLibrary (lib);
}
if (pos == -1)
{
return text;
}
return TRUE;
}
*/
text[pos] = 0;
return &(text[pos + 1]);
char *split(char *text, char seperator){
//if (DEBUG==1) putlog("splitting");
int i;int pos=-1;
for (i=0;i<strlen(text);i++){
if (text[i]==seperator){pos=i;i=strlen(text)+1;}
}
if (pos==-1) return text;
text[pos]=0;
return &(text[pos+1]);
}
int endsWith(char *text, char *suffix){
@ -44,32 +71,21 @@ int endsWith(char *text, char *suffix){
return 0;
}
int inStr(char *s1, size_t sl1, char *s2)
{
size_t i;
for (i = 0; i < sl1 - strlen(s2); i++)
{
size_t j;
for (j = 0; j < strlen(s2); j++)
{
if (s1[i + j] != s2[j])
{
j = strlen(s2) + 2;
}
}
if (j == strlen(s2))
{
return i;
int inStr(char *s1, int sl1, char *s2){
//if (DEBUG==1) putlog("checking instr");
int i;int j;
for(i=0;i<sl1-strlen(s2);i++){
for (j=0;j<strlen(s2);j++){
if (s1[i+j]!=s2[j]) j=strlen(s2)+2;
}
if (j==strlen(s2)) return i;
}
return -1;
}
static char *subString(char *text, int first, int length, int spcKill){
//if (DEBUG==1) putlog("creating substring");
char *ret = g_new (char, length + 1);
char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1));
int i;
ret[length]=0;
for (i=0;i<length;i++){
@ -91,7 +107,7 @@ static char *substring(char *text, int first, int length){return subString(text,
char *readLine(FILE *f){
//if (DEBUG==1) putlog("reading line from file");
char *buffer = g_new (char, 1024);
char *buffer=(char*)calloc(1024,sizeof(char)); //malloc(sizeof(char)*1024);
int pos=0;
int cc=0;
while((cc!=EOF)&&(pos<1024)&&(cc!=10)){
@ -105,19 +121,14 @@ char *readLine(FILE *f){
return buffer;
}
char *toUpper(char *text)
{
char *ret = (char*) calloc(strlen(text) + 1, sizeof(char));
size_t i;
for (i = 0; i < strlen(text); i++)
{
ret[i] = toupper(text[i]);
}
ret[strlen(text)] = 0;
return ret;
char *toUpper(char *text){
//if (DEBUG==1) putlog("converting text to upper case");
char *ret=(char*) calloc(strlen(text)+1,sizeof(char));
int i;
for (i=0;i<strlen(text);i++) ret[i]=toupper(text[i]);
ret[strlen(text)]=0;
//if (DEBUG==1) putlog("uc done");
return ret;
}
static char *str3cat(char *s1, char *s2, char *s3){

View File

@ -75,25 +75,62 @@ static char MODES [][13]={"Stereo","Joint-Stereo","Dual-Channel","Mono"};
int iPow(int x, int y){return (int)(pow((double)x,(double) y));}
int str2int(char *text)
{
int ret = 0;
size_t i;
for (i = 1; i <= strlen(text); i++)
{
if ((text[strlen(text) - i] > 57) || (text[strlen(text) - i] < 48))
{
hexchat_printf(ph, "invalid char in string: %i", (int) text[strlen(text) - i]);
return 255;
int str2int(char *text){
//if (DEBUG==1) putlog("converting string to int");
int i;
int ret=0;
for (i=1;i<=strlen(text);i++){
if ((text[strlen(text)-i]>57)||(text[strlen(text)-i]<48)){
hexchat_printf(ph,"invalid char in string: %i",text[strlen(text)-i]);
return 255;
}
ret+=((int)text[strlen(text)-i]-48)*iPow(10,i-1);
}
//hexchat_printf(ph, "str2int(%s)=%i",text,ret);
//if (DEBUG==1) putlog("int converted");
return ret;
}
/*
static int getSize(char *file){
//if (DEBUG==1) putlog("reading filesize");
struct stat info;
if (stat(file,&info)!=0) return -1;
return info.st_size;
}*/
/*
int inStr(char *s1, int sl1, char *s2){
//if (DEBUG==1) putlog("checking instr");
int i;int j;
for(i=0;i<sl1-strlen(s2);i++){
for (j=0;j<strlen(s2);j++){
if (s1[i+j]!=s2[j]) j=strlen(s2)+2;
}
ret += ((int) text[strlen(text) - i] - 48)*iPow(10, i - 1);
if (j==strlen(s2)) return i;
}
return -1;
}
static char *subString(char *text, int first, int length, int spcKill){
//if (DEBUG==1) putlog("creating substring");
char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1));
ret[length]=0;int i;
for (i=0;i<length;i++){
ret[i]=text[i+first];
//if (ret[i]==0) ret[i]='0';
}
if (spcKill==1){
for (i=length-1;i>=0;i--){
if (ret[i]==32) ret[i]=0;
else i=-1;
}
}
//if (DEBUG==1) putlog("substring created");
return ret;
}
static char *substring(char *text, int first, int length){return subString(text,first,length,0);} //1
*/
static char *tagExtract(char *tag, int tagLen, char* info){
//if (DEBUG==1) putlog("extracting tag");
int pos, len, i;
@ -122,6 +159,7 @@ struct tagInfo readID3V1(char *file){
char *tag;
char *id;
char *tmp;
tag = (char*) malloc(sizeof(char)*129);
ret.artist=NULL;
f=fopen(file,"rb");
if (f==NULL){
@ -132,21 +170,18 @@ struct tagInfo readID3V1(char *file){
//int offset=getSize(file)-128;
res=fseek(f,-128,SEEK_END);
if (res!=0) {printf("seek failed\n");fclose(f);return ret;}
tag = (char*) malloc(sizeof(char)*129);
//long int pos=ftell(f);
//printf("position= %li\n",pos);
for (i=0;i<128;i++) {
c=fgetc(f);
if (c==EOF) {hexchat_printf(ph,"read ID3V1 failed\n");fclose(f);free(tag);return ret;}
if (c==EOF) {hexchat_printf(ph,"read ID3V1 failed\n");fclose(f);return ret;}
tag[i]=(char)c;
}
fclose(f);
//printf("tag readed: \n");
id=substring(tag,0,3);
//printf("header: %s\n",id);
res=strcmp(id,"TAG");
free(id);
if (res!=0){hexchat_printf(ph,"no id3 v1 found\n");free(tag);return ret;}
if (strcmp(id,"TAG")!=0){hexchat_printf(ph,"no id3 v1 found\n");return ret;}
ret.title=subString(tag,3,30,1);
ret.artist=subString(tag,33,30,1);
ret.album=subString(tag,63,30,1);
@ -166,33 +201,26 @@ struct tagInfo readID3V1(char *file){
//hexchat_printf(ph, "tmp: \"%s\" -> %i",tmp,tmp[0]);
//hexchat_printf(ph,"genre \"%s\"",ret.genre);
//if (DEBUG==1) putlog("id3v1 extracted");
free(tmp);
free(tag);
return ret;
}
char *extractID3Genre(char *tag)
{
if (tag[strlen(tag) - 1] == ')')
{
tag[strlen(tag) - 1] = 0;
tag = &tag[1];
return GENRES[str2int(tag)];
}
else
{
size_t i;
for (i = 0; i < strlen(tag); i++)
{
if (tag[i] == ')')
{
tag = &tag[i] + 1;
return tag;
}
}
}
return "[152] failed";
char *extractID3Genre(char *tag){
//if (DEBUG==1) putlog("extracting id3 genre");
if (tag[strlen(tag)-1]==')'){
tag[strlen(tag)-1]=0;
tag=&tag[1];
return GENRES[str2int(tag)];
//return tag;
}
else{
int i;
//hexchat_print(ph, "Using 2 criteria");
for (i=0;i<strlen(tag);i++){
if (tag[i]==')'){ tag=&tag[i]+1;return tag;}
//return tag;
}
}
return "[152] failed";
}
struct tagInfo readID3V2(char *file){
@ -216,7 +244,6 @@ struct tagInfo readID3V2(char *file){
for (i=0;i<10;i++){
c=fgetc(f);
if (c==EOF){
fclose(f);
//putlog("found eof while reading id3v2");
return ret;
}

View File

@ -48,20 +48,12 @@ static int mpc_tell(char *word[], char *word_eol[], void *userdata){
HWND hwnd = FindWindow("MediaPlayerClassicW",NULL);
if (hwnd==0) {hexchat_print(ph, randomLine(notRunTheme));return HEXCHAT_EAT_ALL;}
tTitle = g_new(char, 1024);
tTitle=(char*)malloc(sizeof(char)*1024);
GetWindowText(hwnd, tTitle, 1024);
zero = strstr (tTitle, " - Media Player Classic");
if (zero != NULL)
{
zero[0] = 0;
}
else
{
g_free(tTitle);
hexchat_print(ph, "pattern not found");
return HEXCHAT_EAT_ALL;
}
zero=strstr(tTitle," - Media Player Classic");
if (zero!=NULL) zero[0]=0;
else hexchat_print(ph,"pattern not found");
if ((tTitle[1]==':')&&(tTitle[2]=='\\')){
//hexchat_print(ph,"seams to be full path");
if (endsWith(tTitle,".mp3")==1){
@ -90,8 +82,7 @@ static int mpc_tell(char *word[], char *word_eol[], void *userdata){
//mp3Line=intReplace(mp3Line,"%perc",perc);
//mp3Line=replace(mp3Line,"%plTitle",title);
mp3Line=replace(mp3Line,"%file",tTitle);
g_free(tTitle);
hexchat_command(ph, mp3Line);
hexchat_command(ph, mp3Line);
return HEXCHAT_EAT_ALL;
}
}
@ -120,16 +111,14 @@ static int mpc_tell(char *word[], char *word_eol[], void *userdata){
//oggLine=intReplace(oggLine,"%perc",perc);
//oggLine=replace(oggLine,"%plTitle",title);
oggLine=replace(oggLine,"%file",tTitle);
g_free(tTitle);
hexchat_command(ph, oggLine);
hexchat_command(ph, oggLine);
return HEXCHAT_EAT_ALL;
}
}
}
line=randomLine(titleTheme);
line=replace(line,"%title", tTitle);
g_free(tTitle);
hexchat_command(ph, line);
hexchat_command(ph,line);
return HEXCHAT_EAT_ALL;
}

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
@ -20,32 +19,75 @@
<RootNamespace>mpcinfo</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
<PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcmpcinfo</TargetName>
<OutDir>$(HexChatRel)plugins\</OutDir>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>hcmpcinfo</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MPCINFO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\common;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>mpcinfo.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;MPCINFO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\common;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalIncludeDirectories>..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>mpcinfo.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
@ -56,4 +98,6 @@
<ClCompile Include="mpcInfo.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -25,18 +25,14 @@ static int getOggInt(char *buff, int beg, int bytes){
return ret;
}
static char *upperStr(char *text)
{
char *ret = (char*) malloc(sizeof(char)*(strlen(text) + 1));
size_t i;
for (i = 0; i < strlen(text); i++)
{
ret[i] = toupper(text[i]);
}
ret[strlen(text)] = 0;
static char *upperStr(char *text){
//if (DEBUG==1) putlog("converting text to uc");
//printf("upperStr(%s)\n",text);
int i;
char *ret=(char*) malloc(sizeof(char)*(strlen(text)+1));
ret[strlen(text)]=0;
for (i=0;i<strlen(text);i++) ret[i]=toupper(text[i]);
//printf("Result: %s\n",ret);
return ret;
}
@ -48,7 +44,7 @@ struct tagInfo getOggHeader(char *file){
char *sub;
char *name;
char *val;
char HEADLOC1[]="_vorbis", HEADLOC3[]="_vorbis", HEADLOC5[]="_vorbis";
char *HEADLOC1, *HEADLOC3, *HEADLOC5;
FILE *f;
struct tagInfo info;
@ -62,8 +58,11 @@ struct tagInfo getOggHeader(char *file){
for (i=0;i<4095;i++) {c=fgetc(f);header[i]=(char)c;}
fclose(f);
HEADLOC1="_vorbis";
HEADLOC1[0]=1;
HEADLOC3="_vorbis";
HEADLOC3[0]=3;
HEADLOC5="_vorbis";
HEADLOC5[0]=5;
h1pos=inStr(header,4096,HEADLOC1);
h3pos=inStr(header,4096,HEADLOC3);
@ -78,7 +77,7 @@ struct tagInfo getOggHeader(char *file){
info.bitrate=nomBr;
if (((maxBr==nomBr)&&(nomBr=minBr))||((minBr==0)&&(maxBr==0))||((minBr=-1)&&(maxBr=-1)) )info.cbr=1;else info.cbr=0;
printf("bitrates: %i|%i|%i\n",maxBr,nomBr,minBr);
printf("freq: %u\n",info.freq);
printf("freq: %i\n",info.freq);
pos=h3pos+7;
pos+=getOggInt(header,pos,4)+4;
count=getOggInt(header,pos,4);
@ -101,7 +100,6 @@ struct tagInfo getOggHeader(char *file){
if (strcmp(name,"GENRE")==0) info.genre=val;
if (strcmp(name,"COMMENT")==0) info.comment=val;
pos+=4+tagLen;
free(name);
}
if (info.artist==NULL) info.artist="";
if (info.album==NULL) info.album ="";

View File

@ -49,32 +49,24 @@ void printThemes(){
hexchat_printf(ph,"\nTitle-Theme:\n");printTheme(titleTheme);
}
void cbFix(char *line)
{
size_t i;
for (i = 0; i < strlen(line); i++)
{
size_t j;
void cbFix(char *line){
//if (DEBUG==1) putlog("cbfix");
int i, j;
for (i=0;i<strlen(line);i++){
if (line[i]=='%'){
if ((line[i+1]=='C')||(line[i+1]=='B')||(line[i+1]=='U')||(line[i+1]=='O')||(line[i+1]=='R')){
if(line[i+1]=='C') line[i]=3;
if(line[i+1]=='B') line[i]=2;
if(line[i+1]=='U') line[i]=37;
if(line[i+1]=='O') line[i]=17;
if(line[i+1]=='R') line[i]=26;
if (line[i] == '%')
{
if ((line[i + 1] == 'C') || (line[i + 1] == 'B') || (line[i + 1] == 'U') || (line[i + 1] == 'O') || (line[i + 1] == 'R'))
{
if (line[i + 1] == 'C') line[i] = 3;
if (line[i + 1] == 'B') line[i] = 2;
if (line[i + 1] == 'U') line[i] = 37;
if (line[i + 1] == 'O') line[i] = 17;
if (line[i + 1] == 'R') line[i] = 26;
for (j = i + 1; j < strlen(line) - 1; j++)
{
line[j] = line[j + 1];
}
line[strlen(line) - 1] = 0;
}
}
}
for (j=i+1;j<strlen(line)-1;j++) line[j]=line[j+1];
line[strlen(line)-1]=0;
}
}
}
//if (DEBUG==1) putlog("cbfix done");
}
struct theme themeAdd(struct theme data, char *info){
@ -91,15 +83,13 @@ struct theme themeAdd(struct theme data, char *info){
}
void loadThemes(){
char *hDir, *hFile, *line, *lineCap, *val;
char *hDir, *hFile, *line, *val;
FILE *f;
hexchat_print(ph,"loading themes\n");
hDir=(char*)calloc(1024,sizeof(char));
strcpy(hDir,hexchat_get_info(ph,"configdir"));
hFile=str3cat(hDir,"\\","mpcInfo.theme.txt");
f = fopen(hFile,"r");
free(hDir);
free(hFile);
if(f==NULL)
{
hexchat_print(ph,"no theme in homedir, checking global theme");
@ -122,12 +112,10 @@ void loadThemes(){
val=split(line,'=');
printf("line: %s\n",line);
printf("val: %s\n",val);
lineCap=toUpper(line);
if (strcmp(lineCap,"OFF_LINE")==0) notRunTheme=themeAdd(notRunTheme,val);
if (strcmp(lineCap,"TITLE_LINE")==0) titleTheme=themeAdd(titleTheme,val);
if (strcmp(lineCap,"MP3_LINE")==0) mp3Theme=themeAdd(mp3Theme,val);
if (strcmp(lineCap,"OGG_LINE")==0) mp3Theme=themeAdd(oggTheme,val);
free(lineCap);
if (strcmp(toUpper(line),"OFF_LINE")==0) notRunTheme=themeAdd(notRunTheme,val);
if (strcmp(toUpper(line),"TITLE_LINE")==0) titleTheme=themeAdd(titleTheme,val);
if (strcmp(toUpper(line),"MP3_LINE")==0) mp3Theme=themeAdd(mp3Theme,val);
if (strcmp(toUpper(line),"OGG_LINE")==0) mp3Theme=themeAdd(oggTheme,val);
}
fclose(f);
hexchat_print(ph, "theme loaded successfull\n");

View File

@ -1,20 +1,18 @@
EXTRA_DIST=generate_header lib/HexChat.pm lib/Xchat.pm lib/HexChat/Embed.pm lib/HexChat/List/Network.pm \
lib/HexChat/List/Network/Entry.pm lib/HexChat/List/Network/AutoJoin.pm lib/IRC.pm
EXTRA_DIST=alt_completion.pl generate_header lib/Xchat.pm lib/Xchat/Embed.pm lib/Xchat/List/Network.pm \
lib/Xchat/List/Network/Entry.pm lib/Xchat/List/Network/AutoJoin.pm lib/IRC.pm
libdir = $(hexchatlibdir)
lib_LTLIBRARIES = perl.la
perl_la_SOURCES = perl.c
perl_la_LDFLAGS = $(PERL_LDFLAGS) $(PLUGIN_LDFLAGS) -module
perl_la_LIBADD = $(GLIB_LIBS)
perl_la_CPPFLAGS = -I$(top_srcdir)/src/common
perl_la_CFLAGS = $(PERL_CFLAGS) $(GLIB_CFLAGS)
BUILT_SOURCES = hexchat.pm.h irc.pm.h
CLEANFILES = $(BUILT_SOURCES)
hexchat.pm.h irc.pm.h: lib/HexChat.pm lib/Xchat.pm lib/HexChat/Embed.pm \
lib/HexChat/List/Network.pm lib/HexChat/List/Network/Entry.pm \
lib/HexChat/List/Network/AutoJoin.pm lib/IRC.pm
cd $(srcdir); perl generate_header
perl_la_LDFLAGS = -avoid-version -module
perl_la_LIBADD = $(PERL_LDFLAGS)
BUILT_SOURCES = xchat.pm.h irc.pm.h
#CFLAGS = @CFLAGS@ -Wno-unused
AM_CPPFLAGS = $(PERL_CFLAGS) $(COMMON_CFLAGS) -I$(srcdir)/../../src/common
CLEANFILES = xchat.pm.h irc.pm.h
xchat.pm.h irc.pm.h: lib/Xchat.pm lib/Xchat/Embed.pm \
lib/Xchat/List/Network.pm lib/Xchat/List/Network/Entry.pm \
lib/Xchat/List/Network/AutoJoin.pm lib/IRC.pm
perl generate_header

View File

@ -0,0 +1,511 @@
use strict;
use warnings;
use Xchat ();
use File::Spec ();
use File::Basename qw(fileparse);
# if the last time you addressed someone was greater than this many minutes
# ago, ignore it
# this avoids having people you have talked to a long time ago coming up too
# early in the completion list
# Setting this to 0 will disable the check which is effectively the same as
# setting it to infinity
my $last_use_threshold = 10; # 10 minutes
# added to the front of a completion the same way as a suffix, only if
# the word is at the beginning of the line
my $prefix = '';
# ignore leading non-alphanumeric characters: -[\]^_`{|}
# Assuming you have the following nicks in a channel:
# [SomeNick] _SomeNick_ `SomeNick SomeNick SomeOtherNick
# when $ignore_leading_non_alnum is set to 0
# s<tab> will cycle through SomeNick and SomeOtherNick
# when $ignore_leading_non_alnum is set to 1
# s<tab> will cycle through [SomeNick] _SomeNick_ `SomeNick SomeNick
# SomeOtherNick
my $ignore_leading_non_alnum = 0;
# enable path completion
my $path_completion = 1;
my $base_path = '';
# ignore the completion_amount setting and always cycle through nicks with tab
my $always_cycle = 0;
Xchat::register(
"Tab Completion", "1.0500", "Alternative tab completion behavior"
);
Xchat::hook_print( "Key Press", \&complete );
Xchat::hook_print( "Close Context", \&close_context );
Xchat::hook_print( "Focus Tab", \&focus_tab );
Xchat::hook_print( "Part", \&clean_selected );
Xchat::hook_print( "Part with Reason", \&clean_selected );
Xchat::hook_command( "", \&track_selected );
sub SHIFT() { 1 }
sub CTRL() { 4 }
sub ALT() { 8 }
sub TAB() { 0xFF09 }
sub LEFT_TAB() { 0xFE20 }
my %completions;
my %last_visit;
my %selected;
my %escape_map = (
'[' => qr![\[{]!,
'{' => qr![\[{]!,
'}' => qr![\]}]!,
']' => qr![\]}]!,
'\\' => qr![\\\|]!,
'|' => qr![\\\|]!,
'.' => qr!\.!,
'^' => qr!\^!,
'$' => qr!\$!,
'*' => qr!\*!,
'+' => qr!\+!,
'?' => qr!\?!,
'(' => qr!\(!,
')' => qr!\)!,
'-' => qr!\-!,
);
my $escapes = join "", keys %escape_map;
$escapes = qr/[\Q$escapes\E]/;
# used to determine if a word is the start of a path
my $path_pattern = qr{^(?:~|/|[[:alpha:]]:\\)};
sub complete {
my ($key, $modifiers) = @{$_[0]};
# if $_[0][0] contains the value of the key pressed
# $_[0][1] contains modifiers
# the value for tab is 0xFF09
# the value for shift-tab(Left Tab) is 0xFE20
# we don't care about other keys
# the key must be a tab and left tab
return Xchat::EAT_NONE unless $key == TAB || $key == LEFT_TAB;
# if it is a tab then it must not have any modifiers
return Xchat::EAT_NONE if $key == TAB && $modifiers & (CTRL|ALT|SHIFT);
# loop backwards for shift+tab/left tab
my $delta = $modifiers & SHIFT ? -1 : 1;
my $context = Xchat::get_context;
$completions{$context} ||= {};
my $completions = $completions{$context};
$completions->{pos} ||= -1;
my $suffix = Xchat::get_prefs( "completion_suffix" );
$suffix =~ s/^\s+//;
my $input = Xchat::get_info( "inputbox" );
my $cursor_pos = Xchat::get_info( "state_cursor" );
my $left = substr( $input, 0, $cursor_pos );
my $right = substr( $input, $cursor_pos );
my $length = length $left;
# trim spaces from the end of $left to avoid grabbing the wrong word
# this is mainly needed for completion at the very beginning where a space
# is added after the completion
$left =~ s/\s+$//;
# always add one to the index because
# 1) if a space is found we want the position after it
# 2) if a space isn't found then we get back -1
my $word_start = rindex( $left, " " ) + 1;
my $word = substr( $left, $word_start );
$left = substr( $left, 0, -length $word );
if( $cursor_pos == $completions->{pos} ) {
my $previous_word = $completions->{completed};
my $new_left = $input;
substr( $new_left, $cursor_pos ) = "";
if( $previous_word and $new_left =~ s/(\Q$previous_word\E)$// ) {
$word = $1;
$word_start = length( $new_left );
$left = $new_left;
}
}
my $command_char = Xchat::get_prefs( "input_command_char" );
# ignore commands
if( ($word !~ m{^[${command_char}]})
or ( $word =~ m{^[${command_char}]} and $word_start != 0 ) ) {
if( $cursor_pos == length $input # end of input box
# not a valid nick char
&& $input =~ /(?<![\x41-\x5A\x61-\x7A\x30-\x39\x5B-\x60\x7B-\x7D-])$/
&& $cursor_pos != $completions->{pos} # not continuing a completion
&& $word !~ m{^(?:[&#/~]|[[:alpha:]]:\\)} # not a channel or path
) {
# check for path completion
unless( $path_completion and $word =~ $path_pattern ) {
$word_start = $cursor_pos;
$left = $input;
$length = length $length;
$right = "";
$word = "";
}
}
if( $word_start == 0 && $prefix && $word =~ /^\Q$prefix/ ) {
$word =~ s/^\Q$prefix//;
}
my $completed; # this is going to be the "completed" word
# for parital completions and channel names so a : isn't added
#$completions->{skip_suffix} = ($word =~ /^[&#]/) ? 1 : 0;
# continuing from a previous completion
if(
exists $completions->{matches} && @{$completions->{matches}}
&& $cursor_pos == $completions->{pos}
&& $word =~ /^\Q$completions->{matches}[$completions->{index}]/
) {
$completions->{index} += $delta;
if( $completions->{index} < 0 ) {
$completions->{index} += @{$completions->{matches}};
} else {
$completions->{index} %= @{$completions->{matches}};
}
} else {
if( $word =~ /^[&#]/ ) {
# channel name completion
$completions->{matches} = [ matching_channels( $word ) ];
$completions->{skip_suffix} = 0;
} elsif( $path_completion and $word =~ $path_pattern ) {
# file name completion
$completions->{matches} = [ matching_files( $word ) ];
$completions->{skip_suffix} = 1;
} else {
# nick completion
# fix $word so { equals [, ] equals }, \ equals |
# and escape regex metacharacters
$word =~ s/($escapes)/$escape_map{$1}/g;
$completions->{matches} = [ matching_nicks( $word ) ];
$completions->{skip_suffix} = 0;
}
$completions->{index} = 0;
}
$completed = $completions->{matches}[ $completions->{index} ];
$completions->{completed} = $completed;
my $completion_amount = Xchat::get_prefs( "completion_amount" );
# don't cycle if the number of possible completions is greater than
# completion_amount
if(
!$always_cycle && (
@{$completions->{matches}} > $completion_amount
&& @{$completions->{matches}} != 1 )
) {
# don't print if we tabbed in the beginning and the list of possible
# completions includes all nicks in the channel
my $context_type = Xchat::context_info->{type};
if( $context_type != 2 # not a channel
or @{$completions->{matches}} < Xchat::get_list("users")
) {
Xchat::print( join " ", @{$completions->{matches}}, "\n" );
}
$completed = lcs( $completions->{matches} );
$completions->{skip_suffix} = 1;
}
if( $completed ) {
if( $word_start == 0 && !$completions->{skip_suffix} ) {
# at the start of the line append completion suffix
Xchat::command( "settext $prefix$completed$suffix$right");
$completions->{pos} = length( "$prefix$completed$suffix" );
} else {
Xchat::command( "settext $left$completed$right" );
$completions->{pos} = length( "$left$completed" );
}
Xchat::command( "setcursor $completions->{pos}" );
}
=begin
# debugging stuff
local $, = " ";
my $input_length = length $input;
Xchat::print [
qq{input[$input]},
qq{input_length[$input_length]},
qq{cursor[$cursor_pos]},
qq{start[$word_start]},
qq{length[$length]},
qq{left[$left]},
qq{word[$word]}, qq{right[$right]},
qq{completed[}. ($completed||""). qq{]},
qq{pos[$completions->{pos}]},
];
use Data::Dumper;
local $Data::Dumper::Indent = 0;
Xchat::print Dumper $completions->{matches};
=cut
return Xchat::EAT_ALL;
} else {
return Xchat::EAT_NONE;
}
}
# all channels starting with $word
sub matching_channels {
my $word = shift;
# for use in compare_channels();
our $current_chan;
local $current_chan = Xchat::get_info( "channel" );
my $conn_id = Xchat::get_info( "id" );
$word =~ s/^[&#]+//;
return
map { $_->[1]->{channel} }
sort compare_channels map {
my $chan = $_->{channel};
$chan =~ s/^[#&]+//;
# comparisons will be done based only on the name
# matching name, same connection, only channels
$chan =~ /^$word/i && $_->{id} == $conn_id ?
[ $chan, $_ ] :
()
} channels();
}
sub channels {
return grep { $_->{type} == 2 } Xchat::get_list( "channels" );
}
sub compare_channels {
# package variable, value set in matching_channels()
our $current_chan;
# turn off warnings generated from channels that have not yet been visited
# since the script was loaded
no warnings "uninitialized";
# the current channel is always first, then ordered by most recently visited
return
$a->[1]{channel} eq $current_chan ? -1 :
$b->[1]{channel} eq $current_chan ? 1 :
$last_visit{ $b->[1]{context} } <=> $last_visit{ $a->[1]{context} }
|| $a->[1]{channel} cmp $b->[1]{channel};
}
sub matching_nicks {
my $word_re = shift;
# for use in compare_nicks()
our ($my_nick, $selections, $now);
local $my_nick = Xchat::get_info( "nick" );
local $selections = $selected{ Xchat::get_context() };
local $now = time;
my $pattern = $ignore_leading_non_alnum ?
qr/^[\-\[\]^_`{|}\\]*$word_re/i : qr/^$word_re/i;
return
map { $_->{nick} }
sort compare_nicks grep {
$_->{nick} =~ $pattern;
} Xchat::get_list( "users" )
}
sub max {
return unless @_;
my $max = shift;
for(@_) {
$max = $_ if $_ > $max;
}
return $max;
}
sub compare_times {
# package variables set in matching_nicks()
our $selections;
our $now;
for my $nick ( $a->{nick}, $b->{nick} ) {
# turn off the warnings that get generated from users who have yet
# to speak since the script was loaded
no warnings "uninitialized";
if( $last_use_threshold
&& (( $now - $selections->{$nick}) > ($last_use_threshold * 60)) ) {
delete $selections->{ $nick }
}
}
my $a_time = $selections->{ $a->{nick} } || 0 ;
my $b_time = $selections->{ $b->{nick} } || 0 ;
if( $a_time || $b_time ) {
return $b_time <=> $a_time;
} elsif( !$a_time && !$b_time ) {
return $b->{lasttalk} <=> $a->{lasttalk};
}
}
sub compare_nicks {
# more package variables, value set in matching_nicks()
our $my_nick;
# our own nick is always last, then ordered by the people we spoke to most
# recently and the people who were speaking most recently
return
$a->{nick} eq $my_nick ? 1 :
$b->{nick} eq $my_nick ? -1 :
compare_times()
|| Xchat::nickcmp( $a->{nick}, $b->{nick} );
# $selections->{ $b->{nick} } <=> $selections->{ $a->{nick} }
# || $b->{lasttalk} <=> $a->{lasttalk}
}
sub matching_files {
my $word = shift;
my ($file, $input_dir) = fileparse( $word );
my $dir = expand_tilde( $input_dir );
if( opendir my $dir_handle, $dir ) {
my @files;
if( $file ) {
@files = grep {
#Xchat::print( $_ );
/^\Q$file/ } readdir $dir_handle;
} else {
@files = readdir $dir_handle;
}
return map {
File::Spec->catfile( $input_dir, $_ );
} sort
grep { !/^[.]{1,2}$/ } @files;
} else {
return ();
}
}
# Remove completion related data for tabs that are closed
sub close_context {
my $context = Xchat::get_context;
delete $completions{$context};
delete $last_visit{$context};
return Xchat::EAT_NONE;
}
# track visit times
sub focus_tab {
$last_visit{Xchat::get_context()} = time();
return Xchat::EAT_NONE;
}
# keep track of the last time a message was addressed to someone
# a message is considered addressed to someone if their nick is used followed
# by the completion suffix
sub track_selected {
my $input = $_[1][0];
return Xchat::EAT_NONE unless defined $input;
my $suffix = Xchat::get_prefs( "completion_suffix" );
for( grep defined, $input =~ /^(.+)\Q$suffix/, $_[0][0] ) {
if( in_channel( $_ ) ) {
$selected{Xchat::get_context()}{$_} = time();
last;
}
}
return Xchat::EAT_NONE;
}
# if a user is in the current channel
# user_info() can also be used instead of the loop
sub in_channel {
my $target = shift;
for my $nick ( nicks() ) {
if( $nick eq $target ) {
return 1;
}
}
return 0;
}
# list of nicks in the current channel
sub nicks {
return map { $_->{nick} } Xchat::get_list( "users" );
}
# remove people from the selected list when they leave the channel
sub clean_selected {
delete $selected{ Xchat::get_context() }{$_[0][0]};
return Xchat::EAT_NONE;
}
# Longest common substring
# Used for partial completion when using non-cycling completion
sub lcs {
my @nicks = @{+shift};
return "" if @nicks == 0;
return $nicks[0] if @nicks == 1;
my $substring = shift @nicks;
while(@nicks) {
$substring = common_string( $substring, shift @nicks );
}
return $substring;
}
sub common_string {
my ($nick1, $nick2) = @_;
my $index = 0;
$index++ while(
($index < length $nick1) && ($index < length $nick2) &&
lc(substr( $nick1, $index, 1 )) eq lc(substr( $nick2, $index, 1 ))
);
return substr( $nick1, 0, $index );
}
sub expand_tilde {
my $file = shift;
$file =~ s/^~/home_dir()/e;
return $file;
}
sub home_dir {
return $base_path if $base_path;
if ( $^O eq "MSWin32" ) {
return $ENV{USERPROFILE};
} else {
return ((getpwuid($>))[7] || $ENV{HOME} || $ENV{LOGDIR});
}
}

101
plugins/perl/char_count.pl Normal file
View File

@ -0,0 +1,101 @@
use strict;
use warnings;
use Xchat qw(:all);
use Glib qw(TRUE FALSE);
use Gtk2 -init;
sub get_inputbox {
my $widget = Glib::Object->new_from_pointer( get_info( "win_ptr" ), 0 );
my $input_box;
my @containers = ($widget);
while( @containers ) {
my $container = shift @containers;
for my $child ( $container->get_children ) {
if( $child->get( "name" ) eq 'xchat-inputbox' ) {
$input_box = $child;
last;
} elsif( $child->isa( "Gtk2::Container" ) ) {
push @containers, $child;
}
}
}
return $input_box;
}
sub get_hbox {
my $widget = shift;
my $hbox;
while( $widget->parent ) {
if( $widget->parent->isa( "Gtk2::HBox" ) ) {
return $widget->parent;
}
$widget = $widget->parent;
}
}
my $input_box = get_inputbox();
if( $input_box ) {
my $hbox = get_hbox( $input_box );
if( $hbox ) {
my $label = Gtk2::Label->new();
$label->set_alignment( 0.5, ($label->get_alignment)[1] );
$hbox->pack_end( $label, 0, 0, 5 );
$label->show();
my $update_label = sub {
my $ctx_type = context_info->{"type"};
hook_timer( 0, sub {
if( $ctx_type == 2 || $ctx_type == 3 ) {
my $count = length get_info "inputbox";
$label->set_text( $count ? $count : "" );
} else {
$label->set_text( "" );
}
return REMOVE;
});
return EAT_NONE;
};
hook_print( "Key Press", $update_label );
hook_print( "Focus Tab", $update_label );
hook_print( "Focus Window", $update_label );
hook_command( "",
sub {
$label->set_text( "" );
return EAT_NONE;
}
);
my @handlers;
my $buffer = $input_box->get_buffer;
my $handler = sub { $update_label->(); return TRUE };
if( $buffer->isa( "Gtk2::TextBuffer" ) ) {
push @handlers, $buffer->signal_connect( "changed", $handler );
} elsif( $buffer->isa( "Gtk2::EntryBuffer" ) ) {
push @handlers,
$buffer->signal_connect( "deleted-text", $handler );
$buffer->signal_connect( "inserted-text", $handler );
}
register( "Character Counter", "1.0.0",
"Display the number of characters in the inputbox",
sub {
$hbox->remove( $label );
$buffer->signal_handler_disconnect( $_ ) for @handlers;
}
);
} else {
prnt "Counldn't find hbox";
}
} else {
prnt "Couldn't fint input box";
}

View File

@ -25,13 +25,12 @@ sub toc {
}
for my $files (
[ "hexchat.pm.h", # output file
"lib/HexChat.pm", # input files
"lib/Xchat.pm",
"lib/HexChat/Embed.pm",
"lib/HexChat/List/Network.pm",
"lib/HexChat/List/Network/Entry.pm",
"lib/HexChat/List/Network/AutoJoin.pm",
[ "xchat.pm.h", # output file
"lib/Xchat.pm", # input files
"lib/Xchat/Embed.pm",
"lib/Xchat/List/Network.pm",
"lib/Xchat/List/Network/Entry.pm",
"lib/Xchat/List/Network/AutoJoin.pm",
],
[ "irc.pm.h", # output file
"lib/IRC.pm" # input file

View File

@ -0,0 +1,27 @@
#!/usr/bin/env perl
use strict;
use warnings;
use File::Basename qw(dirname);
sub __DIR__ {
return dirname +(caller 0)[1];
}
# this must go before use Pod::Html to use our private copy
use lib __DIR__ . '/lib';
use Pod::Html;
chdir( __DIR__ ) or die $!;
pod2html(
# "pod2html",
"--header",
"--infile=lib/Xchat.pod",
"--outfile=xchat2-perl.html",
);
#system( qw(tidy -m -i -xml -utf8 -quiet xchat2-perl.html) );
unlink( "pod2htmd.tmp" );
unlink( "pod2htmi.tmp" );
exec( "./syntax_highlight", "xchat2-perl.html" )
or die $!;

View File

@ -1,556 +0,0 @@
$SIG{__WARN__} = sub {
my $message = shift @_;
my ($package) = caller;
# redirect Gtk/Glib errors and warnings back to STDERR
my $message_levels = qr/ERROR|CRITICAL|WARNING|MESSAGE|INFO|DEBUG/i;
if( $message =~ /^(?:Gtk|GLib|Gdk)(?:-\w+)?-$message_levels/i ) {
print STDERR $message;
} else {
if( defined &HexChat::Internal::print ) {
HexChat::print( $message );
} else {
warn $message;
}
}
};
use File::Spec ();
use File::Basename ();
use File::Glob ();
use List::Util ();
use Symbol();
use Time::HiRes ();
use Carp ();
package HexChat;
use base qw(Exporter);
use strict;
use warnings;
sub PRI_HIGHEST ();
sub PRI_HIGH ();
sub PRI_NORM ();
sub PRI_LOW ();
sub PRI_LOWEST ();
sub EAT_NONE ();
sub EAT_HEXCHAT ();
sub EAT_PLUGIN ();
sub EAT_ALL ();
sub KEEP ();
sub REMOVE ();
sub FD_READ ();
sub FD_WRITE ();
sub FD_EXCEPTION ();
sub FD_NOTSOCKET ();
sub get_context;
sub HexChat::Internal::context_info;
sub HexChat::Internal::print;
#keep compability with Xchat scripts
sub EAT_XCHAT ();
BEGIN {
*Xchat:: = *HexChat::;
}
our %EXPORT_TAGS = (
constants => [
qw(PRI_HIGHEST PRI_HIGH PRI_NORM PRI_LOW PRI_LOWEST), # priorities
qw(EAT_NONE EAT_HEXCHAT EAT_XCHAT EAT_PLUGIN EAT_ALL), # callback return values
qw(FD_READ FD_WRITE FD_EXCEPTION FD_NOTSOCKET), # fd flags
qw(KEEP REMOVE), # timers
],
hooks => [
qw(hook_server hook_command hook_print hook_timer hook_fd unhook),
],
util => [
qw(register nickcmp strip_code send_modes), # misc
qw(print prnt printf prntf command commandf emit_print), # output
qw(find_context get_context set_context), # context
qw(get_info get_prefs get_list context_info user_info), # input
qw(plugin_pref_set plugin_pref_get plugin_pref_delete plugin_pref_list), #settings
],
);
$EXPORT_TAGS{all} = [ map { @{$_} } @EXPORT_TAGS{qw(constants hooks util)}];
our @EXPORT = @{$EXPORT_TAGS{constants}};
our @EXPORT_OK = @{$EXPORT_TAGS{all}};
sub register {
my ($package, $calling_package) = HexChat::Embed::find_pkg();
my $pkg_info = HexChat::Embed::pkg_info( $package );
my $filename = $pkg_info->{filename};
my ($name, $version, $description, $callback) = @_;
if( defined $pkg_info->{gui_entry} ) {
HexChat::print( "HexChat::register called more than once in "
. $pkg_info->{filename} );
return ();
}
$description = "" unless defined $description;
if( $callback ) {
$callback = HexChat::Embed::fix_callback(
$package, $calling_package, $callback
);
}
$pkg_info->{shutdown} = $callback;
unless( $name && $name =~ /[[:print:]\w]/ ) {
$name = "Not supplied";
}
unless( $version && $version =~ /\d+(?:\.\d+)?/ ) {
$version = "NaN";
}
$pkg_info->{gui_entry} =
HexChat::Internal::register( $name, $version, $description, $filename );
# keep with old behavior
return ();
}
sub _process_hook_options {
my ($options, $keys, $store) = @_;
unless( @$keys == @$store ) {
die 'Number of keys must match the size of the store';
}
my @results;
if( ref( $options ) eq 'HASH' ) {
for my $index ( 0 .. @$keys - 1 ) {
my $key = $keys->[$index];
if( exists( $options->{ $key } ) && defined( $options->{ $key } ) ) {
${$store->[$index]} = $options->{ $key };
}
}
}
}
sub hook_server {
return undef unless @_ >= 2;
my $message = shift;
my $callback = shift;
my $options = shift;
my ($package, $calling_package) = HexChat::Embed::find_pkg();
$callback = HexChat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($priority, $data) = ( HexChat::PRI_NORM, undef );
_process_hook_options(
$options,
[qw(priority data)],
[\($priority, $data)],
);
my $pkg_info = HexChat::Embed::pkg_info( $package );
my $hook = HexChat::Internal::hook_server(
$message, $priority, $callback, $data, $package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_command {
return undef unless @_ >= 2;
my $command = shift;
my $callback = shift;
my $options = shift;
my ($package, $calling_package) = HexChat::Embed::find_pkg();
$callback = HexChat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($priority, $help_text, $data) = ( HexChat::PRI_NORM, undef, undef );
_process_hook_options(
$options,
[qw(priority help_text data)],
[\($priority, $help_text, $data)],
);
my $pkg_info = HexChat::Embed::pkg_info( $package );
my $hook = HexChat::Internal::hook_command(
$command, $priority, $callback, $help_text, $data, $package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_print {
return undef unless @_ >= 2;
my $event = shift;
my $callback = shift;
my $options = shift;
my ($package, $calling_package) = HexChat::Embed::find_pkg();
$callback = HexChat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($priority, $run_after, $filter, $data) = ( HexChat::PRI_NORM, 0, 0, undef );
_process_hook_options(
$options,
[qw(priority run_after_event filter data)],
[\($priority, $run_after, $filter, $data)],
);
if( $run_after and $filter ) {
Carp::carp( "HexChat::hook_print's run_after_event and filter options are mutually exclusive, you can only use of them at a time per hook" );
return;
}
if( $run_after ) {
my $cb = $callback;
$callback = sub {
my @args = @_;
hook_timer( 0, sub {
$cb->( @args );
if( ref $run_after eq 'CODE' ) {
$run_after->( @args );
}
return REMOVE;
});
return EAT_NONE;
};
}
if( $filter ) {
my $cb = $callback;
$callback = sub {
my @args = @{$_[0]};
my $event_data = $_[1];
my $event_name = $event;
my $last_arg = @args - 1;
my @new = $cb->( \@args, $event_data, $event_name );
# allow changing event by returning the new value
if( @new > @args ) {
$event_name = pop @new;
}
# a filter can either return the new results or it can modify
# @_ in place.
if( @new == @args ) {
emit_print( $event_name, @new[ 0 .. $last_arg ] );
return EAT_ALL;
} elsif(
join( "\0", @{$_[0]} ) ne join( "\0", @args[ 0 .. $last_arg ] )
) {
emit_print( $event_name, @args[ 0 .. $last_arg ] );
return EAT_ALL;
}
return EAT_NONE;
};
}
my $pkg_info = HexChat::Embed::pkg_info( $package );
my $hook = HexChat::Internal::hook_print(
$event, $priority, $callback, $data, $package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_timer {
return undef unless @_ >= 2;
my ($timeout, $callback, $data) = @_;
my ($package, $calling_package) = HexChat::Embed::find_pkg();
$callback = HexChat::Embed::fix_callback(
$package, $calling_package, $callback
);
if(
ref( $data ) eq 'HASH' && exists( $data->{data} )
&& defined( $data->{data} )
) {
$data = $data->{data};
}
my $pkg_info = HexChat::Embed::pkg_info( $package );
my $hook = HexChat::Internal::hook_timer( $timeout, $callback, $data, $package );
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_fd {
return undef unless @_ >= 2;
my ($fd, $callback, $options) = @_;
return undef unless defined $fd && defined $callback;
my $fileno = fileno $fd;
return undef unless defined $fileno; # no underlying fd for this handle
my ($package, $calling_package) = HexChat::Embed::find_pkg();
$callback = HexChat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($flags, $data) = (HexChat::FD_READ, undef);
_process_hook_options(
$options,
[qw(flags data)],
[\($flags, $data)],
);
my $cb = sub {
my $userdata = shift;
return $userdata->{CB}->(
$userdata->{FD}, $userdata->{FLAGS}, $userdata->{DATA},
);
};
my $pkg_info = HexChat::Embed::pkg_info( $package );
my $hook = HexChat::Internal::hook_fd(
$fileno, $cb, $flags, {
DATA => $data, FD => $fd, CB => $callback, FLAGS => $flags,
},
$package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub unhook {
my $hook = shift @_;
my $package = shift @_;
($package) = caller unless $package;
my $pkg_info = HexChat::Embed::pkg_info( $package );
if( defined( $hook )
&& $hook =~ /^\d+$/
&& grep { $_ == $hook } @{$pkg_info->{hooks}} ) {
$pkg_info->{hooks} = [grep { $_ != $hook } @{$pkg_info->{hooks}}];
return HexChat::Internal::unhook( $hook );
}
return ();
}
sub _do_for_each {
my ($cb, $channels, $servers) = @_;
# not specifying any channels or servers is not the same as specifying
# undef for both
# - not specifying either results in calling the callback inthe current ctx
# - specifying undef for for both results in calling the callback in the
# front/currently selected tab
if( @_ == 3 && !($channels || $servers) ) {
$channels = [ undef ];
$servers = [ undef ];
} elsif( !($channels || $servers) ) {
$cb->();
return 1;
}
$channels = [ $channels ] unless ref( $channels ) eq 'ARRAY';
if( $servers ) {
$servers = [ $servers ] unless ref( $servers ) eq 'ARRAY';
} else {
$servers = [ undef ];
}
my $num_done = 0;
my $old_ctx = HexChat::get_context();
for my $server ( @$servers ) {
for my $channel ( @$channels ) {
if( HexChat::set_context( $channel, $server ) ) {
$cb->();
$num_done++
}
}
}
HexChat::set_context( $old_ctx );
return $num_done;
}
sub print {
my $text = shift @_;
return "" unless defined $text;
if( ref( $text ) eq 'ARRAY' ) {
if( $, ) {
$text = join $, , @$text;
} else {
$text = join "", @$text;
}
}
return _do_for_each(
sub { HexChat::Internal::print( $text ); },
@_
);
}
sub printf {
my $format = shift;
HexChat::print( sprintf( $format, @_ ) );
}
# make HexChat::prnt() and HexChat::prntf() as aliases for HexChat::print() and
# HexChat::printf(), mainly useful when these functions are exported
sub prnt {
goto &HexChat::print;
}
sub prntf {
goto &HexChat::printf;
}
sub command {
my $command = shift;
return "" unless defined $command;
my @commands;
if( ref( $command ) eq 'ARRAY' ) {
@commands = @$command;
} else {
@commands = ($command);
}
return _do_for_each(
sub { HexChat::Internal::command( $_ ) foreach @commands },
@_
);
}
sub commandf {
my $format = shift;
HexChat::command( sprintf( $format, @_ ) );
}
sub plugin_pref_set {
my $setting = shift // return 0;
my $value = shift // return 0;
return HexChat::Internal::plugin_pref_set($setting, $value);
}
sub plugin_pref_get {
my $setting = shift // return 0;
return HexChat::Internal::plugin_pref_get($setting);
}
sub plugin_pref_delete {
my $setting = shift // return 0;
return HexChat::Internal::plugin_pref_delete($setting);
}
sub plugin_pref_list {
my %list = HexChat::Internal::plugin_pref_list();
return \%list;
}
sub set_context {
my $context;
if( @_ == 2 ) {
my ($channel, $server) = @_;
$context = HexChat::find_context( $channel, $server );
} elsif( @_ == 1 ) {
if( defined $_[0] && $_[0] =~ /^\d+$/ ) {
$context = $_[0];
} else {
$context = HexChat::find_context( $_[0] );
}
} elsif( @_ == 0 ) {
$context = HexChat::find_context();
}
return $context ? HexChat::Internal::set_context( $context ) : 0;
}
sub get_info {
my $id = shift;
my $info;
if( defined( $id ) ) {
if( grep { $id eq $_ } qw(state_cursor id) ) {
$info = HexChat::get_prefs( $id );
} else {
$info = HexChat::Internal::get_info( $id );
}
}
return $info;
}
sub user_info {
my $nick = HexChat::strip_code(shift @_ || HexChat::get_info( "nick" ));
my $user;
for (HexChat::get_list( "users" ) ) {
if ( HexChat::nickcmp( $_->{nick}, $nick ) == 0 ) {
$user = $_;
last;
}
}
return $user;
}
sub context_info {
my $ctx = shift @_ || HexChat::get_context;
my $old_ctx = HexChat::get_context;
my @fields = (
qw(away channel charset host id inputbox libdirfs modes network),
qw(nick nickserv server topic version win_ptr win_status),
qw(configdir xchatdir xchatdirfs state_cursor),
);
if( HexChat::set_context( $ctx ) ) {
my %info;
for my $field ( @fields ) {
$info{$field} = HexChat::get_info( $field );
}
my $ctx_info = HexChat::Internal::context_info;
@info{keys %$ctx_info} = values %$ctx_info;
HexChat::set_context( $old_ctx );
return \%info;
} else {
return undef;
}
}
sub get_list {
unless( grep { $_[0] eq $_ } qw(channels dcc ignore notify users networks) ) {
Carp::carp( "'$_[0]' does not appear to be a valid list name" );
}
if( $_[0] eq 'networks' ) {
return HexChat::List::Network->get();
} else {
return HexChat::Internal::get_list( $_[0] );
}
}
sub strip_code {
my $pattern = qr<
\cB| #Bold
\cC\d{0,2}(?:,\d{1,2})?| #Color
\e\[(?:\d{1,2}(?:;\d{1,2})*)?m| # ANSI color code
\cG| #Beep
\cO| #Reset
\cV| #Reverse
\c_ #Underline
>x;
if( defined wantarray ) {
my $msg = shift;
$msg =~ s/$pattern//g;
return $msg;
} else {
$_[0] =~ s/$pattern//g if defined $_[0];
}
}
1

2399
plugins/perl/lib/Pod/Html.pm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,525 @@
require HexChat;
$SIG{__WARN__} = sub {
my $message = shift @_;
my ($package) = caller;
# redirect Gtk/Glib errors and warnings back to STDERR
my $message_levels = qr/ERROR|CRITICAL|WARNING|MESSAGE|INFO|DEBUG/i;
if( $message =~ /^(?:Gtk|GLib|Gdk)(?:-\w+)?-$message_levels/i ) {
print STDERR $message;
} else {
if( defined &Xchat::Internal::print ) {
Xchat::print( $message );
} else {
warn $message;
}
}
};
use File::Spec ();
use File::Basename ();
use File::Glob ();
use List::Util ();
use Symbol();
use Time::HiRes ();
use Carp ();
package Xchat;
use base qw(Exporter);
use strict;
use warnings;
sub PRI_HIGHEST ();
sub PRI_HIGH ();
sub PRI_NORM ();
sub PRI_LOW ();
sub PRI_LOWEST ();
sub EAT_NONE ();
sub EAT_XCHAT ();
sub EAT_PLUIN ();
sub EAT_ALL ();
sub KEEP ();
sub REMOVE ();
sub FD_READ ();
sub FD_WRITE ();
sub FD_EXCEPTION ();
sub FD_NOTSOCKET ();
sub get_context;
sub Xchat::Internal::context_info;
sub Xchat::Internal::print;
our %EXPORT_TAGS = (
constants => [
qw(PRI_HIGHEST PRI_HIGH PRI_NORM PRI_LOW PRI_LOWEST), # priorities
qw(EAT_NONE EAT_XCHAT EAT_PLUGIN EAT_ALL), # callback return values
qw(FD_READ FD_WRITE FD_EXCEPTION FD_NOTSOCKET), # fd flags
qw(KEEP REMOVE), # timers
],
hooks => [
qw(hook_server hook_command hook_print hook_timer hook_fd unhook),
],
util => [
qw(register nickcmp strip_code send_modes), # misc
qw(print prnt printf prntf command commandf emit_print), # output
qw(find_context get_context set_context), # context
qw(get_info get_prefs get_list context_info user_info), # input
],
);
$EXPORT_TAGS{all} = [ map { @{$_} } @EXPORT_TAGS{qw(constants hooks util)}];
our @EXPORT = @{$EXPORT_TAGS{constants}};
our @EXPORT_OK = @{$EXPORT_TAGS{all}};
sub register {
my ($package, $calling_package) = Xchat::Embed::find_pkg();
my $pkg_info = Xchat::Embed::pkg_info( $package );
my $filename = $pkg_info->{filename};
my ($name, $version, $description, $callback) = @_;
if( defined $pkg_info->{gui_entry} ) {
Xchat::print( "Xchat::register called more than once in "
. $pkg_info->{filename} );
return ();
}
$description = "" unless defined $description;
if( $callback ) {
$callback = Xchat::Embed::fix_callback(
$package, $calling_package, $callback
);
}
$pkg_info->{shutdown} = $callback;
unless( $name && $name =~ /[[:print:]\w]/ ) {
$name = "Not supplied";
}
unless( $version && $version =~ /\d+(?:\.\d+)?/ ) {
$version = "NaN";
}
$pkg_info->{gui_entry} =
Xchat::Internal::register( $name, $version, $description, $filename );
# keep with old behavior
return ();
}
sub _process_hook_options {
my ($options, $keys, $store) = @_;
unless( @$keys == @$store ) {
die 'Number of keys must match the size of the store';
}
my @results;
if( ref( $options ) eq 'HASH' ) {
for my $index ( 0 .. @$keys - 1 ) {
my $key = $keys->[$index];
if( exists( $options->{ $key } ) && defined( $options->{ $key } ) ) {
${$store->[$index]} = $options->{ $key };
}
}
}
}
sub hook_server {
return undef unless @_ >= 2;
my $message = shift;
my $callback = shift;
my $options = shift;
my ($package, $calling_package) = Xchat::Embed::find_pkg();
$callback = Xchat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($priority, $data) = ( Xchat::PRI_NORM, undef );
_process_hook_options(
$options,
[qw(priority data)],
[\($priority, $data)],
);
my $pkg_info = Xchat::Embed::pkg_info( $package );
my $hook = Xchat::Internal::hook_server(
$message, $priority, $callback, $data, $package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_command {
return undef unless @_ >= 2;
my $command = shift;
my $callback = shift;
my $options = shift;
my ($package, $calling_package) = Xchat::Embed::find_pkg();
$callback = Xchat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($priority, $help_text, $data) = ( Xchat::PRI_NORM, undef, undef );
_process_hook_options(
$options,
[qw(priority help_text data)],
[\($priority, $help_text, $data)],
);
my $pkg_info = Xchat::Embed::pkg_info( $package );
my $hook = Xchat::Internal::hook_command(
$command, $priority, $callback, $help_text, $data, $package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_print {
return undef unless @_ >= 2;
my $event = shift;
my $callback = shift;
my $options = shift;
my ($package, $calling_package) = Xchat::Embed::find_pkg();
$callback = Xchat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($priority, $run_after, $filter, $data) = ( Xchat::PRI_NORM, 0, 0, undef );
_process_hook_options(
$options,
[qw(priority run_after_event filter data)],
[\($priority, $run_after, $filter, $data)],
);
if( $run_after and $filter ) {
Carp::carp( "Xchat::hook_print's run_after_event and filter options are mutually exclusive, you can only use of them at a time per hook" );
return;
}
if( $run_after ) {
my $cb = $callback;
$callback = sub {
my @args = @_;
hook_timer( 0, sub {
$cb->( @args );
if( ref $run_after eq 'CODE' ) {
$run_after->( @args );
}
return REMOVE;
});
return EAT_NONE;
};
}
if( $filter ) {
my $cb = $callback;
$callback = sub {
my @args = @{$_[0]};
my $event_data = $_[1];
my $event_name = $event;
my $last_arg = @args - 1;
my @new = $cb->( \@args, $event_data, $event_name );
# allow changing event by returning the new value
if( @new > @args ) {
$event_name = pop @new;
}
# a filter can either return the new results or it can modify
# @_ in place.
if( @new == @args ) {
emit_print( $event_name, @new[ 0 .. $last_arg ] );
return EAT_ALL;
} elsif(
join( "\0", @{$_[0]} ) ne join( "\0", @args[ 0 .. $last_arg ] )
) {
emit_print( $event_name, @args[ 0 .. $last_arg ] );
return EAT_ALL;
}
return EAT_NONE;
};
}
my $pkg_info = Xchat::Embed::pkg_info( $package );
my $hook = Xchat::Internal::hook_print(
$event, $priority, $callback, $data, $package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_timer {
return undef unless @_ >= 2;
my ($timeout, $callback, $data) = @_;
my ($package, $calling_package) = Xchat::Embed::find_pkg();
$callback = Xchat::Embed::fix_callback(
$package, $calling_package, $callback
);
if(
ref( $data ) eq 'HASH' && exists( $data->{data} )
&& defined( $data->{data} )
) {
$data = $data->{data};
}
my $pkg_info = Xchat::Embed::pkg_info( $package );
my $hook = Xchat::Internal::hook_timer( $timeout, $callback, $data, $package );
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub hook_fd {
return undef unless @_ >= 2;
my ($fd, $callback, $options) = @_;
return undef unless defined $fd && defined $callback;
my $fileno = fileno $fd;
return undef unless defined $fileno; # no underlying fd for this handle
my ($package, $calling_package) = Xchat::Embed::find_pkg();
$callback = Xchat::Embed::fix_callback(
$package, $calling_package, $callback
);
my ($flags, $data) = (Xchat::FD_READ, undef);
_process_hook_options(
$options,
[qw(flags data)],
[\($flags, $data)],
);
my $cb = sub {
my $userdata = shift;
return $userdata->{CB}->(
$userdata->{FD}, $userdata->{FLAGS}, $userdata->{DATA},
);
};
my $pkg_info = Xchat::Embed::pkg_info( $package );
my $hook = Xchat::Internal::hook_fd(
$fileno, $cb, $flags, {
DATA => $data, FD => $fd, CB => $callback, FLAGS => $flags,
},
$package
);
push @{$pkg_info->{hooks}}, $hook if defined $hook;
return $hook;
}
sub unhook {
my $hook = shift @_;
my $package = shift @_;
($package) = caller unless $package;
my $pkg_info = Xchat::Embed::pkg_info( $package );
if( defined( $hook )
&& $hook =~ /^\d+$/
&& grep { $_ == $hook } @{$pkg_info->{hooks}} ) {
$pkg_info->{hooks} = [grep { $_ != $hook } @{$pkg_info->{hooks}}];
return Xchat::Internal::unhook( $hook );
}
return ();
}
sub _do_for_each {
my ($cb, $channels, $servers) = @_;
# not specifying any channels or servers is not the same as specifying
# undef for both
# - not specifying either results in calling the callback inthe current ctx
# - specifying undef for for both results in calling the callback in the
# front/currently selected tab
if( @_ == 3 && !($channels || $servers) ) {
$channels = [ undef ];
$servers = [ undef ];
} elsif( !($channels || $servers) ) {
$cb->();
return 1;
}
$channels = [ $channels ] unless ref( $channels ) eq 'ARRAY';
if( $servers ) {
$servers = [ $servers ] unless ref( $servers ) eq 'ARRAY';
} else {
$servers = [ undef ];
}
my $num_done = 0;
my $old_ctx = Xchat::get_context();
for my $server ( @$servers ) {
for my $channel ( @$channels ) {
if( Xchat::set_context( $channel, $server ) ) {
$cb->();
$num_done++
}
}
}
Xchat::set_context( $old_ctx );
return $num_done;
}
sub print {
my $text = shift @_;
return "" unless defined $text;
if( ref( $text ) eq 'ARRAY' ) {
if( $, ) {
$text = join $, , @$text;
} else {
$text = join "", @$text;
}
}
return _do_for_each(
sub { Xchat::Internal::print( $text ); },
@_
);
}
sub printf {
my $format = shift;
Xchat::print( sprintf( $format, @_ ) );
}
# make Xchat::prnt() and Xchat::prntf() as aliases for Xchat::print() and
# Xchat::printf(), mainly useful when these functions are exported
sub prnt {
goto &Xchat::print;
}
sub prntf {
goto &Xchat::printf;
}
sub command {
my $command = shift;
return "" unless defined $command;
my @commands;
if( ref( $command ) eq 'ARRAY' ) {
@commands = @$command;
} else {
@commands = ($command);
}
return _do_for_each(
sub { Xchat::Internal::command( $_ ) foreach @commands },
@_
);
}
sub commandf {
my $format = shift;
Xchat::command( sprintf( $format, @_ ) );
}
sub set_context {
my $context;
if( @_ == 2 ) {
my ($channel, $server) = @_;
$context = Xchat::find_context( $channel, $server );
} elsif( @_ == 1 ) {
if( defined $_[0] && $_[0] =~ /^\d+$/ ) {
$context = $_[0];
} else {
$context = Xchat::find_context( $_[0] );
}
} elsif( @_ == 0 ) {
$context = Xchat::find_context();
}
return $context ? Xchat::Internal::set_context( $context ) : 0;
}
sub get_info {
my $id = shift;
my $info;
if( defined( $id ) ) {
if( grep { $id eq $_ } qw(state_cursor id) ) {
$info = Xchat::get_prefs( $id );
} else {
$info = Xchat::Internal::get_info( $id );
}
}
return $info;
}
sub user_info {
my $nick = Xchat::strip_code(shift @_ || Xchat::get_info( "nick" ));
my $user;
for (Xchat::get_list( "users" ) ) {
if ( Xchat::nickcmp( $_->{nick}, $nick ) == 0 ) {
$user = $_;
last;
}
}
return $user;
}
sub context_info {
my $ctx = shift @_ || Xchat::get_context;
my $old_ctx = Xchat::get_context;
my @fields = (
qw(away channel charset host id inputbox libdirfs modes network),
qw(nick nickserv server topic version win_ptr win_status),
qw(configdir xchatdir xchatdirfs state_cursor),
);
if( Xchat::set_context( $ctx ) ) {
my %info;
for my $field ( @fields ) {
$info{$field} = Xchat::get_info( $field );
}
my $ctx_info = Xchat::Internal::context_info;
@info{keys %$ctx_info} = values %$ctx_info;
Xchat::set_context( $old_ctx );
return %info if wantarray;
return \%info;
} else {
return undef;
}
}
sub get_list {
unless( grep { $_[0] eq $_ } qw(channels dcc ignore notify users networks) ) {
Carp::carp( "'$_[0]' does not appear to be a valid list name" );
}
if( $_[0] eq 'networks' ) {
return Xchat::List::Network->get();
} else {
return Xchat::Internal::get_list( $_[0] );
}
}
sub strip_code {
my $pattern = qr<
\cB| #Bold
\cC\d{0,2}(?:,\d{1,2})?| #Color
\e\[(?:\d{1,2}(?:;\d{1,2})*)?m| # ANSI color code
\cG| #Beep
\cO| #Reset
\cV| #Reverse
\c_ #Underline
>x;
if( defined wantarray ) {
my $msg = shift;
$msg =~ s/$pattern//g;
return $msg;
} else {
$_[0] =~ s/$pattern//g if defined $_[0];
}
}
1

1362
plugins/perl/lib/Xchat.pod Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
package HexChat::Embed;
package Xchat::Embed;
use strict;
use warnings;
use Data::Dumper;
# list of loaded scripts keyed by their package names
# The package names are generated from the filename of the script using
# the file2pkg() function.
@ -43,11 +42,11 @@ sub load {
if( exists $scripts{$package} ) {
my $pkg_info = pkg_info( $package );
my $filename = File::Basename::basename( $pkg_info->{filename} );
HexChat::printf(
Xchat::printf(
qq{'%s' already loaded from '%s'.\n},
$filename, $pkg_info->{filename}
);
HexChat::print(
Xchat::print(
'If this is a different script then it rename and try '.
'loading it again.'
);
@ -61,7 +60,7 @@ sub load {
$source =~ s/^__END__.*//ms;
# this must come before the eval or the filename will not be found in
# HexChat::register
# Xchat::register
$scripts{$package}{filename} = $file;
$scripts{$package}{loaded_at} = Time::HiRes::time();
@ -94,7 +93,7 @@ sub load {
$error_message .= " $conflict_package already defined in " .
pkg_info($owner_package{ $conflict_package })->{filename}."\n";
}
HexChat::print( $error_message );
Xchat::print( $error_message );
return 2;
}
@ -115,7 +114,7 @@ sub load {
unless( exists $scripts{$package}{gui_entry} ) {
$scripts{$package}{gui_entry} =
HexChat::Internal::register(
Xchat::Internal::register(
"", "unknown", "", $file
);
}
@ -123,13 +122,13 @@ sub load {
if( $@ ) {
# something went wrong
$@ =~ s/\(eval \d+\)/$file/g;
HexChat::print( "Error loading '$file':\n$@\n" );
Xchat::print( "Error loading '$file':\n$@\n" );
# make sure the script list doesn't contain false information
unload( $scripts{$package}{filename} );
return 1;
}
} else {
HexChat::print( "Error opening '$file': $!\n" );
Xchat::print( "Error opening '$file': $!\n" );
return 2;
}
@ -163,7 +162,7 @@ sub unload {
if( exists $pkg_info->{hooks} ) {
for my $hook ( @{$pkg_info->{hooks}} ) {
HexChat::unhook( $hook, $package );
Xchat::unhook( $hook, $package );
}
}
@ -177,10 +176,10 @@ sub unload {
}
Symbol::delete_package( $package );
delete $scripts{$package};
return HexChat::EAT_ALL;
return Xchat::EAT_ALL;
} else {
HexChat::print( qq{"$file" is not loaded.\n} );
return HexChat::EAT_NONE;
Xchat::print( qq{"$file" is not loaded.\n} );
return Xchat::EAT_NONE;
}
}
@ -189,7 +188,7 @@ sub unload_all {
unload( $scripts{$package}->{filename} );
}
return HexChat::EAT_ALL;
return Xchat::EAT_ALL;
}
sub reload {
@ -204,11 +203,11 @@ sub reload {
}
load( $fullpath );
return HexChat::EAT_ALL;
return Xchat::EAT_ALL;
}
sub reload_all {
my @dirs = HexChat::get_info( "configdir" );
my @dirs = Xchat::get_info( "configdir" );
push @dirs, File::Spec->catdir( $dirs[0], "plugins" );
for my $dir ( @dirs ) {
my $auto_load_glob = File::Spec->catfile( $dir, "*.pl" );
@ -228,28 +227,6 @@ sub reload_all {
}
}
sub evaluate {
my ($code) = @_;
my @results = eval $code;
HexChat::print $@ if $@; #print warnings
local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Terse = 1;
if (@results > 1) {
HexChat::print Dumper \@results;
}
elsif (ref $results[0] || !$results[0]) {
HexChat::print Dumper $results[0];
}
else {
HexChat::print $results[0];
}
return HexChat::EAT_HEXCHAT;
};
sub expand_homedir {
my $file = shift @_;
@ -267,7 +244,7 @@ sub file2pkg {
my $string = File::Basename::basename( shift @_ );
$string =~ s/\.pl$//i;
$string =~ s|([^A-Za-z0-9/])|'_'.unpack("H*",$1)|eg;
return "HexChat::Script::" . $string;
return "Xchat::Script::" . $string;
}
sub pkg_info {
@ -279,7 +256,7 @@ sub find_external_pkg {
my $level = 1;
while( my @frame = caller( $level ) ) {
return @frame if $frame[0] !~ /(?:^IRC$|^HexChat)/;
return @frame if $frame[0] !~ /(?:^IRC$|^Xchat)/;
$level++;
}
return;
@ -289,7 +266,7 @@ sub find_pkg {
my $level = 1;
while( my ($package, $file, $line) = caller( $level ) ) {
return $package if $package =~ /^HexChat::Script::/;
return $package if $package =~ /^Xchat::Script::/;
$level++;
}

View File

@ -1,4 +1,4 @@
package HexChat::List::Network;
package Xchat::List::Network;
use strict;
use warnings;
use Storable qw(dclone);
@ -6,7 +6,7 @@ my $last_modified;
my @servers;
sub get {
my $server_file = HexChat::get_info( "configdir" ) . "/servlist.conf";
my $server_file = Xchat::get_info( "configdir" ) . "/servlist.conf";
# recreate the list only if the server list file has changed
if( -f $server_file &&
@ -19,7 +19,7 @@ sub get {
while( my $record = <$fh> ) {
chomp $record;
next if $record =~ /^v=/; # skip the version line
push @servers, HexChat::List::Network::Entry::parse( $record );
push @servers, Xchat::List::Network::Entry::parse( $record );
}
} else {
warn "Unable to open '$server_file': $!";

View File

@ -1,4 +1,4 @@
package HexChat::List::Network::AutoJoin;
package Xchat::List::Network::AutoJoin;
use strict;
use warnings;

View File

@ -1,4 +1,4 @@
package HexChat::List::Network::Entry;
package Xchat::List::Network::Entry;
use strict;
use warnings;
@ -26,7 +26,7 @@ sub parse {
# the order of the channels need to be maintained
# list of { channel => .., key => ... }
autojoins => HexChat::List::Network::AutoJoin->new( '' ),
autojoins => Xchat::List::Network::AutoJoin->new( '' ),
connect_commands => [],
flags => {},
selected => undef,
@ -39,7 +39,7 @@ sub parse {
my @fields = split /\n/, $data;
chomp @fields;
$entry->{ autojoins } = HexChat::List::Network::AutoJoin->new();
$entry->{ autojoins } = Xchat::List::Network::AutoJoin->new();
for my $field ( @fields ) {
SWITCH: for ( $field ) {

View File

@ -16,8 +16,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -29,15 +27,16 @@
#endif
#ifdef WIN32
#include <windows.h>
#include <stdbool.h>
#else
#include <dirent.h>
#endif
#include <glib.h>
#undef PACKAGE
#ifdef WIN32
#include "../../config-win32.h" /* for #define OLD_PERL */
#else
#include "../../config.h"
#endif
#include "hexchat-plugin.h"
static hexchat_plugin *ph; /* plugin handle */
@ -79,26 +78,37 @@ thread_mbox (char *str)
static void
perl_auto_load_from_path (const char *path)
{
char *search_path = g_build_filename (path, "*.pl", NULL);
WIN32_FIND_DATAA find_data;
HANDLE find_handle = FindFirstFileA (search_path, &find_data);
WIN32_FIND_DATA find_data;
HANDLE find_handle;
char *search_path;
int path_len = strlen (path);
/* +6 for \*.pl and \0 */
search_path = malloc(path_len + 6);
sprintf (search_path, "%s\\*.pl", path);
find_handle = FindFirstFile (search_path, &find_data);
if (find_handle != INVALID_HANDLE_VALUE)
{
do
{
if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 && (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0)
if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
||find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
{
char *full_path = g_build_filename (path, find_data.cFileName, NULL);
char *full_path =
malloc (path_len + strlen (find_data.cFileName) + 2);
sprintf (full_path, "%s\\%s", path, find_data.cFileName);
perl_load_file (full_path);
g_free (full_path);
free (full_path);
}
}
while (FindNextFileA (find_handle, &find_data) != 0);
while (FindNextFile (find_handle, &find_data) != 0);
FindClose (find_handle);
}
g_free (search_path);
free (search_path);
}
#else
static void
@ -108,16 +118,14 @@ perl_auto_load_from_path (const char *path)
struct dirent *ent;
dir = opendir (path);
if (dir)
{
while ((ent = readdir (dir)))
{
if (dir) {
while ((ent = readdir (dir))) {
int len = strlen (ent->d_name);
if (len > 3 && strcasecmp (".pl", ent->d_name + len - 3) == 0)
{
char *file = g_build_filename (path, ent->d_name, NULL);
if (len > 3 && strcasecmp (".pl", ent->d_name + len - 3) == 0) {
char *file = malloc (len + strlen (path) + 2);
sprintf (file, "%s/%s", path, ent->d_name);
perl_load_file (file);
g_free (file);
free (file);
}
}
closedir (dir);
@ -140,10 +148,31 @@ perl_auto_load (void *unused)
/* don't pollute the filesystem with script files, this only causes misuse of the folders
* only use ~/.config/hexchat/addons/ and %APPDATA%\HexChat\addons */
sub_dir = g_build_filename (xdir, "addons", NULL);
perl_auto_load_from_path (sub_dir);
g_free (sub_dir);
#if 0
/* autoload from ~/.config/hexchat/ or %APPDATA%\HexChat\ on win32 */
perl_auto_load_from_path (xdir);
#endif
sub_dir = malloc (strlen (xdir) + 8);
strcpy (sub_dir, xdir);
strcat (sub_dir, "/addons");
perl_auto_load_from_path (sub_dir);
free (sub_dir);
#if 0
#ifdef WIN32
/* autoload from C:\Program Files\HexChat\plugins\ */
sub_dir = malloc (1025 + 9);
copied = GetModuleFileName( 0, sub_dir, 1024 );
sub_dir[copied] = '\0';
slash = strrchr( sub_dir, '\\' );
if( slash != NULL ) {
*slash = '\0';
}
perl_auto_load_from_path ( strncat (sub_dir, "\\plugins", 9));
free (sub_dir);
#endif
#endif
return 0;
}
@ -208,6 +237,8 @@ get_filename (char *word[], char *word_eol[])
int len;
char *file;
len = strlen (word[2]);
/* if called as /load "filename.pl" the only difference between word and
* word_eol will be the two quotes
*/
@ -260,19 +291,7 @@ list_item_to_sv ( hexchat_list *list, const char *const *fields )
field_value = newSVuv (hexchat_list_int (ph, list, field_name));
break;
case 't':
/* From perldoc for Perl's own timelocal() and timegm():
* <quote>
* On perl versions older than 5.12.0, the range of dates that can be actually be handled depends on the size of time_t (usually a signed integer) on the given platform.
* As of version 5.12.0, perl has stopped using the underlying time library of the operating system it's running on and has its own implementation of those routines with a
* safe range of at least +/ 2**52 (about 142 million years).
* </quote>
*
* This is further confirmed from looking at the source for Time::Local - it's a Perl module and the implementations of timelocal() and timegm() use simple addition and
* subtraction of numbers. Perl automatically promotes numbers from int32_t (IV) to uint32_t (UV) to 64-bit IEEE754 double (NV) as required.
*
* This means that using a double (NV) for our own time_t suffers from the same assumptions that Perl's own functions do.
*/
field_value = newSVnv ((const NV) hexchat_list_time (ph, list, field_name));
field_value = newSVnv (hexchat_list_time (ph, list, field_name));
break;
default:
field_value = &PL_sv_undef;
@ -304,11 +323,11 @@ array2av (char *array[])
return av;
}
/* sets $HexChat::Embed::current_package */
/* sets $Xchat::Embed::current_package */
static void
set_current_package (SV *package)
{
SV *current_package = get_sv ("HexChat::Embed::current_package", 1);
SV *current_package = get_sv ("Xchat::Embed::current_package", 1);
SvSetSV_nosteal (current_package, package);
}
@ -348,7 +367,7 @@ fd_cb (int fd, int flags, void *userdata)
XPUSHs (sv_2mortal (newSViv (PTR2IV (data->hook))));
PUTBACK;
call_pv ("HexChat::unhook", G_EVAL);
call_pv ("Xchat::unhook", G_EVAL);
SPAGAIN;
SvREFCNT_dec (data->callback);
@ -356,7 +375,7 @@ fd_cb (int fd, int flags, void *userdata)
if (data->userdata) {
SvREFCNT_dec (data->userdata);
}
g_free (data);
free (data);
}
}
@ -389,7 +408,7 @@ timer_cb (void *userdata)
}
set_current_package (data->package);
count = call_sv (data->callback, G_EVAL | G_KEEPERR);
count = call_sv (data->callback, G_EVAL);
set_current_package (&PL_sv_undef);
SPAGAIN;
@ -410,7 +429,7 @@ timer_cb (void *userdata)
XPUSHs (sv_mortalcopy (data->package));
PUTBACK;
call_pv ("HexChat::unhook", G_EVAL);
call_pv ("Xchat::unhook", G_EVAL);
SPAGAIN;
}
}
@ -439,7 +458,7 @@ server_cb (char *word[], char *word_eol[], void *userdata)
return HEXCHAT_EAT_NONE;
/* hexchat_printf (ph, */
/* "Received %d words in server callback", av_len (wd)); */
/* "Recieved %d words in server callback", av_len (wd)); */
PUSHMARK (SP);
XPUSHs (newRV_noinc ((SV *) array2av (word)));
XPUSHs (newRV_noinc ((SV *) array2av (word_eol)));
@ -448,7 +467,7 @@ server_cb (char *word[], char *word_eol[], void *userdata)
data->depth++;
set_current_package (data->package);
count = call_sv (data->callback, G_EVAL | G_KEEPERR);
count = call_sv (data->callback, G_EVAL);
set_current_package (&PL_sv_undef);
data->depth--;
SPAGAIN;
@ -487,7 +506,7 @@ command_cb (char *word[], char *word_eol[], void *userdata)
if (data->depth)
return HEXCHAT_EAT_NONE;
/* hexchat_printf (ph, "Received %d words in command callback", */
/* hexchat_printf (ph, "Recieved %d words in command callback", */
/* av_len (wd)); */
PUSHMARK (SP);
XPUSHs (newRV_noinc ((SV *) array2av (word)));
@ -497,7 +516,7 @@ command_cb (char *word[], char *word_eol[], void *userdata)
data->depth++;
set_current_package (data->package);
count = call_sv (data->callback, G_EVAL | G_KEEPERR);
count = call_sv (data->callback, G_EVAL);
set_current_package (&PL_sv_undef);
data->depth--;
SPAGAIN;
@ -565,7 +584,7 @@ print_cb (char *word[], void *userdata)
}
}
/*hexchat_printf (ph, "Received %d words in print callback", av_len (wd)+1); */
/*hexchat_printf (ph, "Recieved %d words in print callback", av_len (wd)+1); */
PUSHMARK (SP);
XPUSHs (newRV_noinc ((SV *) wd));
XPUSHs (data->userdata);
@ -573,7 +592,7 @@ print_cb (char *word[], void *userdata)
data->depth++;
set_current_package (data->package);
count = call_sv (data->callback, G_EVAL | G_KEEPERR);
count = call_sv (data->callback, G_EVAL);
set_current_package (&PL_sv_undef);
data->depth--;
SPAGAIN;
@ -600,19 +619,19 @@ print_cb (char *word[], void *userdata)
/* custom IRC perl functions for scripting */
/* HexChat::Internal::register (scriptname, version, desc, shutdowncallback, filename)
/* Xchat::Internal::register (scriptname, version, desc, shutdowncallback, filename)
*
*/
static
XS (XS_HexChat_register)
XS (XS_Xchat_register)
{
char *name, *version, *desc, *filename;
void *gui_entry;
dXSARGS;
if (items != 4) {
hexchat_printf (ph,
"Usage: HexChat::Internal::register(scriptname, version, desc, filename)");
"Usage: Xchat::Internal::register(scriptname, version, desc, filename)");
} else {
name = SvPV_nolen (ST (0));
version = SvPV_nolen (ST (1));
@ -628,16 +647,16 @@ XS (XS_HexChat_register)
}
/* HexChat::print(output) */
/* Xchat::print(output) */
static
XS (XS_HexChat_print)
XS (XS_Xchat_print)
{
char *text = NULL;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::Internal::print(text)");
hexchat_print (ph, "Usage: Xchat::Internal::print(text)");
} else {
text = SvPV_nolen (ST (0));
hexchat_print (ph, text);
@ -646,7 +665,7 @@ XS (XS_HexChat_print)
}
static
XS (XS_HexChat_emit_print)
XS (XS_Xchat_emit_print)
{
char *event_name;
int RETVAL;
@ -654,7 +673,7 @@ XS (XS_HexChat_emit_print)
dXSARGS;
if (items < 1) {
hexchat_print (ph, "Usage: HexChat::emit_print(event_name, ...)");
hexchat_print (ph, "Usage: Xchat::emit_print(event_name, ...)");
} else {
event_name = (char *) SvPV_nolen (ST (0));
RETVAL = 0;
@ -700,7 +719,7 @@ XS (XS_HexChat_emit_print)
}
static
XS (XS_HexChat_send_modes)
XS (XS_Xchat_send_modes)
{
AV *p_targets = NULL;
int modes_per_line = 0;
@ -714,13 +733,13 @@ XS (XS_HexChat_send_modes)
dXSARGS;
if (items < 3 || items > 4) {
hexchat_print (ph,
"Usage: HexChat::send_modes( targets, sign, mode, modes_per_line)"
"Usage: Xchat::send_modes( targets, sign, mode, modes_per_line)"
);
} else {
if (SvROK (ST (0))) {
p_targets = (AV*) SvRV (ST (0));
target_count = av_len (p_targets) + 1;
targets = g_new (const char *, target_count);
targets = malloc (target_count * sizeof (char *));
for (i = 0; i < target_count; i++ ) {
elem = av_fetch (p_targets, i, 0);
@ -731,13 +750,12 @@ XS (XS_HexChat_send_modes)
}
}
} else{
targets = g_new (const char *, 1);
targets = malloc (sizeof (char *));
targets[0] = SvPV_nolen (ST (0));
target_count = 1;
}
if (target_count == 0) {
g_free ((char**) targets);
XSRETURN_EMPTY;
}
@ -749,16 +767,16 @@ XS (XS_HexChat_send_modes)
}
hexchat_send_modes (ph, targets, target_count, modes_per_line, sign, mode);
g_free ((char**) targets);
free (targets);
}
}
static
XS (XS_HexChat_get_info)
XS (XS_Xchat_get_info)
{
SV *temp = NULL;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::get_info(id)");
hexchat_print (ph, "Usage: Xchat::get_info(id)");
} else {
SV *id = ST (0);
const char *RETVAL;
@ -792,13 +810,13 @@ XS (XS_HexChat_get_info)
}
static
XS (XS_HexChat_context_info)
XS (XS_Xchat_context_info)
{
const char *const *fields;
dXSARGS;
if (items > 0 ) {
hexchat_print (ph, "Usage: HexChat::Internal::context_info()");
hexchat_print (ph, "Usage: Xchat::Internal::context_info()");
}
fields = hexchat_list_fields (ph, "channels" );
XPUSHs (list_item_to_sv (NULL, fields));
@ -806,14 +824,14 @@ XS (XS_HexChat_context_info)
}
static
XS (XS_HexChat_get_prefs)
XS (XS_Xchat_get_prefs)
{
const char *str;
int integer;
SV *temp = NULL;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::get_prefs(name)");
hexchat_print (ph, "Usage: Xchat::get_prefs(name)");
} else {
@ -842,9 +860,9 @@ XS (XS_HexChat_get_prefs)
}
}
/* HexChat::Internal::hook_server(name, priority, callback, userdata) */
/* Xchat::Internal::hook_server(name, priority, callback, userdata) */
static
XS (XS_HexChat_hook_server)
XS (XS_Xchat_hook_server)
{
char *name;
@ -859,7 +877,7 @@ XS (XS_HexChat_hook_server)
if (items != 5) {
hexchat_print (ph,
"Usage: HexChat::Internal::hook_server(name, priority, callback, userdata, package)");
"Usage: Xchat::Internal::hook_server(name, priority, callback, userdata, package)");
} else {
name = SvPV_nolen (ST (0));
pri = (int) SvIV (ST (1));
@ -867,7 +885,11 @@ XS (XS_HexChat_hook_server)
userdata = ST (3);
package = ST (4);
data = NULL;
data = g_new (HookData, 1);
data = malloc (sizeof (HookData));
if (data == NULL) {
XSRETURN_UNDEF;
}
data->callback = newSVsv (callback);
data->userdata = newSVsv (userdata);
data->depth = 0;
@ -879,9 +901,9 @@ XS (XS_HexChat_hook_server)
}
}
/* HexChat::Internal::hook_command(name, priority, callback, help_text, userdata) */
/* Xchat::Internal::hook_command(name, priority, callback, help_text, userdata) */
static
XS (XS_HexChat_hook_command)
XS (XS_Xchat_hook_command)
{
char *name;
int pri;
@ -896,7 +918,7 @@ XS (XS_HexChat_hook_command)
if (items != 6) {
hexchat_print (ph,
"Usage: HexChat::Internal::hook_command(name, priority, callback, help_text, userdata, package)");
"Usage: Xchat::Internal::hook_command(name, priority, callback, help_text, userdata, package)");
} else {
name = SvPV_nolen (ST (0));
pri = (int) SvIV (ST (1));
@ -912,7 +934,11 @@ XS (XS_HexChat_hook_command)
package = ST (5);
data = NULL;
data = g_new (HookData, 1);
data = malloc (sizeof (HookData));
if (data == NULL) {
XSRETURN_UNDEF;
}
data->callback = newSVsv (callback);
data->userdata = newSVsv (userdata);
data->depth = 0;
@ -924,9 +950,9 @@ XS (XS_HexChat_hook_command)
}
/* HexChat::Internal::hook_print(name, priority, callback, [userdata]) */
/* Xchat::Internal::hook_print(name, priority, callback, [userdata]) */
static
XS (XS_HexChat_hook_print)
XS (XS_Xchat_hook_print)
{
char *name;
@ -939,7 +965,7 @@ XS (XS_HexChat_hook_print)
dXSARGS;
if (items != 5) {
hexchat_print (ph,
"Usage: HexChat::Internal::hook_print(name, priority, callback, userdata, package)");
"Usage: Xchat::Internal::hook_print(name, priority, callback, userdata, package)");
} else {
name = SvPV_nolen (ST (0));
pri = (int) SvIV (ST (1));
@ -948,7 +974,11 @@ XS (XS_HexChat_hook_print)
userdata = ST (3);
package = ST (4);
data = g_new (HookData, 1);
data = malloc (sizeof (HookData));
if (data == NULL) {
XSRETURN_UNDEF;
}
data->callback = newSVsv (callback);
data->userdata = newSVsv (userdata);
data->depth = 0;
@ -959,9 +989,9 @@ XS (XS_HexChat_hook_print)
}
}
/* HexChat::Internal::hook_timer(timeout, callback, userdata) */
/* Xchat::Internal::hook_timer(timeout, callback, userdata) */
static
XS (XS_HexChat_hook_timer)
XS (XS_Xchat_hook_timer)
{
int timeout;
SV *callback;
@ -974,7 +1004,7 @@ XS (XS_HexChat_hook_timer)
if (items != 4) {
hexchat_print (ph,
"Usage: HexChat::Internal::hook_timer(timeout, callback, userdata, package)");
"Usage: Xchat::Internal::hook_timer(timeout, callback, userdata, package)");
} else {
timeout = (int) SvIV (ST (0));
callback = ST (1);
@ -982,7 +1012,11 @@ XS (XS_HexChat_hook_timer)
userdata = ST (2);
package = ST (3);
data = g_new (HookData, 1);
data = malloc (sizeof (HookData));
if (data == NULL) {
XSRETURN_UNDEF;
}
data->callback = newSVsv (callback);
data->userdata = newSVsv (userdata);
data->ctx = hexchat_get_context (ph);
@ -994,9 +1028,9 @@ XS (XS_HexChat_hook_timer)
}
}
/* HexChat::Internal::hook_fd(fd, callback, flags, userdata) */
/* Xchat::Internal::hook_fd(fd, callback, flags, userdata) */
static
XS (XS_HexChat_hook_fd)
XS (XS_Xchat_hook_fd)
{
int fd;
SV *callback;
@ -1010,7 +1044,7 @@ XS (XS_HexChat_hook_fd)
if (items != 5) {
hexchat_print (ph,
"Usage: HexChat::Internal::hook_fd(fd, callback, flags, userdata)");
"Usage: Xchat::Internal::hook_fd(fd, callback, flags, userdata)");
} else {
fd = (int) SvIV (ST (0));
callback = ST (1);
@ -1032,7 +1066,11 @@ XS (XS_HexChat_hook_fd)
}
#endif
data = g_new (HookData, 1);
data = malloc (sizeof (HookData));
if (data == NULL) {
XSRETURN_UNDEF;
}
data->callback = newSVsv (callback);
data->userdata = newSVsv (userdata);
data->depth = 0;
@ -1045,14 +1083,14 @@ XS (XS_HexChat_hook_fd)
}
static
XS (XS_HexChat_unhook)
XS (XS_Xchat_unhook)
{
hexchat_hook *hook;
HookData *userdata;
int retCount = 0;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::unhook(hook)");
hexchat_print (ph, "Usage: Xchat::unhook(hook)");
} else {
hook = INT2PTR (hexchat_hook *, SvUV (ST (0)));
userdata = (HookData *) hexchat_unhook (ph, hook);
@ -1072,22 +1110,22 @@ XS (XS_HexChat_unhook)
SvREFCNT_dec (userdata->package);
}
g_free (userdata);
free (userdata);
}
XSRETURN (retCount);
}
XSRETURN_EMPTY;
}
/* HexChat::Internal::command(command) */
/* Xchat::Internal::command(command) */
static
XS (XS_HexChat_command)
XS (XS_Xchat_command)
{
char *cmd = NULL;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::Internal::command(command)");
hexchat_print (ph, "Usage: Xchat::Internal::command(command)");
} else {
cmd = SvPV_nolen (ST (0));
hexchat_command (ph, cmd);
@ -1097,7 +1135,7 @@ XS (XS_HexChat_command)
}
static
XS (XS_HexChat_find_context)
XS (XS_Xchat_find_context)
{
char *server = NULL;
char *chan = NULL;
@ -1105,7 +1143,7 @@ XS (XS_HexChat_find_context)
dXSARGS;
if (items > 2)
hexchat_print (ph, "Usage: HexChat::find_context ([channel, [server]])");
hexchat_print (ph, "Usage: Xchat::find_context ([channel, [server]])");
{
switch (items) {
@ -1153,23 +1191,23 @@ XS (XS_HexChat_find_context)
}
static
XS (XS_HexChat_get_context)
XS (XS_Xchat_get_context)
{
dXSARGS;
if (items != 0) {
hexchat_print (ph, "Usage: HexChat::get_context()");
hexchat_print (ph, "Usage: Xchat::get_context()");
} else {
XSRETURN_IV (PTR2IV (hexchat_get_context (ph)));
}
}
static
XS (XS_HexChat_set_context)
XS (XS_Xchat_set_context)
{
hexchat_context *ctx;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::set_context(ctx)");
hexchat_print (ph, "Usage: Xchat::set_context(ctx)");
} else {
ctx = INT2PTR (hexchat_context *, SvUV (ST (0)));
XSRETURN_IV ((IV) hexchat_set_context (ph, ctx));
@ -1177,11 +1215,11 @@ XS (XS_HexChat_set_context)
}
static
XS (XS_HexChat_nickcmp)
XS (XS_Xchat_nickcmp)
{
dXSARGS;
if (items != 2) {
hexchat_print (ph, "Usage: HexChat::nickcmp(s1, s2)");
hexchat_print (ph, "Usage: Xchat::nickcmp(s1, s2)");
} else {
XSRETURN_IV ((IV) hexchat_nickcmp (ph, SvPV_nolen (ST (0)),
SvPV_nolen (ST (1))));
@ -1189,7 +1227,7 @@ XS (XS_HexChat_nickcmp)
}
static
XS (XS_HexChat_get_list)
XS (XS_Xchat_get_list)
{
SV *name;
hexchat_list *list;
@ -1198,7 +1236,7 @@ XS (XS_HexChat_get_list)
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::get_list(name)");
hexchat_print (ph, "Usage: Xchat::get_list(name)");
} else {
SP -= items; /*remove the argument list from the stack */
@ -1230,12 +1268,12 @@ XS (XS_HexChat_get_list)
}
static
XS (XS_HexChat_Embed_plugingui_remove)
XS (XS_Xchat_Embed_plugingui_remove)
{
void *gui_entry;
dXSARGS;
if (items != 1) {
hexchat_print (ph, "Usage: HexChat::Embed::plugingui_remove(handle)");
hexchat_print (ph, "Usage: Xchat::Embed::plugingui_remove(handle)");
} else {
gui_entry = INT2PTR (void *, SvUV (ST (0)));
hexchat_plugingui_remove (ph, gui_entry);
@ -1243,72 +1281,6 @@ XS (XS_HexChat_Embed_plugingui_remove)
XSRETURN_EMPTY;
}
static
XS (XS_HexChat_plugin_pref_set)
{
dMARK;
dAX;
XSRETURN_IV ((IV) hexchat_pluginpref_set_str (ph, SvPV_nolen (ST (0)),
SvPV_nolen (ST (1))));
}
static
XS (XS_HexChat_plugin_pref_get)
{
int result;
char value[512];
dMARK;
dAX;
result = hexchat_pluginpref_get_str (ph, SvPV_nolen (ST (0)), value);
if (result)
XSRETURN_PV (value);
XSRETURN_UNDEF;
}
static
XS (XS_HexChat_plugin_pref_delete)
{
dMARK;
dAX;
XSRETURN_IV ((IV) hexchat_pluginpref_delete (ph, SvPV_nolen (ST (0))));
}
static
XS (XS_HexChat_plugin_pref_list)
{
char list[4096];
char value[512];
char *token;
dSP;
dMARK;
dAX;
if (!hexchat_pluginpref_list (ph, list))
XSRETURN_EMPTY;
PUSHMARK (SP);
token = strtok (list, ",");
while (token != NULL)
{
hexchat_pluginpref_get_str (ph, token, value);
XPUSHs (sv_2mortal (newSVpv (token, 0)));
XPUSHs (sv_2mortal (newSVpv (value, 0)));
token = strtok (NULL, ",");
}
PUTBACK;
}
/* xs_init is the second argument perl_parse. As the name hints, it
initializes XS subroutines (see the perlembed manpage) */
static void
@ -1320,36 +1292,31 @@ xs_init (pTHX)
scripts by the 'use perlmod;' construction */
newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
/* load up all the custom IRC perl functions */
newXS ("HexChat::Internal::register", XS_HexChat_register, __FILE__);
newXS ("HexChat::Internal::hook_server", XS_HexChat_hook_server, __FILE__);
newXS ("HexChat::Internal::hook_command", XS_HexChat_hook_command, __FILE__);
newXS ("HexChat::Internal::hook_print", XS_HexChat_hook_print, __FILE__);
newXS ("HexChat::Internal::hook_timer", XS_HexChat_hook_timer, __FILE__);
newXS ("HexChat::Internal::hook_fd", XS_HexChat_hook_fd, __FILE__);
newXS ("HexChat::Internal::unhook", XS_HexChat_unhook, __FILE__);
newXS ("HexChat::Internal::print", XS_HexChat_print, __FILE__);
newXS ("HexChat::Internal::command", XS_HexChat_command, __FILE__);
newXS ("HexChat::Internal::set_context", XS_HexChat_set_context, __FILE__);
newXS ("HexChat::Internal::get_info", XS_HexChat_get_info, __FILE__);
newXS ("HexChat::Internal::context_info", XS_HexChat_context_info, __FILE__);
newXS ("HexChat::Internal::get_list", XS_HexChat_get_list, __FILE__);
newXS ("HexChat::Internal::plugin_pref_set", XS_HexChat_plugin_pref_set, __FILE__);
newXS ("HexChat::Internal::plugin_pref_get", XS_HexChat_plugin_pref_get, __FILE__);
newXS ("HexChat::Internal::plugin_pref_delete", XS_HexChat_plugin_pref_delete, __FILE__);
newXS ("HexChat::Internal::plugin_pref_list", XS_HexChat_plugin_pref_list, __FILE__);
newXS ("Xchat::Internal::register", XS_Xchat_register, __FILE__);
newXS ("Xchat::Internal::hook_server", XS_Xchat_hook_server, __FILE__);
newXS ("Xchat::Internal::hook_command", XS_Xchat_hook_command, __FILE__);
newXS ("Xchat::Internal::hook_print", XS_Xchat_hook_print, __FILE__);
newXS ("Xchat::Internal::hook_timer", XS_Xchat_hook_timer, __FILE__);
newXS ("Xchat::Internal::hook_fd", XS_Xchat_hook_fd, __FILE__);
newXS ("Xchat::Internal::unhook", XS_Xchat_unhook, __FILE__);
newXS ("Xchat::Internal::print", XS_Xchat_print, __FILE__);
newXS ("Xchat::Internal::command", XS_Xchat_command, __FILE__);
newXS ("Xchat::Internal::set_context", XS_Xchat_set_context, __FILE__);
newXS ("Xchat::Internal::get_info", XS_Xchat_get_info, __FILE__);
newXS ("Xchat::Internal::context_info", XS_Xchat_context_info, __FILE__);
newXS ("Xchat::Internal::get_list", XS_Xchat_get_list, __FILE__);
newXS ("HexChat::find_context", XS_HexChat_find_context, __FILE__);
newXS ("HexChat::get_context", XS_HexChat_get_context, __FILE__);
newXS ("HexChat::get_prefs", XS_HexChat_get_prefs, __FILE__);
newXS ("HexChat::emit_print", XS_HexChat_emit_print, __FILE__);
newXS ("HexChat::send_modes", XS_HexChat_send_modes, __FILE__);
newXS ("HexChat::nickcmp", XS_HexChat_nickcmp, __FILE__);
newXS ("Xchat::find_context", XS_Xchat_find_context, __FILE__);
newXS ("Xchat::get_context", XS_Xchat_get_context, __FILE__);
newXS ("Xchat::get_prefs", XS_Xchat_get_prefs, __FILE__);
newXS ("Xchat::emit_print", XS_Xchat_emit_print, __FILE__);
newXS ("Xchat::send_modes", XS_Xchat_send_modes, __FILE__);
newXS ("Xchat::nickcmp", XS_Xchat_nickcmp, __FILE__);
newXS ("HexChat::Embed::plugingui_remove", XS_HexChat_Embed_plugingui_remove,
newXS ("Xchat::Embed::plugingui_remove", XS_Xchat_Embed_plugingui_remove,
__FILE__);
stash = get_hv ("HexChat::", TRUE);
stash = get_hv ("Xchat::", TRUE);
if (stash == NULL) {
exit (1);
}
@ -1361,8 +1328,7 @@ xs_init (pTHX)
newCONSTSUB (stash, "PRI_LOWEST", newSViv (HEXCHAT_PRI_LOWEST));
newCONSTSUB (stash, "EAT_NONE", newSViv (HEXCHAT_EAT_NONE));
newCONSTSUB (stash, "EAT_HEXCHAT", newSViv (HEXCHAT_EAT_HEXCHAT));
newCONSTSUB (stash, "EAT_XCHAT", newSViv (HEXCHAT_EAT_HEXCHAT)); /* for compatibility */
newCONSTSUB (stash, "EAT_XCHAT", newSViv (HEXCHAT_EAT_HEXCHAT));
newCONSTSUB (stash, "EAT_PLUGIN", newSViv (HEXCHAT_EAT_PLUGIN));
newCONSTSUB (stash, "EAT_ALL", newSViv (HEXCHAT_EAT_ALL));
newCONSTSUB (stash, "FD_READ", newSViv (HEXCHAT_FD_READ));
@ -1372,7 +1338,7 @@ xs_init (pTHX)
newCONSTSUB (stash, "KEEP", newSViv (1));
newCONSTSUB (stash, "REMOVE", newSViv (0));
version = get_sv( "HexChat::VERSION", 1 );
version = get_sv( "Xchat::VERSION", 1 );
sv_setpv( version, PACKAGE_VERSION );
}
@ -1386,7 +1352,7 @@ perl_init (void)
static const char xchat_definitions[] = {
/* Redefine the $SIG{__WARN__} handler to have HexChat
printing warnings in the main window. (TheHobbit) */
#include "hexchat.pm.h"
#include "xchat.pm.h"
};
#ifdef OLD_PERL
static const char irc_definitions[] = {
@ -1444,9 +1410,9 @@ perl_load_file (char *filename)
/* http://forum.xchat.org/viewtopic.php?t=3277 */
thread_mbox ("Cannot use this " PERL_DLL "\n\n"
#ifdef _WIN64
"64-bit HexChat Perl is required.");
"64-bit Strawberry Perl is required.");
#else
"32-bit HexChat Perl is required.");
"32-bit Strawberry Perl is required.");
#endif
else {
/* a lot of people install this old version */
@ -1458,14 +1424,14 @@ perl_load_file (char *filename)
"You must have a Visual C++ build of Perl "
PERL_REQUIRED_VERSION " installed in order to\n"
"run Perl scripts. A reboot may be required.\n\n"
"http://hexchat.github.io/downloads.html\n\n"
"http://hexchat.org/downloads.html\n\n"
"I have found Perl 5.6, but that is too old.");
} else {
thread_mbox ("Cannot open " PERL_DLL "!\n\n"
"You must have a Visual C++ build of Perl "
PERL_REQUIRED_VERSION " installed in order to\n"
"run Perl scripts. A reboot may be required.\n\n"
"http://hexchat.github.io/downloads.html\n\n"
"http://hexchat.org/downloads.html\n\n"
"Make sure Perl's bin directory is in your PATH.");
}
}
@ -1482,7 +1448,7 @@ perl_load_file (char *filename)
perl_init ();
}
return execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::load", 0)),
return execute_perl (sv_2mortal (newSVpv ("Xchat::Embed::load", 0)),
filename);
}
@ -1492,7 +1458,7 @@ perl_end (void)
{
if (my_perl != NULL) {
execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::unload_all", 0)), "");
execute_perl (sv_2mortal (newSVpv ("Xchat::Embed::unload_all", 0)), "");
PL_perl_destruct_level = 1;
perl_destruct (my_perl);
perl_free (my_perl);
@ -1506,7 +1472,7 @@ static int
perl_command_unloadall (char *word[], char *word_eol[], void *userdata)
{
if (my_perl != NULL) {
execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::unload_all", 0)), "");
execute_perl (sv_2mortal (newSVpv ("Xchat::Embed::unload_all", 0)), "");
return HEXCHAT_EAT_HEXCHAT;
}
@ -1517,7 +1483,7 @@ static int
perl_command_reloadall (char *word[], char *word_eol[], void *userdata)
{
if (my_perl != NULL) {
execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::reload_all", 0)), "");
execute_perl (sv_2mortal (newSVpv ("Xchat::Embed::reload_all", 0)), "");
return HEXCHAT_EAT_HEXCHAT;
} else {
@ -1546,7 +1512,7 @@ perl_command_unload (char *word[], char *word_eol[], void *userdata)
char *file = get_filename (word, word_eol);
if (my_perl != NULL && file != NULL) {
execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::unload", 0)), file);
execute_perl (sv_2mortal (newSVpv ("Xchat::Embed::unload", 0)), file);
return HEXCHAT_EAT_HEXCHAT;
}
@ -1559,7 +1525,7 @@ perl_command_reload (char *word[], char *word_eol[], void *eat)
char *file = get_filename (word, word_eol);
if (my_perl != NULL && file != NULL) {
execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::reload", 0)), file);
execute_perl (sv_2mortal (newSVpv ("Xchat::Embed::reload", 0)), file);
return HEXCHAT_EAT_HEXCHAT;
}
@ -1569,15 +1535,6 @@ perl_command_reload (char *word[], char *word_eol[], void *eat)
return HEXCHAT_EAT_NONE;
}
static int
perl_command_eval (char *word[], char *word_eol[], void *userdata)
{
if (my_perl != NULL)
execute_perl (sv_2mortal (newSVpv ("HexChat::Embed::evaluate", 0)), word_eol[2]);
return HEXCHAT_EAT_HEXCHAT;
}
void
hexchat_plugin_get_info (char **name, char **desc, char **version,
void **reserved)
@ -1615,15 +1572,12 @@ hexchat_plugin_init (hexchat_plugin * plugin_handle, char **plugin_name,
0);
hexchat_hook_command (ph, "reload", HEXCHAT_PRI_NORM, perl_command_reload, 0,
0);
hexchat_hook_command (ph, "pl_reload", HEXCHAT_PRI_NORM, perl_command_reload,
"Reloads a Perl script. Syntax: /pl_reload <filename.pl>", (int*)1);
hexchat_hook_command (ph, "pl_reload", HEXCHAT_PRI_NORM, perl_command_reload, 0,
(int*)1);
hexchat_hook_command (ph, "unloadall", HEXCHAT_PRI_NORM,
perl_command_unloadall, "Unloads all loaded Perl scripts.", 0);
perl_command_unloadall, 0, 0);
hexchat_hook_command (ph, "reloadall", HEXCHAT_PRI_NORM,
perl_command_reloadall, "Realoads all loaded Perl scripts.", 0);
hexchat_hook_command (ph, "pl", HEXCHAT_PRI_NORM,
perl_command_eval, "Evaluates Perl code. Syntax: /pl <perl code>", 0);
perl_command_reloadall, 0, 0);
/*perl_init (); */
hexchat_hook_timer (ph, 0, perl_auto_load, NULL );

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
@ -17,54 +16,101 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{D90BC3E3-1341-4849-9354-5F40489D39D1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>perl520</RootNamespace>
<RootNamespace>perl518</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
<PropertyGroup>
<TargetName>hcperl</TargetName>
<OutDir>$(HexChatRel)plugins\</OutDir>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\win32\hexchat.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetName>$(PerlOutput)</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>$(PerlOutput)</TargetName>
<OutDir>$(HexChatBin)</OutDir>
<IntDir>$(HexChatObj)$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PERL520_EXPORTS;HAS_BOOL;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);..\..\src\common;$(HexChatLib);$(PerlPath)\lib\CORE;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PERL518_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(PerlPath)\lib\CORE;$(IntDir);..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(IntDir);$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(PerlLib).lib;$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(PerlLib).lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>perl.def</ModuleDefinitionFile>
<DelayLoadDLLs>$(PerlLib).dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<PreBuildEvent>
<Command>"$(GendefPath)\gendef" "$(PerlPath)\bin\$(PerlLib).dll"
move $(PerlLib).def "$(IntDir)"
lib /nologo /machine:x86 "/def:$(IntDir)$(PerlLib).def" "/out:$(IntDir)\$(PerlLib).lib"
lib /nologo /machine:x86 "/def:$(IntDir)$(PerlLib).def" "/out:$(OutDir)\$(PerlLib).lib"
"$(PerlPath)\bin\perl.exe" generate_header
move irc.pm.h "$(IntDir)"
move hexchat.pm.h "$(IntDir)"</Command>
move xchat.pm.h "$(IntDir)"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PERL520_EXPORTS;HAS_BOOL;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);..\..\src\common;$(HexChatLib);$(PerlPath)\lib\CORE;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>
</PrecompiledHeader>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PERL518_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(PerlPath)\lib\CORE;$(IntDir);..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(IntDir);$(DepsRoot)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(PerlLib).lib;$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(PerlLib).lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>perl.def</ModuleDefinitionFile>
<DelayLoadDLLs>$(PerlLib).dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<PreBuildEvent>
<Command>"$(GendefPath)\gendef" "$(PerlPath)\bin\$(PerlLib).dll"
move $(PerlLib).def "$(IntDir)"
lib /nologo /machine:x64 "/def:$(IntDir)$(PerlLib).def" "/out:$(IntDir)\$(PerlLib).lib"
lib /nologo /machine:x64 "/def:$(IntDir)$(PerlLib).def" "/out:$(OutDir)\$(PerlLib).lib"
"$(PerlPath)\bin\perl.exe" generate_header
move irc.pm.h "$(IntDir)"
move hexchat.pm.h "$(IntDir)"</Command>
move xchat.pm.h "$(IntDir)"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
@ -74,4 +120,6 @@ move hexchat.pm.h "$(IntDir)"</Command>
<ClCompile Include="perl.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,69 @@
#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use Text::VimColor;
use HTML::TokeParser::Simple;
use HTML::Entities qw(decode_entities);
use Path::Class;
my $html_file = shift;
my $reader = file( $html_file )->openr;
unlink $html_file;
my $writer = file( $html_file )->openw;
my $parser = HTML::TokeParser::Simple->new( $reader );
while( my $token = $parser->get_token ) {
my $class_name = $token->get_attr( "class" );
if( $token->is_start_tag( "div" )
&& ( $class_name && $class_name =~ qr/\bexample\b/ )
) {
my $start_tag = $token;
$start_tag->set_attr( class => $class_name . " synNormal" );
my @content;
my $end_tag;
EXAMPLE:
while( $token = $parser->get_token ) {
if( $token->is_end_tag( "div" ) ) {
$end_tag = $token;
last EXAMPLE;
}
if( $token->is_text ) {
push @content, decode_entities( $token->as_is );
}
}
my $code = join "", @content;
# say $code;
my $vim = Text::VimColor->new(
string => $code,
filetype => "perl",
vim_options => [qw( -RXZ -i NONE -u NONE -N -n)],
);
my $html = $vim->html;
$html =~ s/^\s+//;
$html =~ s/\s+$//;
print $writer $start_tag->as_is;
my $lines = $html =~ tr/\n/\n/;
say $writer "<div class='line_number'>";
for my $line ( 0 .. $lines ) {
say $writer "<div>",1 + $line,"</div>";
}
say $writer "</div>";
print $writer "<div class='content'><pre>";
say $writer $html;
say $writer "</pre></div>";
print $writer $end_tag->as_is;
} else {
print $writer $token->as_is;
}
}

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