This commit is contained in:
Graeme Walker 2001-12-18 12:00:00 +00:00
parent 1f92260cdf
commit 2911440f23
131 changed files with 7924 additions and 2321 deletions

View File

@ -1,13 +1,23 @@
Change Log E-MailRelay Change Log
========== ======================
0.9.5 -> 0.9.6
--------------
* SMTP AUTHentication extension -- LOGIN mechanism only.
* Client-side protocol timeout.
* Client-side connection timeout.
* Preprocessor can cancel further message processing.
* Client's IP address recorded in envelope files.
* Multiple hard-coded listening addresses supported at compile-time.
* Fix for automatic reopening of stderr stream.
0.9.4 -> 0.9.5 0.9.4 -> 0.9.5
-------------- --------------
* Windows fixes and improvements: Windows fixes and improvements...
- system-tray + dialog-box user interface * system-tray + dialog-box user interface
- fix for dropped connections * fix for dropped connections
- fix for content file deletion * fix for content file deletion
- fix for directory iterator * fix for directory iterator
0.9.3 -> 0.9.4 0.9.3 -> 0.9.4
-------------- --------------
@ -26,8 +36,7 @@ Change Log
0.9.1 -> 0.9.2 0.9.1 -> 0.9.2
-------------- --------------
* Better autoconf detection. (Now builds on all SourceForge's * Better autoconf detection.
compile-farm environments, including FreeBSD and Solaris+gcc.)
* Workround for FreeBSD uname() feature. * Workround for FreeBSD uname() feature.
* Added missing .sh_ files to the distribution. * Added missing .sh_ files to the distribution.
* Fixed a benign directory iterator bug. * Fixed a benign directory iterator bug.

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -165,7 +165,7 @@ maintainer-clean-recursive:
dot_seen=no; \ dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \ rev="$$subdir $$rev"; \
test "$$subdir" = "." && dot_seen=yes; \ test "$$subdir" != "." || dot_seen=yes; \
done; \ done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \ test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \ target=`echo $@ | sed s/-recursive//`; \
@ -259,7 +259,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
@ -276,7 +276,6 @@ distdir: $(DISTFILES)
|| exit 1; \ || exit 1; \
fi; \ fi; \
done done
info-am: info-am:
info: info-recursive info: info-recursive
dvi-am: dvi-am:

6
NEWS
View File

@ -1,6 +1,2 @@
to do no news
-----
* more-native windows port (system tray, registry etc)
* Mac OSX build
* setuid() security

12
README
View File

@ -59,20 +59,16 @@ The following documentation is provided:
* doc/developer.txt -- developer guide * doc/developer.txt -- developer guide
* ChangeLog -- change log for releases * ChangeLog -- change log for releases
And for completeness the following stub documents are also included:
* NEWS
* AUTHORS
Source code documentation can be generated by using doxygen (www.doxygen.org). Source code documentation can be generated by using doxygen (www.doxygen.org).
Configurations Configurations
-------------- --------------
The code was developed on SuSE Linux 7.1 using: The code was developed on SuSE Linux 7.1 using:
* linux 2.2.18, * linux 2.4.10,
* gcc 2.95.2, * gcc 2.95.3,
* glibc 2.2.7 (libc.so.6), * glibc 2.2.4 (libc.so.6),
* gnu make 3.79.1, * gnu make 3.79.1,
* autoconf 2.13 * autoconf 2.52
and ported to Windows 98 using and ported to Windows 98 using
* MSVC 6.0 * MSVC 6.0

12
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
dnl aclocal.m4 generated automatically by aclocal 1.4 dnl aclocal.m4 generated automatically by aclocal 1.4-p5
dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it, dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved. dnl with or without modifications, as long as this notice is preserved.
@ -19,7 +19,7 @@ dnl PARTICULAR PURPOSE.
dnl Usage: dnl Usage:
dnl AM_INIT_AUTOMAKE(package,version, [no-define]) dnl AM_INIT_AUTOMAKE(package,version, [no-define])
AC_DEFUN(AM_INIT_AUTOMAKE, AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_REQUIRE([AC_PROG_INSTALL]) [AC_REQUIRE([AC_PROG_INSTALL])
PACKAGE=[$1] PACKAGE=[$1]
AC_SUBST(PACKAGE) AC_SUBST(PACKAGE)
@ -47,7 +47,7 @@ AC_REQUIRE([AC_PROG_MAKE_SET])])
# Check to make sure that the build environment is sane. # Check to make sure that the build environment is sane.
# #
AC_DEFUN(AM_SANITY_CHECK, AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane]) [AC_MSG_CHECKING([whether build environment is sane])
# Just in case # Just in case
sleep 1 sleep 1
@ -88,7 +88,7 @@ AC_MSG_RESULT(yes)])
dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
dnl The program must properly implement --version. dnl The program must properly implement --version.
AC_DEFUN(AM_MISSING_PROG, AC_DEFUN([AM_MISSING_PROG],
[AC_MSG_CHECKING(for working $2) [AC_MSG_CHECKING(for working $2)
# Run test in a subshell; some versions of sh will print an error if # Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected. # an executable is not found, even if stderr is redirected.
@ -104,7 +104,7 @@ AC_SUBST($1)])
# Like AC_CONFIG_HEADER, but automatically create stamp file. # Like AC_CONFIG_HEADER, but automatically create stamp file.
AC_DEFUN(AM_CONFIG_HEADER, AC_DEFUN([AM_CONFIG_HEADER],
[AC_PREREQ([2.12]) [AC_PREREQ([2.12])
AC_CONFIG_HEADER([$1]) AC_CONFIG_HEADER([$1])
dnl When config.status generates a header, we must update the stamp-h file. dnl When config.status generates a header, we must update the stamp-h file.

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -150,7 +150,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \

View File

@ -27,7 +27,7 @@
awk="awk" awk="awk"
tmp="/tmp/`basename $0`.$$.tmp" tmp="/tmp/`basename $0`.$$.tmp"
log="/tmp/`basename $0`.$$.out" log="/tmp/`basename $0`.out"
trap "rm -f ${tmp} >/dev/null 2>&1 ; exit" 0 1 2 3 13 15 trap "rm -f ${tmp} >/dev/null 2>&1 ; exit" 0 1 2 3 13 15
### ###
@ -56,10 +56,10 @@ ProcessContent()
function rot_s( n , string ) function rot_s( n , string )
{ {
result = "" rot_s_result = ""
for( i = 1 ; i <= length(string) ; i++ ) for( i = 1 ; i <= length(string) ; i++ )
result = result rot_c(n,substr(string,i,1)) rot_s_result = rot_s_result rot_c(n,substr(string,i,1))
return result return rot_s_result
} }
{ {
@ -117,10 +117,10 @@ Wrap()
is_mime_content = match($0,"^Content-") is_mime_content = match($0,"^Content-")
is_continuation = match($0,"^[[:space:]][[:space:]]*[^[:space:]]") is_continuation = match($0,"^[[:space:]][[:space:]]*[^[:space:]]")
block = is_mime_content || (was_mime_content && is_continuation) suppress = is_mime_content || (was_mime_content && is_continuation)
was_mime_content = block was_mime_content = suppress
if( ! block ) if( ! suppress )
print print
} }
else else
@ -141,6 +141,11 @@ Main()
cp ${tmp} "${1}" cp ${tmp} "${1}"
} }
# Main $@ > ${log} 2>&1 debug="0"
Main $@ if test "${debug}" -eq 1
then
Main $@ > ${log} 2>&1
else
Main $@
fi

View File

@ -23,33 +23,39 @@
# #
# Soak tests the E-MailRelay system. # Soak tests the E-MailRelay system.
# #
# (As a side-effect it does "killall emailrelay".)
#
# configuration # configuration
# #
exe="../src/main/emailrelay" exe="`dirname $0`/../src/main/emailrelay"
content="/etc/services"
pp="1001" # port prefix pp="1001" # port prefix
null_filter="/bin/touch"
as_client="--no-syslog --no-daemon --dont-serve --forward --forward-to" # no --log
as_server="--log" # no --close-stderr
as_proxy="--log --immediate --forward-to" # no --close-stderr
content="/etc/passwd"
# configuration fallback # configuration fallback
# #
if test \! -f "${exe}" bin_dir="`dirname $0`"
if test \! -f "${exe}" -a -x "${bin_dir}/../emailrelay"
then then
exe="../emailrelay" exe="${bin_dir}/../emailrelay"
fi echo `basename $0`: using executable \"${exe}\" >&2
if test \! -f "${null_filter}"
then
null_filter="/usr/bin/touch"
fi fi
# initialisation # initialisation
# #
as_client="--no-syslog --no-daemon --dont-serve --forward --forward-to" # no --log
as_server="--log" # no --close-stderr
as_proxy="--log --immediate --forward-to" # no --close-stderr
base_dir="/tmp/`basename $0`.$$.tmp" base_dir="/tmp/`basename $0`.$$.tmp"
auth_file="${base_dir}/`basename $0 .sh`.auth"
mkdir "${base_dir}" mkdir "${base_dir}"
trap "rm -rf ${base_dir} 2>/dev/null ; killall emailrelay ; exit" 0 1 2 3 13 15 trap "rm -rf ${base_dir} 2>/dev/null ; killall emailrelay 2>/dev/null ; exit" 0 1 2 3 13 15
Auth()
{
echo "login server joe joe+00s+3Dpassword"
echo "login client joe joe+00s+3Dpassword"
}
Content() Content()
{ {
@ -57,7 +63,7 @@ Content()
echo "Subject: test message from process" $$ echo "Subject: test message from process" $$
echo "From: tester" echo "From: tester"
echo "" echo ""
for i in 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 for i in 1 1 1 1 1 1 1 1 1 1
do do
cat "${content}" cat "${content}"
done done
@ -65,11 +71,13 @@ Content()
Envelope() Envelope()
{ {
echo "X-MailRelay-Format: #2821.2" echo "X-MailRelay-Format: #2821.3"
echo "X-MailRelay-Content: 8bit" echo "X-MailRelay-Content: 8bit"
echo "X-MailRelay-From: me" echo "X-MailRelay-From: me"
echo "X-MailRelay-ToCount: 1" echo "X-MailRelay-ToCount: 1"
echo "X-MailRelay-To-Remote:" ${USER}@localhost echo "X-MailRelay-To-Remote:" ${USER}@localhost
echo "X-MailRelay-Authentication: anon"
echo "X-MailRelay-Client: 127.0.0.1"
echo "X-MailRelay-End: 1" echo "X-MailRelay-End: 1"
} }
@ -91,7 +99,7 @@ RunClient()
to_address="${1}" to_address="${1}"
spool_dir="${2}" spool_dir="${2}"
${exe} ${as_client} ${to_address} --spool-dir ${spool_dir} ${exe} ${as_client} ${to_address} --spool-dir ${spool_dir} --client-auth ${auth_file}
} }
Send() Send()
@ -120,6 +128,7 @@ RunServer()
mkdir -p "${spool_dir}" mkdir -p "${spool_dir}"
${exe} ${as_server} --port ${port} --spool-dir ${spool_dir} \ ${exe} ${as_server} --port ${port} --spool-dir ${spool_dir} \
--pid-file ${pid_file} \ --pid-file ${pid_file} \
--server-auth ${auth_file} \
--admin `expr ${port} + 100` --forward-to localhost:smtp --no-syslog 2> "${log}" --admin `expr ${port} + 100` --forward-to localhost:smtp --no-syslog 2> "${log}"
} }
@ -139,23 +148,55 @@ RunProxy()
mkdir -p "${spool_dir}" mkdir -p "${spool_dir}"
${exe} ${as_proxy} ${to_address} --port ${port} --spool-dir ${spool_dir} \ ${exe} ${as_proxy} ${to_address} --port ${port} --spool-dir ${spool_dir} \
--pid-file ${pid_file} \ --pid-file ${pid_file} \
--server-auth ${auth_file} \
--client-auth ${auth_file} \
--admin `expr ${port} + 100` --no-syslog 2> "${log}" --admin `expr ${port} + 100` --no-syslog 2> "${log}"
} }
killall emailrelay Init()
{
killall emailrelay 2>/dev/null
Auth > ${auth_file}
}
RunServer ${pp}3 ${base_dir}/spool-3 server-2.out server-2.pid RunServers()
RunProxy ${pp}1 localhost:${pp}3 ${base_dir}/spool-1 proxy.out proxy.pid {
RunServer ${pp}2 ${base_dir}/spool-2 server-1.out server-1.pid RunServer ${pp}3 ${base_dir}/spool-3 server-2.out server-2.pid
RunProxy ${pp}1 localhost:${pp}3 ${base_dir}/spool-1 proxy.out proxy.pid
RunServer ${pp}2 ${base_dir}/spool-2 server-1.out server-1.pid
sleep 1 # to allow pid files time to be written
}
sleep 1 # to allow pid files time to be written CheckServers()
echo ps -l -p `cat server-2.pid` -p `cat server-1.pid` -p `cat proxy.pid` {
ps -l -p `cat server-2.pid` -p `cat server-1.pid` -p `cat proxy.pid` if test \! -f server-1.pid -o \! -f server-2.pid -o \! -f proxy.pid
then
echo `basename $0`: error starting 'server(s)' >&2
cat server-?.out proxy.out 2>/dev/null | sed 's/^/ /' >&2
exit 1
fi
}
while true Ps()
do {
Send localhost:${pp}1 echo `basename $0`: output from \"ps -l -p `cat server-2.pid` -p `cat server-1.pid` -p `cat proxy.pid`\"...
Send localhost:${pp}2 ps -l -p `cat server-2.pid` -p `cat server-1.pid` -p `cat proxy.pid` | sed 's/^/ /'
echo -n . }
done
Main()
{
while true
do
Send localhost:${pp}1
Send localhost:${pp}2
echo -n .
rm -f ${base_dir}/spool-?/*content
done
}
Init
RunServers
CheckServers
Ps
Main

View File

@ -36,9 +36,12 @@
# configuration # configuration
# #
exe="../src/main/emailrelay" exe_dir="../src/main"
poke="../src/main/emailrelay-poke" if test "${1}" != "" ; then exe_dir="${1}" ; fi
exe="${exe_dir}/emailrelay"
poke="${exe_dir}/emailrelay-poke"
null_filter="/bin/touch" null_filter="/bin/touch"
content_file="/etc/services"
pp="1001" # port-prefix pp="1001" # port-prefix
# configuration fallback # configuration fallback
@ -51,6 +54,7 @@ fi
# initialisation # initialisation
# #
base_dir="/tmp/`basename $0`.$$.tmp" base_dir="/tmp/`basename $0`.$$.tmp"
summary_log="/tmp/`basename $0`.out"
exit_code="1" exit_code="1"
Cleanup() Cleanup()
@ -58,10 +62,11 @@ Cleanup()
kill `cat ${base_dir}/pid-* 2>/dev/null` 2>/dev/null kill `cat ${base_dir}/pid-* 2>/dev/null` 2>/dev/null
if test -d ${base_dir} if test -d ${base_dir}
then then
grep "MailRelay-Reason" ${base_dir}/*/*envelope*bad > /tmp/`basename $0`.out 2>/dev/null grep "MailRelay-Reason" ${base_dir}/*/*envelope*bad > "${summary_log}" 2>/dev/null
grep "." ${base_dir}/log-? >> /tmp/`basename $0`.out 2>/dev/null grep "." ${base_dir}/log-? >> "${summary_log}" 2>/dev/null
ls -lR ${base_dir} >> "${summary_log}" 2>/dev/null
diff -w ${base_dir}/store-4/*content "${content_file}" >> "${summary_log}" 2>/dev/null
fi fi
rm -rf ${base_dir} 2>/dev/null
} }
Trap() Trap()
@ -109,17 +114,19 @@ Content()
echo "Subject: test message 1" echo "Subject: test message 1"
echo "From: sender" echo "From: sender"
echo " " echo " "
echo "Content" cat "${content_file}"
} }
Envelope() Envelope()
{ {
echo "X-MailRelay-Format: #2821.2" echo "X-MailRelay-Format: #2821.3"
echo "X-MailRelay-Content: 8bit" echo "X-MailRelay-Content: 8bit"
echo "X-MailRelay-From: sender" echo "X-MailRelay-From: sender"
echo "X-MailRelay-ToCount: 2" echo "X-MailRelay-ToCount: 2"
echo "X-MailRelay-To-Remote: recipient-1@localhost" echo "X-MailRelay-To-Remote: recipient-1@localhost"
echo "X-MailRelay-To-Remote: recipient-2@localhost" echo "X-MailRelay-To-Remote: recipient-2@localhost"
echo "X-MailRelay-Authentication: "
echo "X-MailRelay-Client: 127.0.0.1"
echo "X-MailRelay-End: 1" echo "X-MailRelay-End: 1"
} }
@ -135,13 +142,13 @@ CheckResults()
exit_code="0" exit_code="0"
echo `basename $0`: succeeded echo `basename $0`: succeeded
else else
echo `basename $0`: failed: see /tmp/`basename $0`.out >&2 echo `basename $0`: failed: see ${summary_log} >&2
fi fi
} }
StartTimer() StartTimer()
{ {
( sleep 5 ; Cleanup ) & ( sleep 30 ; Cleanup ) &
} }
CreateMessages() CreateMessages()
@ -151,14 +158,33 @@ CreateMessages()
Envelope | CrLf > ${base_dir}/store-1/emailrelay.0.1.envelope Envelope | CrLf > ${base_dir}/store-1/emailrelay.0.1.envelope
} }
CreateAuth()
{
mkdir -p "${base_dir}"
file="${base_dir}/server.auth"
echo "# server.auth" > ${file}
echo "login server fred freds_password" >> ${file}
echo "login server joe joe+00s_password" >> ${file}
echo "login client dummy pwd" >> ${file}
echo "cram-md5 client dummy digest" >> ${file}
file="${base_dir}/client.auth"
echo "# client.auth" > ${file}
echo "cram-md5 client foo bar" >> ${file}
echo "login client joe joe+00s_password" >> ${file}
echo "login server abc def" >> ${file}
}
trap "Trap ; exit" 1 2 3 13 15 trap "Trap ; exit" 1 2 3 13 15
trap "Trap 0 ; exit" 0 trap "Trap 0 ; exit" 0
StartTimer StartTimer
CreateAuth
RunServer ${pp}1 store-2 log-1 pid-1 RunServer ${pp}1 store-2 log-1 pid-1
RunServer ${pp}2 store-2 log-2 pid-2 "--admin ${pp}9 --forward-to localhost:${pp}3" RunServer ${pp}2 store-2 log-2 pid-2 "--admin ${pp}9 --forward-to localhost:${pp}3"
RunServer ${pp}3 store-3 log-3 pid-3 "--immediate --forward-to localhost:${pp}4 --filter ${null_filter}" RunServer ${pp}3 store-3 log-3 pid-3 "--immediate --forward-to localhost:${pp}4 --filter ${null_filter} --client-auth ${base_dir}/client.auth"
RunServer ${pp}4 store-4 log-4 pid-4 RunServer ${pp}4 store-4 log-4 pid-4 "--server-auth ${base_dir}/server.auth"
CreateMessages CreateMessages
RunClient localhost:${pp}1 store-1 log-c pid-5 RunClient localhost:${pp}1 store-1 log-c pid-5
RunPoke ${pp}9 log-p RunPoke ${pp}9 log-p

View File

@ -131,9 +131,13 @@ function dequote( line )
{ {
quote = "\"" quote = "\""
not_quote = "[^" quote "]" not_quote = "[^" quote "]"
gsub( quote not_quote "*" quote , "<b><em>&</em></b>" , line ) #start_tag="<kbd><b>"
gsub( "<em>" quote , "<em>" , line ) #end_tag="</b></kbd>"
gsub( quote "</em>" , "</em>" , line ) start_tag="<b>"
end_tag="</b>"
gsub( quote not_quote "*" quote , start_tag "&" end_tag , line )
gsub( start_tag quote , start_tag , line )
gsub( quote end_tag , end_tag , line )
return line return line
} }
@ -153,6 +157,11 @@ function tagOutput( line , tag )
printf( "<%s>%s</%s>\n" , tag , fn(dequote(escape(line))) , tag ) printf( "<%s>%s</%s>\n" , tag , fn(dequote(escape(line))) , tag )
} }
function tagOutputRaw( line , tag )
{
printf( "<%s>%s</%s>\n" , tag , escape(line) , tag )
}
function process( line , next_ ) function process( line , next_ )
{ {
tab = " " tab = " "
@ -176,7 +185,7 @@ function process( line , next_ )
} }
else if( is_code ) else if( is_code )
{ {
tagOutput( line , "pre" ) tagOutputRaw( line , "pre" )
} }
else if( is_definition_term ) else if( is_definition_term )
{ {
@ -211,13 +220,13 @@ function process( line , next_ )
{ {
major += 1 major += 1
minor = 0 minor = 0
printf( "<h1><a name=\"H_%d\">%s</h1>" , major , line ) printf( "<h1><a name=\"H_%d\">%s</a></h1>" , major , line )
printf( "<!-- index:1:H:%d::%s -->\n" , major , line ) printf( "<!-- index:1:H:%d::%s -->\n" , major , line )
} }
else if( is_sub_heading ) else if( is_sub_heading )
{ {
minor += 1 minor += 1
printf( "<h2><a name=\"SH_%d_%d\">%s</h2>" , major , minor , line ) printf( "<h2><a name=\"SH_%d_%d\">%s</a></h2>" , major , minor , line )
printf( "<!-- index:2:SH:%d:%d:%s -->\n" , major , minor , line ) printf( "<!-- index:2:SH:%d:%d:%s -->\n" , major , minor , line )
} }
else if( !is_heading_line && !is_sub_heading_line ) else if( !is_heading_line && !is_sub_heading_line )
@ -245,7 +254,13 @@ END {
# === # ===
# AugmentLists() # AugmentLists()
# #
# Adds list begin/end tags around a set of list items. # Adds list begin/end tags around a set of list items
# eg. <ul> and </ul> tags either side of a set of
# contiguous <li> lines.
#
# The 'ignore' parameters can be used to make sure that
# list-item lines separated with 'ignore' patterns are
# treated as being contiguous.
# #
AugmentLists() AugmentLists()
{ {
@ -310,15 +325,17 @@ ${awk} -v tag="${1}" '
# === # ===
# Decorate() # Decorate()
# #
# Adds additional stuff after a given opening tag. # Adds additional stuff after a given opening tag
# The tag is expected to be at the start of the line. # and optionally before a closing tag. The opening
# tag is expected to be at the start of the line.
# #
Decorate() Decorate()
{ {
${awk} -v tag="${1}" -v decoration="${2}" ' ${awk} -v tag="${1}" -v first="${2}" -v second="${3}" '
{ {
line = $0 line = $0
sub( "^<" tag ">" , "<" tag ">" decoration , line ) sub( "^<" tag ">" , "<" tag ">" first , line )
sub( "</" tag ">" , second "</" tag ">" , line )
print line print line
} ' } '
} }
@ -371,21 +388,33 @@ END {
# === # ===
# Anchorise_1() # Anchorise_1()
# #
# Converts [[-foo-bar-]] to <a href="foo">bar</a>. # Converts "*foo* [bar]" to <a href="bar">foo</a>.
# #
Anchorise_1() Anchorise_1()
{ {
sed 's/\[\[-\([^-]*\)-\([^-]*\)-\]\]/<a href="\1">\2<\/a>/g' sed 's/\*\([^[:space:]]*\)\* \[\([^[:space:]]*\)\]/<a href="\2">\1<\/a>/g'
} }
# === # ===
# Anchorise_2() # Anchorise_2()
# #
# Converts [[foo]] to <a href="../foo">foo</a>. # Converts [[-foo-bar-]] to <a href="foo">bar</a>.
# Deprecated.
# #
Anchorise_2() Anchorise_2()
{ {
sed 's/\[\[\([^\]*\)\]\]/<a href=..\/"\1">\1<\/a>/g' sed 's/\[\[-\([^-]*\)-\([^-]*\)-\]\]/<a href="\1" type="deprecated">\2<\/a>/g'
}
# ===
# Anchorise_3()
#
# Converts [[foo]] to <a href="../foo">foo</a>.
# Deprecated.
#
Anchorise_3()
{
sed 's/\[\[\([^\]*\)\]\]/<a href=..\/"\1" type="deprecated">\1<\/a>/g'
} }
# === # ===
@ -444,8 +473,7 @@ Cat "${file}" | \
Elide "dd" | \ Elide "dd" | \
Elide "pre" | \ Elide "pre" | \
Decorate dt "<img src=\"graphics/bullet.gif\">\\\&nbsp;" | \ Decorate dt "<img src=\"graphics/bullet.gif\">\\\&nbsp;" | \
Decorate dd "<p>" | \ Decorate dd "<p>" "<p>" | \
Anchorise_1 | \ Anchorise_1 | \
Anchorise_2 | \
MoveIndex MoveIndex

View File

@ -1,44 +1,43 @@
/* config.h.in. Generated automatically from configure.in by autoheader. */ /* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define if you have the ANSI C header files. */ /* Define if you have the <dirent.h> header file, and it defines `DIR'. */
#undef STDC_HEADERS
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define if you have the glob function. */
#undef HAVE_GLOB
/* Define if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H #undef HAVE_DIRENT_H
/* Define if you have the <ndir.h> header file. */ /* Define if you have the `glob' function. */
#undef HAVE_GLOB
/* have reentrant gmtime */
#undef HAVE_GMTIME_R
/* have reentrant localtime */
#undef HAVE_LOCALTIME_R
/* Define if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H #undef HAVE_NDIR_H
/* Define if you have the <sys/dir.h> header file. */ /* auto_ptr assignment has non-const rhs */
#undef HAVE_NONCONST_AUTOPTR
/* Define if you have the <sys/dir.h> header file, and it defines `DIR'. */
#undef HAVE_SYS_DIR_H #undef HAVE_SYS_DIR_H
/* Define if you have the <sys/ndir.h> header file. */ /* Define if you have the <sys/ndir.h> header file, and it defines `DIR'. */
#undef HAVE_SYS_NDIR_H #undef HAVE_SYS_NDIR_H
/* Define if you have the <sys/time.h> header file. */ /* Define if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H #undef HAVE_SYS_TIME_H
/* Define if you have the <unistd.h> header file. */ /* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H #undef HAVE_UNISTD_H
/* Name of package */ /* Name of package */
#undef PACKAGE #undef PACKAGE
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Version number of package */ /* Version number of package */
#undef VERSION #undef VERSION
/* auto_ptr assignment has non-const rhs */
#undef HAVE_NONCONST_AUTOPTR
/* have reentrant localtime */
#undef HAVE_LOCALTIME_R
/* have reentrant gmtime */
#undef HAVE_GMTIME_R

4966
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,7 @@ dnl ===
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_INIT(src/main/gsmtp.h) AC_INIT(src/main/gsmtp.h)
AM_INIT_AUTOMAKE(emailrelay,0.9.5) AM_INIT_AUTOMAKE(emailrelay,0.9.6)
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
dnl === dnl ===

View File

@ -1,7 +1,7 @@
EXTRA_DIST = developer.txt reference.txt userguide.txt index.html emailrelay.1 emailrelay-poke.1 doxygen_header.html graphics/bullet.gif EXTRA_DIST = developer.txt reference.txt userguide.txt windows.txt index.html emailrelay.1 emailrelay-poke.1 doxygen_header.html graphics/bullet.gif
noinst_SCRIPTS = .dox noinst_SCRIPTS = .dox
pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html windows.html changelog.html
CLEANFILES = $(noinst_SCRIPTS) html *.ht readme.html developer.html reference.html userguide.html man.html CLEANFILES = $(noinst_SCRIPTS) html *.ht readme.html developer.html reference.html userguide.html man.html
SUFFIXES = .txt .html .ht SUFFIXES = .txt .html .ht
@ -36,6 +36,9 @@ developer.html reference.html userguide.html: $(converter)
readme.html: $(top_srcdir)/README $(converter) readme.html: $(top_srcdir)/README $(converter)
$(converter) -a "$(AWK)" $(top_srcdir)/README > readme.html $(converter) -a "$(AWK)" $(top_srcdir)/README > readme.html
changelog.html: $(top_srcdir)/ChangeLog $(converter)
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog > changelog.html
install-data-local: install-data-local:
$(mkinstalldirs) $(destdir)$(mandir)/man1 $(mkinstalldirs) $(destdir)$(mandir)/man1
$(INSTALL) $(top_srcdir)/doc/emailrelay.1 $(destdir)$(mandir)/man1/emailrelay.1 $(INSTALL) $(top_srcdir)/doc/emailrelay.1 $(destdir)$(mandir)/man1/emailrelay.1

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -69,10 +69,10 @@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
VERSION = @VERSION@ VERSION = @VERSION@
EXTRA_DIST = developer.txt reference.txt userguide.txt index.html emailrelay.1 emailrelay-poke.1 doxygen_header.html graphics/bullet.gif EXTRA_DIST = developer.txt reference.txt userguide.txt windows.txt index.html emailrelay.1 emailrelay-poke.1 doxygen_header.html graphics/bullet.gif
noinst_SCRIPTS = .dox noinst_SCRIPTS = .dox
pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html windows.html changelog.html
CLEANFILES = $(noinst_SCRIPTS) html *.ht readme.html developer.html reference.html userguide.html man.html CLEANFILES = $(noinst_SCRIPTS) html *.ht readme.html developer.html reference.html userguide.html man.html
SUFFIXES = .txt .html .ht SUFFIXES = .txt .html .ht
@ -141,7 +141,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
@ -237,6 +237,9 @@ developer.html reference.html userguide.html: $(converter)
readme.html: $(top_srcdir)/README $(converter) readme.html: $(top_srcdir)/README $(converter)
$(converter) -a "$(AWK)" $(top_srcdir)/README > readme.html $(converter) -a "$(AWK)" $(top_srcdir)/README > readme.html
changelog.html: $(top_srcdir)/ChangeLog $(converter)
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog > changelog.html
install-data-local: install-data-local:
$(mkinstalldirs) $(destdir)$(mandir)/man1 $(mkinstalldirs) $(destdir)$(mandir)/man1
$(INSTALL) $(top_srcdir)/doc/emailrelay.1 $(destdir)$(mandir)/man1/emailrelay.1 $(INSTALL) $(top_srcdir)/doc/emailrelay.1 $(destdir)$(mandir)/man1/emailrelay.1

View File

@ -21,8 +21,8 @@ to create GUI windows in order to process network events. The extra GUI and
event classes are put into a separate library in the "src/win32" directory, event classes are put into a separate library in the "src/win32" directory,
using the namespace "GGui". using the namespace "GGui".
Class structure overview Class structure
------------------------ ---------------
The message-store functionality uses three abstract interfaces: "MessageStore", The message-store functionality uses three abstract interfaces: "MessageStore",
"NewMessage" and "StoredMessage". The "NewMessage" interface is used to create "NewMessage" and "StoredMessage". The "NewMessage" interface is used to create
messages within the store, and the "StoredMessage" interface is used for messages within the store, and the "StoredMessage" interface is used for
@ -38,6 +38,9 @@ another for immediate forwarding ("ProtocolMessageForward").
The protocol and message-store functionality are brought together by the The protocol and message-store functionality are brought together by the
high-level "GSmtp::Server" and "GSmtp::Client" classes. high-level "GSmtp::Server" and "GSmtp::Client" classes.
Simplified class diagrams for the *GNet* [graphics/gnet-classes.png] and
*GSmtp* [graphics/gsmtp-classes.png] namespaces are available.
Directory structure Directory structure
------------------- -------------------
@ -142,11 +145,27 @@ If porting to a good ANSI C++ compiler then start by removing files from the
review the following header files: "src/glib/gdef.h", "src/gnet/gnet.h", review the following header files: "src/glib/gdef.h", "src/gnet/gnet.h",
"src/glib/gmemory.h". "src/glib/gmemory.h".
IPv6 Compile-time features
---- ---------------------
IPv6 is supported at compile-time by selecting source files in the "src/gnet" The following features are available to source-code hackers:
directory ending "_ipv6.cpp" rather than "_ipv4.cpp". The code has been tested
to a limited extent on Linux. # IPv6
IPv6 is supported at compile-time by selecting source files in the "src/gnet"
directory ending "_ipv6.cpp" rather than "_ipv4.cpp". The code has been tested
to a limited extent on Linux.
# Verbose logging
Verbose logging can be enabled by defining the pre-processor symbol "_DEBUG".
(See "src/glib/glog.h".)
# Multiple listening ports
Refer to the Server constructor in "src/main/gsmtpserver.cpp". Set "normal"
to false and edit the hard-coded address strings. If the addresses
need different port numbers then pass them to bind() in the third
parameter.
Windows build Windows build
------------- -------------
@ -228,6 +247,11 @@ Other patterns:
- GSmtp::ServerProtocol - GSmtp::ServerProtocol
Idioms
------
The "<<=" operator defined in "src/glib/gmemory.h" is used idiomatically
to reassign a std::auto_ptr<>.
Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved. Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved.

View File

@ -29,6 +29,10 @@ emailrelay \- e-mail transfer agent
.B emailrelay .B emailrelay
--as-client --as-client
.I server-address .I server-address
.LP
.B emailrelay
--as-proxy
.I server-address
.SH DESCRIPTION .SH DESCRIPTION
.I emailrelay .I emailrelay
is an simple e-mail message transfer agent. It is intended to be used is an simple e-mail message transfer agent. It is intended to be used
@ -50,90 +54,77 @@ In this mode all messages are forwarded immediately to the downstream
server. server.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-V,--version
Displays version information and exits.
.TP
.B \-a,--admin \fIadmin-port\fR .B \-a,--admin \fIadmin-port\fR
Enables the administration interface and specifies its listening port number. Enables the administration interface and specifies its listening port number.
.TP .TP
.B \-q,--as-client \fIhost:port\fR
Equivalent to \fI--log\fR \fI--no-syslog\fR \fI--no-daemon\fR \fI--dont-serve\fR \fI--forward\fR \fI--forward-to\fR.
.TP
.B \-y,--as-proxy \fIhost:port\fR
Equivalent to \fI--log\fR \fI--close-stderr\fR \fI--immediate\fR \fI--forward-to\fR.
.TP
.B \-d,--as-server .B \-d,--as-server
Equivalent to \fI--close-stderr\fR \fI--log\fR. Equivalent to \fI--log\fR \fI--close-stderr\fR.
.TP
.B \-C,--client-auth \fIfile\fR
Enables authentication with remote server, using the given secrets file.
.TP .TP
.B \-e,--close-stderr .B \-e,--close-stderr
Closes the standard error stream when daemonising. Closes the standard error stream after start-up.
.TP .TP
.B \-f,--forward .B \-U,--connection-timeout \fItime\fR
Forwards stored mail on startup (requires \fI--forward-to\fR). Sets the client-side connection timeout in seconds (default is 40).
.TP
.B \-h,--help
Displays help text and exits.
.TP
.B \-i,--pid-file \fIpid-file\fR
Records the daemon process-id in the given file.
.TP
.B \-l,--log
Writes log information on standard error (if open) and syslog (if not disabled).
.TP
.B \-m,--immediate
Forwards each message as soon as it is received (requires \fI--forward-to\fR).
.TP
.B \-n,--no-syslog
Disables syslog output.
.TP
.B \-o,--forward-to \fIhost:port\fR
Specifies the remote smtp server (required by \fI--forward\fR and \fI--admin\fR).
.TP
.B \-p,--port \fIport\fR
Specifies the smtp listening port number.
.TP
.B \-q,--as-client \fIhost:port\fR
Equivalent to \fI--no-syslog\fR \fI--no-daemon\fR \fI--log\fR \fI--dont-serve\fR \fI--forward\fR \fI--forward-to\fR.
.TP
.B \-r,--remote-clients
Allows remote clients to connect.
.TP
.B \-s,--spool-dir \fIdir\fR
Specifies the spool directory (default is \fI/usr/local/var/spool/emailrelay\fR).
.TP
.B \-t,--no-daemon
Does not detach from the terminal.
.TP
.B \-v,--verbose
Generates more verbose logging (if compiled-in and logging enabled and stderr open).
.TP .TP
.B \-x,--dont-serve .B \-x,--dont-serve
Stops the process acting as a server (usually used with \fI--forward\fR). Stops the process acting as a server (usually used with \fI--forward\fR).
.TP .TP
.B \-y,--as-proxy \fIhost:port\fR
Equivalent to \fI--close-stderr\fR \fI--log\fR \fI--immediate\fR \fI--forward-to\fR.
.TP
.B \-z,--filter \fIprogram\fR .B \-z,--filter \fIprogram\fR
Defines a mail preprocessor (disallowed if running as root). Defines a mail pre-processor (disallowed if running as root).
.SH "DIAGNOSTICS" .TP
If the .B \-f,--forward
.IR --log , Forwards stored mail on startup (requires \fI--forward-to\fR).
.I --as-client .TP
or .B \-o,--forward-to \fIhost:port\fR
.I --as-server Specifies the remote smtp server (required by \fI--forward\fR and \fI--admin\fR).
switches are in force then warning and error messages .TP
are sent to .B \-h,--help
.I syslog Displays help text and exits.
(using the .TP
.BR LOG_MAIL .B \-m,--immediate
facility) and to Forwards each message as soon as it is received (requires \fI--forward-to\fR).
.IR stderr . .TP
Output to .B \-l,--log
.I syslog Writes log information on standard error (if open) and syslog (if not disabled).
can be disabled with .TP
.IR --no-syslog , .B \-t,--no-daemon
and output to stderr can be disabled in daemon mode with Does not detach from the terminal.
.IR --close-stderr . .TP
.PP .B \-n,--no-syslog
Failed e-mail messages are kept in the spool directory and given Disables syslog output.
a .TP
.I .bad .B \-i,--pid-file \fIpid-file\fR
filename suffix. The failure reason is usually recorded within the Records the daemon process-id in the given file.
envelope file itself. .TP
.B \-p,--port \fIport\fR
Specifies the smtp listening port number.
.TP
.B \-r,--remote-clients
Allows remote clients to connect.
.TP
.B \-T,--response-timeout \fItime\fR
Sets the client-side response timeout in seconds (default is 1800).
.TP
.B \-S,--server-auth \fIfile\fR
Enables authentication of remote clients, using the given secrets file.
.TP
.B \-s,--spool-dir \fIdir\fR
Specifies the spool directory (default is \fI/usr/local/var/spool/emailrelay\fR).
.TP
.B \-v,--verbose
Generates more verbose logging (if compiled-in and logging enabled and stderr open).
.TP
.B \-V,--version
Displays version information and exits.
.SH FILES .SH FILES
.IP \(bu 2 .IP \(bu 2
/usr/local/sbin/emailrelay /usr/local/sbin/emailrelay

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 487 B

View File

@ -1,16 +1,19 @@
<html> <html>
<head> <head>
<title>E-MailRelay index</title>
</head> </head>
<body> <body>
<h1>E-MailRelay Documentation</h1> <h1>E-MailRelay Documentation</h1>
<bl> <ul>
<li><a href="readme.html">Readme</a></li> <li><a href="readme.html">Readme</a></li>
<li><a href="changelog.html">Change log</a></li>
<li><a href="userguide.html">User guide</a></li> <li><a href="userguide.html">User guide</a></li>
<li><a href="reference.html">Reference manual</a></li> <li><a href="reference.html">Reference manual</a></li>
<li><a href="windows.html">Windows installation guide</a></li>
<li><a href="developer.html">Notes for developers</a></li> <li><a href="developer.html">Notes for developers</a></li>
<li><a href="html/index.html">Source code documentation</a> (generated by <a href="http://www.doxygen.org">doxygen</a>, if available)</li> <li><a href="html/index.html">Source code documentation</a> (generated by <a href="http://www.doxygen.org">doxygen</a>, if available)</li>
<li><a href="man.html">Man page</a> (generated by man2html, if available)</li> <li><a href="man.html">Man page</a> (generated by man2html, if available)</li>
<li><a href="http://emailrelay.sourceforge.net">Web site</a></li> <li><a href="http://emailrelay.sourceforge.net">Web site</a></li>
</bl> </ul>
</body> </body>
</html> </html>

View File

@ -14,66 +14,78 @@ The "emailrelay" program supports the following command-line usage:
where <switch> is: where <switch> is:
# --version (-V)
Displays version information and exits.
# --admin (-a) # --admin (-a)
Enables the administration interface and specifies its listening port number. Enables the administration interface and specifies its listening port number.
# --as-client (-q)
Equivalent to "--log --no-syslog --no-daemon --dont-serve --forward --forward-to".
# --as-proxy (-y)
Equivalent to "--log --close-stderr --immediate --forward-to".
# --as-server (-d) # --as-server (-d)
Equivalent to "--close-stderr --log". Equivalent to "--log --close-stderr".
# --client-auth (-C)
Enables authentication with remote server, using the given secrets file.
# --close-stderr (-e) # --close-stderr (-e)
Closes the standard error stream when daemonising. Closes the standard error stream after start-up.
# --forward (-f) # --connection-timeout (-U)
Forwards stored mail on startup (requires --forward-to). Sets the client-side connection timeout in seconds (default is 40).
# --help (-h)
Displays help text and exits.
# --pid-file (-i)
Records the daemon process-id in the given file.
# --log (-l)
Writes log information on standard error (if open) and syslog (if not disabled).
# --immediate (-m)
Forwards each message as soon as it is received (requires --forward-to).
# --no-syslog (-n)
Disables syslog output.
# --forward-to (-o)
Specifies the remote smtp server (required by --forward and --admin).
# --port (-p)
Specifies the smtp listening port number.
# --as-client (-q)
Equivalent to "--no-syslog --no-daemon --log --dont-serve --forward --forward-to".
# --remote-clients (-r)
Allows remote clients to connect.
# --spool-dir (-s)
Specifies the spool directory (default is "/usr/local/var/spool/emailrelay").
# --no-daemon (-t)
Does not detach from the terminal.
# --verbose (-v)
Generates more verbose logging (if compiled-in and logging enabled and stderr open).
# --dont-serve (-x) # --dont-serve (-x)
Stops the process acting as a server (usually used with --forward). Stops the process acting as a server (usually used with --forward).
# --as-proxy (-y)
Equivalent to "--close-stderr --log --immediate --forward-to".
# --filter (-z) # --filter (-z)
Defines a mail pre-processor (disallowed if running as root). Defines a mail pre-processor (disallowed if running as root).
# --forward (-f)
Forwards stored mail on startup (requires --forward-to).
# --forward-to (-o)
Specifies the remote smtp server (required by --forward and --admin).
# --help (-h)
Displays help text and exits.
# --immediate (-m)
Forwards each message as soon as it is received (requires --forward-to).
# --log (-l)
Writes log information on standard error (if open) and syslog (if not disabled).
# --no-daemon (-t)
Does not detach from the terminal.
# --no-syslog (-n)
Disables syslog output.
# --pid-file (-i)
Records the daemon process-id in the given file.
# --port (-p)
Specifies the smtp listening port number.
# --remote-clients (-r)
Allows remote clients to connect.
# --response-timeout (-T)
Sets the client-side response timeout in seconds (default is 1800).
# --server-auth (-S)
Enables authentication of remote clients, using the given secrets file.
# --spool-dir (-s)
Specifies the spool directory (default is "/usr/local/var/spool/emailrelay").
# --verbose (-v)
Generates more verbose logging (if compiled-in and logging enabled and stderr open).
# --version (-V)
Displays version information and exits.
If no command-line switches are supplied at all then the default If no command-line switches are supplied at all then the default
behaviour is: behaviour is:
* to run as a daemon, detached from the terminal * to run as a daemon, detached from the terminal
@ -127,6 +139,11 @@ and the failure reason is written into the file.
SMTP issues SMTP issues
----------- -----------
# Authentication:
The AUTH extension is supported in V0.9.6, but only with the unofficial LOGIN
mechanism.
# Local delivery: # Local delivery:
E-MailRelay will reject all local recipients, with the exception of E-MailRelay will reject all local recipients, with the exception of
@ -149,9 +166,9 @@ SMTP issues
# Timeouts: # Timeouts:
Client-side timeouts are not implemented. If the ISP server is very slow then A simple client-side timeout is implemented which will abort the transaction
in a typical setup the dial-up line will be dropped due to inactivity. This if the server fails to respond to any of the client's SMTP commands within the
will have the desired effect of aborting the message submission. given time period.
# Message loops: # Message loops:
@ -200,17 +217,52 @@ forwards the mail on to the system's default MTA (on port 25):
--filter ${HOME}/.emailrelay/filter \ --filter ${HOME}/.emailrelay/filter \
--spool-dir ${HOME}/.emailrelay/spool --spool-dir ${HOME}/.emailrelay/spool
The pre-processor program should terminate with an exit code of zero to indicate
success. An exit code of 100 can be used to cancel all further processing of the
message, and any other non-zero exit code is used to indicate an error.
For example, the following pre-processor shell script examines the client's
IP address and conditionally dumps the message into "sendmail" (using the
sendmail command-line interface rather than SMTP):
#!/bin/sh
#
content="${1}"
envelope="`echo \"${content}\" | sed 's/content/envelope/'`"
ip="`awk '/MailRelay-Client:/ {print $2;exit}' \"${envelope}\"`"
if test "${ip}" = "192.168.0.2"
then
cat "${content}" | /usr/sbin/sendmail -t
rm -f "${envelope}" "${content}"
exit 100 # <= cancel further processing by emailrelay
fi
exit 0
An example pre-processor script which does simple rot-13 masking of messages is
also provided in the distribution ("share/emailrelay/emailrelay-process.sh").
This could be used as a template for a more sophisticated message encryption
system.
Security issues Security issues
--------------- ---------------
A major security concern is the use of an external mail pre-processor (using the A major security concern is the use of an external mail pre-processor (using the
--filter switch). In this release this feature is simply disabled if the process "--filter" switch). In this release this feature is simply disabled if the
is running as root (effective userid is zero). The pre-processor will run as the process is running as root (effective userid is zero). The pre-processor will
same userid as the E-MailRelay program, but with an almost empty set of run as the same userid as the E-MailRelay program, but with an almost empty set
environment variables, and no open file descriptors other than of environment variables, and no open file descriptors other than
"stdin"/"stdout"/"stderr" open onto "/dev/null". The pre-processor filename has "stdin"/"stdout"/"stderr" open onto "/dev/null". The pre-processor filename has
to be configured using a full path, so there is no dependence on the current to be configured using a full path, so there is no dependence on the current
working directory or the PATH variable. working directory or the PATH variable.
Security issues which relate to the SMTP protocol itself are beyond the scope of
this document, but RFC2821 makes the following observation: "SMTP mail is
inherently insecure in that it is feasible for even [..] casual users to [..]
create messages that will trick a [..] recipient into believing that they came
from somewhere else. [..] Real [..] security lies [..] in end-to-end methods [..]
such as those which use digital signatures."
The "Authentication" section below also relates to security.
Some other points are: Some other points are:
* The program runs with a "umask" of 177 so files are created with "-rw-------" permissions. * The program runs with a "umask" of 177 so files are created with "-rw-------" permissions.
* Strings are dynamically allocated, so buffer overflow/truncation issues are avoided. * Strings are dynamically allocated, so buffer overflow/truncation issues are avoided.
@ -218,28 +270,85 @@ Some other points are:
* No configuration parameters can be changed through the administrative interface. * No configuration parameters can be changed through the administrative interface.
* No exec(), system() or popen() calls are used other than execve() to spawn the mail pre-processor. * No exec(), system() or popen() calls are used other than execve() to spawn the mail pre-processor.
Authentication
--------------
E-MailRelay has some support for the ESMTP "AUTH" extension, as defined in
RFC2554, on both the server-side and client-side. The only authentication
mechanism currently provided is the non-standard (but widely used) "LOGIN"
mechanism, using plaintext passwords. A future release may add "CRAM-MD5"
(RFC2195).
Authentication is enabled with the "--auth-client" and "--auth-server"
command-line switches. The switch parameter is the name of a "secrets" file,
containing (in the current release) plaintext passwords.
The secrets file has a line-based format: blank lines are ignored and the hash
character (#) is used for comments. Lines have four white-space delimited
fields: "mechanism", "client-or-server", "userid", and "secret". The "mechanism"
field must be "login" (case-insensitive); the "client-or-server" field must be
"client" or "server"; the "userid" field is xtext-encoded user identifier; and
the "secret" field is the xtext-encoded plaintext password. (The "xtext"
encoding scheme is defined in RFC1891.) A client-side secrets file should
contain at least one "login client" entry, and a server-side secrets file should
contains zero or more "login server" entries. The same secrets file may be
specified for both "--auth-client" and "--auth-server" switches.
For example, the following secrets file defines "jsmith" as the username to be
used when E-MailRelay authenticates with a downstream server, and defines two
usernames ("user1" and "user2") which can be used by clients when they
authenticate with the E-MailRelay server:
#
# emailrelay secrets file
#
login client jsmith my+20password
login server user1 secret
login server user2 ignorance+3Ddeath
Clearly storing plaintext passwords in a file and then sending them unencypted
over a network is a bad thing. You should at least make sure that the secrets
file has tight permissions, and that the passwords in it are not also used for
anything important (such as root access).
On the server side authentication is advertised in the response to the SMTP
"EHLO" command, but authentication by the client is optional. If the client does
authenticate then the authenticated user-id is stored with the message and
then passed on to a downstream server using an "AUTH=userid" parameter on the
SMTP "MAIL FROM" command. If the client chooses not to authenticate then the
submitted messages will be forwarded using "AUTH=<>" on the "MAIL FROM"
command. Note that any "AUTH=userid" information on incoming submitted messages
is ignored and discarded: it is the authorised userid from the AUTH command
which is propogated, not the userid from the incoming "MAIL FROM" command's
"AUTH=" parameter.
On the client side authentication is performed when the client has connected to
a server which supports the AUTH extension with the LOGIN mechanism. If client
authentication is enabled (with the "--auth-client" switch) but the server does not
support the AUTH extension, or does not support the LOGIN mechanism, then the
client will fail the first message and terminate with an error message.
Note that some ISPs require separate POP/IMAP authentication before SMTP access
from a particular IP address is allowed. This type of POP-before-SMTP
authentication can be done outside the E-MailRelay system by POP/IMAP utilities
such as "fetchmail".
Files Files
----- -----
By default "make install" installs files in the following locations: By default "make install" installs files in the following locations:
* /usr/local/sbin/emailrelay
* /usr/local/libexec/emailrelay-poke * /usr/local/libexec/emailrelay-poke
* /usr/local/libexec/emailrelay.sh * /usr/local/libexec/emailrelay.sh
* /usr/local/sbin/emailrelay
* /usr/local/var/spool/emailrelay/empty_file * /usr/local/var/spool/emailrelay/empty_file
* /usr/local/share/emailrelay/emailrelay-notify.sh * /usr/local/share/emailrelay/emailrelay-notify.sh
* /usr/local/share/emailrelay/emailrelay-deliver.sh * /usr/local/share/emailrelay/emailrelay-deliver.sh
* /usr/local/share/emailrelay/emailrelay-process.sh * /usr/local/share/emailrelay/emailrelay-process.sh
* /usr/local/share/emailrelay/*.html * /usr/local/share/emailrelay/*.html
* /usr/local/share/emailrelay/graphics/bullet.gif
* /usr/local/man/man1/emailrelay.1
* /usr/local/man/man1/emailrelay-poke.1
This directory structure is constrained by the "autoconf" and GNU standards. This directory structure is constrained by the GNU/"autoconf" conventions rather
Preferred locations for a GNU/Linux distribution would be something like this: than the Filesystem Hierarchy Standard.
* /usr/sbin/emailrelay
* /opt/emailrelay/bin/emailrelay-poke
* /sbin/init.d/emailrelay.sh
* /var/spool/emailrelay/
* /opt/emailrelay/examples/emailrelay-notify.sh
* /opt/emailrelay/examples/emailrelay-deliver.sh
* /opt/emailrelay/examples/emailrelay-process.sh
* /usr/share/doc/packages/emailrelay/*.html

View File

@ -184,6 +184,89 @@ directory may be sufficient:
EOF EOF
Troubleshooting
---------------
A useful technique for troubleshooting SMTP problems is to telnet into the
remote server and drive the SMTP protocol manually. Telnet can be told to
connect to the remote SMTP port by putting the port number (25) on the command
line after the remote hostname, for example: "telnet smtp.myisp.net 25".
Once connected you should get a startup banner from the server, which will
probably tell you what server software you have connected to. From there you
should type something like "EHLO myhost.mydomain". The response to the EHLO
command should contain a list of SMTP extensions which the server software
supports. If this includes the AUTH extension then the set of supported
authentication mechanisms (such as LOGIN, CRAM-MD5 etc.) will be listed on the
same line.
After the EHLO response you should type "MAIL FROM:<myhost.mydomain>", retaining
the angle brackets but substituing your own address. If this is accepted then
enter a "RCPT TO:<me@myhost.mydomain>" command to say where the e-mail is going.
(Again, retain the angle brackets but substitute an appropriate address.)
After one or more "RCPT TO" commands you should enter the "DATA" command,
followed by the message content. The message content should include an RFC822
header, followed by a blank line, followed by the message text. For testing
purposes you might get away without having any header/body structure at all, but
to do things properly you should have at least a "To:" line, a "From:" line and
a "Subject:" line in the header.
At the end of the message text type a "." on a line of its own. At that point the
message should get dispatched, and end up in your in-box in the usual way
(assuming you put your own address in the "RCPT TO" command).
The following is an example SMTP dialogue, with ">>" and "<<" marks added to
show what was typed and what was received:
>> telnet smtp.myisp.net 25
<< Trying 12.34.56.78...
<< Connected to smtp.myisp.net.
<< Escape character is '^]'.
<< 220 mail12.myisp.net ESMTP Exim 3.13 #0 Sat, 17 Nov 2001 16:22:39 +0000
>> EHLO myhost.myisp.net
<< 250-mail12.myisp.net Hello modem-185.myisp.net [12.34.56.78]
<< 250-SIZE 104857600
<< 250-PIPELINING
<< 250 HELP
>> MAIL FROM:<me@myhost.myisp.net>
<< 250 <me@myhost.myisp.net> is syntactically correct
>> RCPT TO:<me@myhost.myisp.net>
<< 250 <me@myhost.myisp.net> verified
>> DATA
<< 354 Enter message, ending with "." on a line by itself
>> To: me@myhost.myisp.net
>> From: me@myhost.myisp.net
>> Subject: test
>>
>> Test message.
>> .
<< 250 OK id=1658Fp-0000Il-00
>> QUIT
<< 221 mail12.myisp.net closing connection
<< Connection closed by foreign host.
If you get some sort of "access denied" errors when talking to a server which
does not support the AUTH extension, then your ISP may be using POP-before-SMTP
authentication. In this scheme you are required to conduct an authenticated POP
or IMAP dialogue before you try to use SMTP. The POP/IMAP dialogue is done
separately from the SMTP connection, but bear in mind that there might be a time
limit so that your SMTP connection has to be made soon after the POP/IMAP
authentication. You should be able to use an e-mail front-end program, or
something like "fetchmail" to do the POP/IMAP authentication.
If you can send mail messages sucessfully using telnet, then you should look at
the E-MailRelay log output and compare what you do interactively with what
the program does. Usually when running as a server E-MailRelay logging goes to
the "syslog" system, and when running as a client it goes to the standard error
stream ("stderr"). To get the server to log onto stderr, replace the
"--as-server" command-line switch with "--log --no-syslog". Refer to the
reference guide for more information.
On Windows things are a bit more difficult because there is no syslog equivalent
on Win9x, and the standard error stream often gets lost. Starting E-MailRelay
from cygwin/bash on Win98 keeps stderr open (albeit with dreadful performance),
whereas the standard command prompt does not. If necessary the environment
variable "GLOGOUTPUT_FILE" can be defined as the name of a log file.
Glossary Glossary
-------- --------

99
doc/windows.txt Normal file
View File

@ -0,0 +1,99 @@
E-MailRelay for Windows
=======================
Introduction
------------
E-MailRelay was originally developed on Linux and so most of the documentation
relates to Unix-like operating systems rather than Microsoft Windows. This
document provides some help on Windows installation and setup.
Quick start
------------
In summary, the Windows installation process is as follows:
* Unpack the zip file to "Program Files\emailrelay".
* Create a shortcut to the E-MailRelay executable in "Start->Programs->StartUp".
* Add "storage-daemon" configuration options (if any) to the "StartUp" shortcut's command line.
* Create a shortcut to the executable on the taskbar and/or desktop.
* Add "forwarding-client" configuration options to the taskbar/desktop shortcut's command line. These configuration options will normally include something like "--as-client smtp.myisp.com:smtp".
* Create a spool directory under "<windir>\spool", eg. "c:\win98\spool\emailrelay".
* Configure your e-mail client (eg. Outlook) to use SMTP on the local machine for outgoing e-mail.
* Run the forwarding client from the taskbar/desktop shortcut once connected to the Internet.
These steps are explained in more detail below.
Unpacking
---------
To start the installation process you will need to extract the files from
the "zip" archive. If you have "WinZip" installed then double-clicking on
the E-MailRelay "zip" file should start WinZip and open the archive.
From WinZip you can press the "Extract" button, or use the "Actions->Extract"
menu option. In the "Extract to" box you can type the full path of a new
sub-directory under "Program Files" which will hold the extracted files, eg.
"C:\Program Files\emailrelay". WinZip will create the sub-directory
("emailrelay") if necessary.
Server configuration
--------------------
Once the files are unpacked you need to create a shortcut to the E-MailRelay
executable in the Start menu's "StartUp" folder. This will make sure that the
E-MailRelay server is started automatically when you next boot the machine and
log in.
One way to do this is to open up the "Program Files\emailrelay" folder using
Windows Explorer or "My Computer", and open a second folder window for the
Start menu. To open thes second "Start menu" window: (1) right-click on a
blank part of the taskbar, (2) select "Properties" from the popup menu, (3)
select the "Start Menu Programs" tab, and (4) press the "Advanced..."
button. In the Start menu window go down into the "Programs" folder and then
into "StartUp". Then simply drag the "emailrelay.exe" file from one window
to the other using the right mouse button. When you drop the file, select
the "Create Shortcut Here" option on the pop-up menu.
You can then configure the E-MailRelay server by adding configuration options
to the shortcut's command line. The server should work okay without this step,
but there may be options you want to add. Refer to the userguide and reference
manual for more information on what configuration options are available.
To add configuration options right-click on the new shortcut which you have
created in the "Start menu" window. Select "Properties" from the pop-up menu,
and then select the "Shortcut" tab in the properties dialog box. The "Target"
box should contain the name of the E-MailRelay executable. Add any additional
configuration options after the executable name, separated by a space.
Client configuration
--------------------
Once the server is configured the next step is to create an icon on the desktop
(or taskbar) which you can use to start the E-MailRelay forwarding client once
you are connected to the Internet.
You can do this by simply dragging the E-MailRelay executable file from the
"Program Files\emailrelay" folder onto the desktop. Then right click on the
new icon and select "Properties" from the pop-up menu.
Again the "Target" box should contain the path of the E-MailRelay executable,
and you should add configuration options at the end, separated by a space.
As a minumum you will need to add "--as-client myisp:smtp", where "myisp"
is replaced with the hostname of your ISP's SMTP server.
Preparation
-----------
To complete the installation you should create a spool directory to hold
your e-mail messages while you are off-line. By default E-MailRelay will
look for a directory "<windir>\spool\emailrelay", where "<windir>" is the
path of your main windows directory, typically "c:\win98" for Windows 98.
Finally you will need to configure you e-mail client program to use
the local E-MailRelay server for outgoing mail. Where it asks for the
name of the SMTP server for outgoing mail you should tell it to use
"localhost" or "127.0.0.1".
Uninstall
---------
There are no DLLs or registry entries to clean up: just delete the files under
"Program Files\emailrelay" and "<windir>\spool\emailrelay", and remove any
taskbar, desktop or "Start->Programs->StartUp" shortcuts.
Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved.

View File

@ -1,10 +1,10 @@
Summary: Simple e-mail message transfer agent using SMTP Summary: Simple e-mail message transfer agent using SMTP
Name: emailrelay Name: emailrelay
Version: 0.9.5 Version: 0.9.6
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: System Environment/Daemons Group: System Environment/Daemons
Source: http://emailrelay.sourceforge.net/.../emailrelay-src-0.9.5.tar.gz Source: http://emailrelay.sourceforge.net/.../emailrelay-src-0.9.6.tar.gz
BuildRoot: /tmp/emailrelay-install BuildRoot: /tmp/emailrelay-install
%description %description
@ -48,6 +48,7 @@ rm -rf $RPM_BUILD_ROOT
/usr/local/share/emailrelay/userguide.html /usr/local/share/emailrelay/userguide.html
/usr/local/share/emailrelay/man.html /usr/local/share/emailrelay/man.html
/usr/local/share/emailrelay/index.html /usr/local/share/emailrelay/index.html
/usr/local/share/emailrelay/windows.html
/usr/local/share/emailrelay/graphics/bullet.gif /usr/local/share/emailrelay/graphics/bullet.gif
/usr/local/share/emailrelay/html/ /usr/local/share/emailrelay/html/
/usr/local/man/man1/emailrelay.1 /usr/local/man/man1/emailrelay.1

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -126,7 +126,7 @@ maintainer-clean-recursive:
dot_seen=no; \ dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \ rev="$$subdir $$rev"; \
test "$$subdir" = "." && dot_seen=yes; \ test "$$subdir" != "." || dot_seen=yes; \
done; \ done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \ test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \ target=`echo $@ | sed s/-recursive//`; \
@ -187,7 +187,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -121,7 +121,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -121,7 +121,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \

20
missing
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Common stub for a few missing GNU programs while installing. # Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997 Free Software Foundation, Inc. # Copyright (C) 1996, 1997, 2001 Free Software Foundation, Inc.
# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996. # Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
@ -23,6 +23,14 @@ if test $# -eq 0; then
exit 1 exit 1
fi fi
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.in; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
case "$1" in case "$1" in
-h|--h|--he|--hel|--help) -h|--h|--he|--hel|--help)
@ -61,7 +69,7 @@ Supported PROGRAM values:
aclocal) aclocal)
echo 1>&2 "\ echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acinclude.m4' or \`configure.in'. You might want you modified \`acinclude.m4' or \`$configure_ac'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site." any GNU archive site."
touch aclocal.m4 touch aclocal.m4
@ -70,7 +78,7 @@ WARNING: \`$1' is missing on your system. You should only need it if
autoconf) autoconf)
echo 1>&2 "\ echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if WARNING: \`$1' is missing on your system. You should only need it if
you modified \`configure.in'. You might want to install the you modified \`$configure_ac'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site." archive site."
touch configure touch configure
@ -79,10 +87,10 @@ WARNING: \`$1' is missing on your system. You should only need it if
autoheader) autoheader)
echo 1>&2 "\ echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acconfig.h' or \`configure.in'. You might want you modified \`acconfig.h' or \`$configure_ac'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site." from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' $configure_ac`
test -z "$files" && files="config.h" test -z "$files" && files="config.h"
touch_files= touch_files=
for f in $files; do for f in $files; do
@ -98,7 +106,7 @@ WARNING: \`$1' is missing on your system. You should only need it if
automake) automake)
echo 1>&2 "\ echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if WARNING: \`$1' is missing on your system. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. you modified \`Makefile.am', \`acinclude.m4' or \`$configure_ac'.
You might want to install the \`Automake' and \`Perl' packages. You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site." Grab them from any GNU archive site."
find . -type f -name Makefile.am -print | find . -type f -name Makefile.am -print |

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -126,7 +126,7 @@ maintainer-clean-recursive:
dot_seen=no; \ dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \ rev="$$subdir $$rev"; \
test "$$subdir" = "." && dot_seen=yes; \ test "$$subdir" != "." || dot_seen=yes; \
done; \ done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \ test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \ target=`echo $@ | sed s/-recursive//`; \
@ -187,7 +187,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -211,7 +211,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
@ -249,22 +249,23 @@ gdatetime_unix.o: gdatetime_unix.cpp gdef.h ../../config.h \
gdirectory.o: gdirectory.cpp gdef.h ../../config.h \ gdirectory.o: gdirectory.cpp gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gdirectory.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gdirectory.h \
gpath.h gstrings.h gfs.h glog.h gpath.h gstrings.h gexception.h gfs.h glog.h
gdirectory_unix.o: gdirectory_unix.cpp gdef.h ../../config.h \ gdirectory_unix.o: gdirectory_unix.cpp gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gdirectory.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gdirectory.h \
gpath.h gstrings.h gfs.h gdebug.h glogoutput.h glog.h gassert.h gpath.h gstrings.h gexception.h gfs.h gfile.h gdebug.h \
glogoutput.h glog.h gassert.h
gexception.o: gexception.cpp gdef.h ../../config.h \ gexception.o: gexception.cpp gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gexception.h ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gexception.h
gfile.o: gfile.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \ gfile.o: gfile.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \ ../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
../../lib/gcc2.95/limits gfile.h gpath.h gstrings.h \ ../../lib/gcc2.95/limits gfile.h gpath.h gstrings.h \
gexception.h glog.h gexception.h gprocess.h glog.h
gfile_unix.o: gfile_unix.cpp gdef.h ../../config.h \ gfile_unix.o: gfile_unix.cpp gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gfile.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gfile.h \
gpath.h gstrings.h gexception.h gpath.h gstrings.h gexception.h gprocess.h
gfs_unix.o: gfs_unix.cpp gdef.h ../../config.h \ gfs_unix.o: gfs_unix.cpp gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gfs.h ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gfs.h

View File

@ -27,6 +27,7 @@
#include "gstr.h" #include "gstr.h"
#include "gdebug.h" #include "gdebug.h"
#include "gassert.h" #include "gassert.h"
#include <cstring>
G::Arg::Arg() G::Arg::Arg()
{ {
@ -138,3 +139,14 @@ std::string G::Arg::prefix() const
return m_prefix ; return m_prefix ;
} }
//static
const char * G::Arg::prefix( char * argv [] ) // throw()
{
const char * exe = argv[0] ;
const char * p1 = std::strrchr( exe , '/' ) ;
const char * p2 = std::strrchr( exe , '\\' ) ;
p1 = p1 ? (p1+1U) : exe ;
p2 = p2 ? (p2+1U) : exe ;
return p1 > p2 ? p1 : p2 ;
}

View File

@ -76,6 +76,11 @@ public:
// Returns the basename of v(0) without // Returns the basename of v(0) without
// any extension. // any extension.
static const char * prefix( char * argv[] ) ; // throw()
// An exception-free version of prefix() which can
// be used in main() outside of the outermost try
// block.
bool contains( const std::string & sw , size_t sw_args = 0U ) const ; bool contains( const std::string & sw , size_t sw_args = 0U ) const ;
// Returns true if the command line // Returns true if the command line
// contains the given switch with enough // contains the given switch with enough

View File

@ -25,7 +25,7 @@
#include "garg.h" #include "garg.h"
#include "gdebug.h" #include "gdebug.h"
std::string G::Arg::moduleName( HINSTANCE hinstance ) std::string G::Arg::moduleName( HINSTANCE )
{ {
return std::string() ; return std::string() ;
} }

View File

@ -86,7 +86,6 @@ void G::Date::init( const G::DateTime::BrokenDownTime & tm )
std::string G::Date::string( Format format ) const std::string G::Date::string( Format format ) const
{ {
const char * sep = format == yyyy_mm_dd_slash ? "/" : "" ;
std::stringstream ss ; std::stringstream ss ;
if( format == yyyy_mm_dd_slash ) if( format == yyyy_mm_dd_slash )
ss << m_year << "/" << m_month << "/" << m_day ; ss << m_year << "/" << m_month << "/" << m_day ;

View File

@ -27,9 +27,9 @@
#include "gassert.h" #include "gassert.h"
#include <sstream> #include <sstream>
const unsigned int minute = 60U ; const time_t minute = 60U ;
const unsigned int hour = 60U * minute ; const time_t hour = 60U * minute ;
const unsigned int day = 24U * hour ; const time_t day = 24U * hour ;
G::DateTime::EpochTime G::DateTime::now() G::DateTime::EpochTime G::DateTime::now()
{ {
@ -43,7 +43,7 @@ G::DateTime::EpochTime G::DateTime::epochTime( const BrokenDownTime & bdt_in )
EpochTime start = std::mktime( &bdt ) ; // localtime EpochTime start = std::mktime( &bdt ) ; // localtime
// iterate over all timezones // iterate over all timezones
const unsigned int delta = minute * 30U ; const time_t delta = minute * 30U ;
for( EpochTime t = (start-day-delta) ; t <= (start+day+delta) ; t += delta ) for( EpochTime t = (start-day-delta) ; t <= (start+day+delta) ; t += delta )
{ {
if( equivalent( t , bdt_in ) ) if( equivalent( t , bdt_in ) )

View File

@ -67,7 +67,8 @@ public:
// operation.) // operation.)
static std::string offsetString( Offset offset ) ; static std::string offsetString( Offset offset ) ;
// Uses the five-character format "+/-hhmm". // Converts the given utc/localtime offset into a five-character
// "+/-hhmm" string.
// See also RFC2822. // See also RFC2822.
private: private:

View File

@ -101,8 +101,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
// Define Windows-style types (under unix these // Define Windows-style types (only used for
// are only used for unimplemented declarations) // unimplemented declarations under unix)
// //
#if ! defined( G_WINDOWS ) #if ! defined( G_WINDOWS )
typedef unsigned char BOOL ; typedef unsigned char BOOL ;
@ -111,7 +111,8 @@
typedef unsigned int HANDLE ; typedef unsigned int HANDLE ;
#endif #endif
// Include commonly-used system headers // Include commonly-used system headers (good for
// pre-compilation)
// //
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -126,6 +127,8 @@
// //
typedef unsigned long g_uint32_t ; typedef unsigned long g_uint32_t ;
typedef unsigned short g_uint16_t ; typedef unsigned short g_uint16_t ;
typedef long g_int32_t ;
typedef short g_int16_t ;
// Define short-name types // Define short-name types
// //
@ -155,6 +158,7 @@
#pragma warning( disable : 4511 ) // cannot create default copy ctor #pragma warning( disable : 4511 ) // cannot create default copy ctor
#pragma warning( disable : 4512 ) // cannot create default op=() #pragma warning( disable : 4512 ) // cannot create default op=()
#pragma warning( disable : 4786 ) // truncation in debug info #pragma warning( disable : 4786 ) // truncation in debug info
#pragma warning( disable : 4275 ) // dll-interface stuff in <complex>
#endif #endif
#endif #endif

View File

@ -26,6 +26,7 @@
#include "gdef.h" #include "gdef.h"
#include "gpath.h" #include "gpath.h"
#include "gexception.h"
#include <string> #include <string>
#include <sys/types.h> #include <sys/types.h>

View File

@ -24,6 +24,7 @@
#include "gdef.h" #include "gdef.h"
#include "gdirectory.h" #include "gdirectory.h"
#include "gfs.h" #include "gfs.h"
#include "gfile.h"
#include "gdebug.h" #include "gdebug.h"
#include "glog.h" #include "glog.h"
#include <unistd.h> #include <unistd.h>
@ -236,6 +237,7 @@ std::string G::DirectoryIteratorImp::modificationTimeString() const
std::string G::DirectoryIteratorImp::sizeString() const std::string G::DirectoryIteratorImp::sizeString() const
{ {
return std::string("0") ; // for now std::string s = G::File::sizeString( filePath() ) ;
return s.empty() ? std::string("0") : s ;
} }

View File

@ -24,6 +24,7 @@
#include "gdef.h" #include "gdef.h"
#include "gdirectory.h" #include "gdirectory.h"
#include "gfs.h" #include "gfs.h"
#include "gfile.h"
#include "gdebug.h" #include "gdebug.h"
#include "glog.h" #include "glog.h"
#include <iomanip> #include <iomanip>
@ -295,8 +296,6 @@ std::string G::DirectoryIteratorImp::sizeString() const
const DWORD & hi = m_context.nFileSizeHigh ; const DWORD & hi = m_context.nFileSizeHigh ;
const DWORD & lo = m_context.nFileSizeLow ; const DWORD & lo = m_context.nFileSizeLow ;
std::stringstream ss ; return G::File::sizeString( hi , lo ) ;
ss << hi << std::setw(8) << std::setfill('0') << lo ;
return ss.str() ;
} }

View File

@ -23,6 +23,7 @@
#include "gdef.h" #include "gdef.h"
#include "gfile.h" #include "gfile.h"
#include "gprocess.h"
#include "glog.h" #include "glog.h"
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
@ -38,7 +39,7 @@ void G::File::remove( const Path & path )
{ {
if( 0 != std::remove( path.pathCstr() ) ) if( 0 != std::remove( path.pathCstr() ) )
{ {
//int error = std::errno ; //int error = G::Process::errno_() ;
throw CannotRemove( path.str() ) ; throw CannotRemove( path.str() ) ;
} }
G_DEBUG( "G::File::remove: \"" << path << "\"" ) ; G_DEBUG( "G::File::remove: \"" << path << "\"" ) ;
@ -55,7 +56,7 @@ void G::File::rename( const Path & from , const Path & to )
{ {
if( 0 != std::rename( from.pathCstr() , to.pathCstr() ) ) if( 0 != std::rename( from.pathCstr() , to.pathCstr() ) )
{ {
//int error = std::errno ; //int error = G::Process::errno_() ;
throw CannotRename( from.str() ) ; throw CannotRename( from.str() ) ;
} }
G_DEBUG( "G::File::rename: \"" << from << "\" -> \"" << to << "\"" ) ; G_DEBUG( "G::File::rename: \"" << from << "\" -> \"" << to << "\"" ) ;
@ -83,3 +84,32 @@ void G::File::mkdir( const Path & dir )
throw CannotMkdir( dir.str() ) ; throw CannotMkdir( dir.str() ) ;
} }
bool G::File::exists( const Path & path )
{
return exists( path , false , true ) ;
}
bool G::File::exists( const Path & path , const NoThrow & )
{
return exists( path , false , false ) ;
}
bool G::File::exists( const Path & path , bool on_error , bool do_throw )
{
bool enoent = false ;
bool rc = exists( path.pathCstr() , enoent ) ; // o/s-specific
if( !rc && enoent )
{
return false ;
}
else if( !rc && do_throw )
{
throw StatError( path.str() ) ;
}
else if( !rc )
{
return on_error ;
}
return true ;
}

View File

@ -32,6 +32,7 @@
namespace G namespace G
{ {
class File ; class File ;
class DirectoryIteratorImp ;
} ; } ;
// Class: G::File // Class: G::File
@ -41,10 +42,12 @@ namespace G
class G::File class G::File
{ {
public: public:
G_EXCEPTION( StatError , "cannot stat() file" ) ;
G_EXCEPTION( CannotRemove , "cannot delete file" ) ; G_EXCEPTION( CannotRemove , "cannot delete file" ) ;
G_EXCEPTION( CannotRename , "cannot rename file" ) ; G_EXCEPTION( CannotRename , "cannot rename file" ) ;
G_EXCEPTION( CannotCopy , "cannot copy file" ) ; G_EXCEPTION( CannotCopy , "cannot copy file" ) ;
G_EXCEPTION( CannotMkdir , "cannot mkdir" ) ; G_EXCEPTION( CannotMkdir , "cannot mkdir" ) ;
G_EXCEPTION( SizeOverflow , "file size overflow" ) ;
class NoThrow // An overload discriminator class for File methods. class NoThrow // An overload discriminator class for File methods.
{} ; {} ;
@ -71,6 +74,25 @@ public:
static void mkdir( const Path & dir ) ; static void mkdir( const Path & dir ) ;
// Creates a directory. // Creates a directory.
static std::string sizeString( const Path & file ) ;
// Returns the file's size in string format.
// Returns the empty string on error.
static bool exists( const Path & file ) ;
// Returns true if the file (or link or device etc.)
// exists. Throws an exception if permission denied
// or too many symlinks etc.
static bool exists( const Path & file , const NoThrow & ) ;
// Returns true if the file (or link or device etc.)
// exists. Returns false on error.
private:
friend class G::DirectoryIteratorImp ;
static std::string sizeString( g_uint32_t hi , g_uint32_t lo ) ; // win32
static bool exists( const Path & , bool , bool ) ;
static bool exists( const char * , bool & ) ; // o/s-specific
} ; } ;
#endif #endif

View File

@ -23,10 +23,39 @@
#include "gdef.h" #include "gdef.h"
#include "gfile.h" #include "gfile.h"
#include "gprocess.h"
#include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sstream>
bool G::File::mkdir( const Path & dir , const NoThrow & ) bool G::File::mkdir( const Path & dir , const NoThrow & )
{ {
return 0 == ::mkdir( dir.str().c_str() , S_IRUSR | S_IWUSR | S_IXUSR ) ; return 0 == ::mkdir( dir.str().c_str() , S_IRUSR | S_IWUSR | S_IXUSR ) ;
} }
bool G::File::exists( const char * path , bool & enoent )
{
struct stat statbuf ;
if( 0 == ::stat( path , &statbuf ) )
{
return true ;
}
else
{
int error = G::Process::errno_() ;
enoent = error == ENOENT || error == ENOTDIR ;
return false ;
}
}
std::string G::File::sizeString( const Path & path )
{
struct stat statbuf ;
if( 0 != ::stat( path.pathCstr() , &statbuf ) )
return std::string() ;
std::stringstream ss ;
ss << statbuf.st_size ;
return ss.str() ;
}

View File

@ -25,9 +25,55 @@
#include "gfile.h" #include "gfile.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <direct.h> #include <direct.h>
#include <iomanip>
#include <sstream>
bool G::File::mkdir( const Path & dir , const NoThrow & ) bool G::File::mkdir( const Path & dir , const NoThrow & )
{ {
return 0 == ::_mkdir( dir.str().c_str() ) ; return 0 == ::_mkdir( dir.str().c_str() ) ;
} }
std::string G::File::sizeString( const Path & path )
{
WIN32_FIND_DATA info ;
HANDLE h = ::FindFirstFile( path.str().c_str() , &info ) ;
if( h == INVALID_HANDLE_VALUE )
return std::string() ;
const DWORD & hi = info.nFileSizeHigh ;
const DWORD & lo = info.nFileSizeLow ;
::FindClose( h ) ;
return sizeString( hi , lo ) ;
}
std::string G::File::sizeString( g_uint32_t hi , g_uint32_t lo )
{
__int64 n = hi ;
n <<= 32U ;
n |= lo ;
if( n < 0 )
throw SizeOverflow() ;
if( n == 0 )
return std::string("0") ;
std::string s ;
while( n != 0 )
{
size_t i = n % 10U ;
s.insert( 0U , 1U , '0' + i ) ;
n /= 10U ;
}
return s ;
}
bool G::File::exists( const char * path , bool & enoent )
{
struct _stat statbuf ;
bool ok = 0 == ::_stat( path , &statbuf ) ;
enoent = !ok ;
return ok ;
}

View File

@ -148,6 +148,11 @@ size_t G::GetOpt::widthLimit( size_t w )
return (w != 0U && w < 50U) ? 50U : w ; return (w != 0U && w < 50U) ? 50U : w ;
} }
void G::GetOpt::showUsage( std::ostream & stream , const std::string & args ) const
{
showUsage( stream , m_args.prefix() , args ) ;
}
void G::GetOpt::showUsage( std::ostream & stream , const std::string & exe , const std::string & args , void G::GetOpt::showUsage( std::ostream & stream , const std::string & exe , const std::string & args ,
size_t tab_stop , size_t width ) const size_t tab_stop , size_t width ) const
{ {
@ -494,7 +499,12 @@ bool G::GetOpt::hasErrors() const
return m_errors.size() != 0U ; return m_errors.size() != 0U ;
} }
void G::GetOpt::showErrors( std::ostream &stream , std::string prefix_1 , void G::GetOpt::showErrors( std::ostream & stream ) const
{
showErrors( stream , m_args.prefix() ) ;
}
void G::GetOpt::showErrors( std::ostream & stream , std::string prefix_1 ,
std::string prefix_2 ) const std::string prefix_2 ) const
{ {
if( m_errors.size() != 0U ) if( m_errors.size() != 0U )

View File

@ -91,8 +91,11 @@ public:
const std::string & args , size_t tab_stop = 30U , const std::string & args , size_t tab_stop = 30U ,
size_t wrap_width = wrapDefault() ) const ; size_t wrap_width = wrapDefault() ) const ;
// Streams out multi-line usage text using // Streams out multi-line usage text using
// usageSummary() and usageHelp(). Does nothing // usageSummary() and usageHelp().
// about non-switch arguments.
void showUsage( std::ostream & stream , const std::string & args ) const ;
// Streams out multi-line usage text using
// usageSummary() and usageHelp().
bool hasErrors() const ; bool hasErrors() const ;
// Returns true if there are errors. // Returns true if there are errors.
@ -103,6 +106,9 @@ public:
// item to the given stream, prefixed with the given // item to the given stream, prefixed with the given
// prefix(es). The two prefixes are simply concatenated. // prefix(es). The two prefixes are simply concatenated.
void showErrors( std::ostream & stream ) const ;
// An overload which uses prefix() as <prefix_1>.
void show( std::ostream & stream , std::string prefix ) const ; void show( std::ostream & stream , std::string prefix ) const ;
// For debugging. // For debugging.
@ -134,8 +140,8 @@ private:
SwitchSpec(char c_,const std::string &name_,const std::string &description_, SwitchSpec(char c_,const std::string &name_,const std::string &description_,
bool v_,const std::string &vd_) : bool v_,const std::string &vd_) :
c(c_) , name(name_) , description(description_) , c(c_) , name(name_) , description(description_) ,
hidden(description_.empty()) , valued(v_) , hidden(description_.empty()) ,
valued(v_) , value_description(vd_) {} value_description(vd_) {}
} ; } ;
typedef std::map<std::string,SwitchSpec GLessAllocator(char,SwitchSpec) > SwitchSpecMap ; typedef std::map<std::string,SwitchSpec GLessAllocator(char,SwitchSpec) > SwitchSpecMap ;
typedef std::pair<bool,std::string> Value ; typedef std::pair<bool,std::string> Value ;

View File

@ -32,19 +32,14 @@ void G::LogOutput::rawOutput( G::Log::Severity severity , const char *message )
std::cerr << message ; std::cerr << message ;
std::cerr.flush() ; std::cerr.flush() ;
if( std::getenv("GLOGOUTPUT_DEBUGGER") != NULL ) static bool debugger = std::getenv("GLOGOUTPUT_DEBUGGER") != NULL ;
if( debugger )
{ {
::OutputDebugString( message ) ; ::OutputDebugString( message ) ;
} }
static bool first = true ; static const char * key = "GLOGOUTPUT_FILE" ;
static const char * filename = NULL ; static const char * filename = std::getenv( key ) ;
if( first )
{
first = false ;
const char * key = "GLOGOUTPUT_FILE" ;
filename = std::getenv(key) ;
}
if( filename != NULL && *filename != '\0' ) if( filename != NULL && *filename != '\0' )
{ {
static std::ofstream file( filename ) ; static std::ofstream file( filename ) ;

View File

@ -75,7 +75,7 @@ void operator<<=( std::auto_ptr<T> & ap , T * p )
// Description: A version for null-pointer constants. // Description: A version for null-pointer constants.
// //
template <class T> template <class T>
void operator<<=( std::auto_ptr<T> & ap , int null_pointer ) void operator<<=( std::auto_ptr<T> & ap , int /* null_pointer */ )
{ {
T * p = 0 ; T * p = 0 ;
ap <<= p ; ap <<= p ;

View File

@ -110,9 +110,11 @@ public:
// Returns true if this process has enhanced security // Returns true if this process has enhanced security
// privileges. // privileges.
static int errno_() ;
// Returns the process's current 'errno' value.
private: private:
Process() ; Process() ;
static int errno_() ;
static void execCore( const Path & , const std::string & ) ; static void execCore( const Path & , const std::string & ) ;
} ; } ;

View File

@ -31,6 +31,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> // open() #include <fcntl.h> // open()
// Class: G::Process::IdImp
// Description: A private implementation class used by G::Process.
//
class G::Process::IdImp class G::Process::IdImp
{ {
public: public:
@ -56,13 +59,15 @@ bool G::Process::cd( const Path & dir , NoThrow )
void G::Process::setUmask() void G::Process::setUmask()
{ {
mode_t new_mode = 0177 ; // create as -rw------- mode_t new_mode = 0177 ; // create as -rw-------
mode_t old_mode = ::umask( new_mode ) ; (void) ::umask( new_mode ) ;
} }
//static //static
void G::Process::closeStderr() void G::Process::closeStderr()
{ {
::close( STDERR_FILENO ) ; ::close( STDERR_FILENO ) ;
::open( G::FileSystem::nullDevice() , O_WRONLY ) ;
::fcntl( STDERR_FILENO , F_SETFD , 0 ) ; // close-on-exec false
} }
//static //static
@ -76,8 +81,24 @@ void G::Process::closeFiles( bool keep_stderr )
for( int fd = 0 ; fd < n ; fd++ ) for( int fd = 0 ; fd < n ; fd++ )
{ {
if( !keep_stderr || fd != STDERR_FILENO ) if( !keep_stderr || fd != STDERR_FILENO )
{
::close( fd ) ; ::close( fd ) ;
}
} }
// reopen standard fds to prevent accidental use
// of arbitrary files or sockets as standard
// streams
//
::open( G::FileSystem::nullDevice() , O_RDONLY ) ;
::open( G::FileSystem::nullDevice() , O_WRONLY ) ;
if( !keep_stderr )
{
::open( G::FileSystem::nullDevice() , O_WRONLY ) ;
::fcntl( STDERR_FILENO , F_SETFD , 0 ) ; // close-on-exec false
}
::fcntl( STDIN_FILENO , F_SETFD , 0 ) ; // close-on-exec false
::fcntl( STDOUT_FILENO , F_SETFD , 0 ) ; // close-on-exec false
} }
G::Process::Who G::Process::fork() G::Process::Who G::Process::fork()
@ -160,9 +181,6 @@ void G::Process::exec( const G::Path & exe , const std::string & arg )
throw InvalidPath( exe.str() ) ; throw InvalidPath( exe.str() ) ;
closeFiles() ; closeFiles() ;
(void) ::open( G::FileSystem::nullDevice() , O_RDONLY ) ; // stdin
(void) ::open( G::FileSystem::nullDevice() , O_WRONLY ) ; // stdout
(void) ::open( G::FileSystem::nullDevice() , O_WRONLY ) ; // stderr
// TODO: more security stuff required here -- setuid() etc. // TODO: more security stuff required here -- setuid() etc.

View File

@ -141,6 +141,7 @@ bool G::Process::privileged()
} }
// not implemented... // not implemented...
// int G::Process::errno_()
// Who G::Process::fork() {} // Who G::Process::fork() {}
// Who G::Process::fork( Id & child ) {} // Who G::Process::fork( Id & child ) {}
// void G::Process::exec( const Path & exe , const std::string & arg ) {} // void G::Process::exec( const Path & exe , const std::string & arg ) {}

View File

@ -182,7 +182,7 @@ unsigned int G::Str::toUInt( const std::string &s , bool limited )
unsigned long G::Str::toULong( const std::string &s , bool limited ) unsigned long G::Str::toULong( const std::string &s , bool limited )
{ {
char * end = NULL ; char * end = NULL ;
unsigned long result = ::strtoul( s.c_str(), &end, 0 ) ; unsigned long result = ::strtoul( s.c_str(), &end, 10 ) ;
if( end == 0 || end[0] != '\0' ) if( end == 0 || end[0] != '\0' )
throw InvalidFormat( s ) ; throw InvalidFormat( s ) ;
@ -257,6 +257,10 @@ std::string G::Str::toPrintableAscii( char c , char escape )
{ {
result.append( 1U , 't' ) ; result.append( 1U , 't' ) ;
} }
else if( c == '\0' )
{
result.append( 1U , '0' ) ;
}
else else
{ {
unsigned int n = c ; unsigned int n = c ;
@ -270,7 +274,7 @@ std::string G::Str::toPrintableAscii( char c , char escape )
std::string G::Str::toPrintableAscii( const std::string & in , char escape ) std::string G::Str::toPrintableAscii( const std::string & in , char escape )
{ {
std::string result ; std::string result ;
for( const char * p = in.c_str() ; *p ; ++p ) for( std::string::const_iterator p = in.begin() ; p != in.end() ; ++p )
result.append( toPrintableAscii(*p,escape) ) ; result.append( toPrintableAscii(*p,escape) ) ;
return result ; return result ;
} }
@ -293,8 +297,16 @@ std::string G::Str::readLineFrom( std::istream & stream , char ignore )
std::string G::Str::readLineFrom( std::istream & stream , const std::string & eol ) std::string G::Str::readLineFrom( std::istream & stream , const std::string & eol )
{ {
std::string result ;
readLineFrom( stream , eol , result ) ;
return result ;
}
void G::Str::readLineFrom( std::istream & stream , const std::string & eol , std::string & line )
{
line.erase() ;
const size_t eol_length = eol.length() ; const size_t eol_length = eol.length() ;
std::string line ;
char c ; char c ;
for( size_t line_length = 1U ; stream.get(c) ; ++line_length ) for( size_t line_length = 1U ; stream.get(c) ; ++line_length )
{ {
@ -305,11 +317,10 @@ std::string G::Str::readLineFrom( std::istream & stream , const std::string & eo
if( line.find(eol,offset) == offset ) if( line.find(eol,offset) == offset )
{ {
line.erase(offset) ; line.erase(offset) ;
return line ; break ;
} }
} }
} }
return line ;
} }
std::string G::Str::wrap( std::string text , const std::string & prefix_1 , std::string G::Str::wrap( std::string text , const std::string & prefix_1 ,

View File

@ -153,6 +153,9 @@ public:
// An overload which uses 'eol' as the terminator, and // An overload which uses 'eol' as the terminator, and
// without the 'ignore' feature. // without the 'ignore' feature.
static void readLineFrom( std::istream & stream , const std::string & eol , std::string & result ) ;
// An overload which avoids string copying.
static std::string wrap( std::string text , static std::string wrap( std::string text ,
const std::string & prefix_first_line , const std::string & prefix_subsequent_lines , const std::string & prefix_first_line , const std::string & prefix_subsequent_lines ,
size_t width = 70U ) ; size_t width = 70U ) ;

View File

@ -46,6 +46,7 @@ libgnet_a_SOURCES = gaddress_ipv4.cpp \
gserver.cpp \ gserver.cpp \
gsocket.cpp \ gsocket.cpp \
gsocket_unix.cpp \ gsocket_unix.cpp \
gtimer.cpp \
gaddress.h \ gaddress.h \
gclient.h \ gclient.h \
gconnection.h \ gconnection.h \
@ -61,4 +62,5 @@ libgnet_a_SOURCES = gaddress_ipv4.cpp \
gselect.h \ gselect.h \
gserver.h \ gserver.h \
gsocket.h \ gsocket.h \
gtimer.h \
gwinsock.h gwinsock.h

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -93,7 +93,7 @@ EXTRA_DIST = gclient_win32.cpp gdescriptor_win32.cpp gevent_win32.cpp glocal_
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib
noinst_LIBRARIES = libgnet.a noinst_LIBRARIES = libgnet.a
libgnet_a_SOURCES = gaddress_ipv4.cpp gclient.cpp gclient_unix.cpp gconnection.cpp gdescriptor_unix.cpp gevent.cpp gevent_unix.cpp geventserver.cpp glinebuffer.cpp glocal_unix.cpp gmonitor.cpp gresolve.cpp gresolve_ipv4.cpp gresolve_unix.cpp gselect.cpp gserver.cpp gsocket.cpp gsocket_unix.cpp gaddress.h gclient.h gconnection.h gdescriptor.h gevent.h geventserver.h glinebuffer.h glocal.h gmonitor.h gnet.h grequest.h gresolve.h gselect.h gserver.h gsocket.h gwinsock.h libgnet_a_SOURCES = gaddress_ipv4.cpp gclient.cpp gclient_unix.cpp gconnection.cpp gdescriptor_unix.cpp gevent.cpp gevent_unix.cpp geventserver.cpp glinebuffer.cpp glocal_unix.cpp gmonitor.cpp gresolve.cpp gresolve_ipv4.cpp gresolve_unix.cpp gselect.cpp gserver.cpp gsocket.cpp gsocket_unix.cpp gtimer.cpp gaddress.h gclient.h gconnection.h gdescriptor.h gevent.h geventserver.h glinebuffer.h glocal.h gmonitor.h gnet.h grequest.h gresolve.h gselect.h gserver.h gsocket.h gtimer.h gwinsock.h
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../../config.h CONFIG_HEADER = ../../config.h
@ -109,7 +109,7 @@ libgnet_a_LIBADD =
libgnet_a_OBJECTS = gaddress_ipv4.o gclient.o gclient_unix.o \ libgnet_a_OBJECTS = gaddress_ipv4.o gclient.o gclient_unix.o \
gconnection.o gdescriptor_unix.o gevent.o gevent_unix.o geventserver.o \ gconnection.o gdescriptor_unix.o gevent.o gevent_unix.o geventserver.o \
glinebuffer.o glocal_unix.o gmonitor.o gresolve.o gresolve_ipv4.o \ glinebuffer.o glocal_unix.o gmonitor.o gresolve.o gresolve_ipv4.o \
gresolve_unix.o gselect.o gserver.o gsocket.o gsocket_unix.o gresolve_unix.o gselect.o gserver.o gsocket.o gsocket_unix.o gtimer.o
CXXFLAGS = @CXXFLAGS@ CXXFLAGS = @CXXFLAGS@
CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX) CXXLD = $(CXX)
@ -211,7 +211,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
@ -230,7 +230,7 @@ gclient.o: gclient.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gaddress.h ../../src/glib/gexception.h gsocket.h gevent.h \ gaddress.h ../../src/glib/gexception.h gsocket.h gevent.h \
gdescriptor.h ../../src/glib/gdatetime.h gresolve.h gmonitor.h \ ../../src/glib/gdatetime.h gdescriptor.h gresolve.h gmonitor.h \
gclient.h gconnection.h gserver.h gselect.h \ gclient.h gconnection.h gserver.h gselect.h \
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \ ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/glog.h ../../src/glib/gassert.h ../../src/glib/glog.h ../../src/glib/gassert.h
@ -238,7 +238,7 @@ gclient_unix.o: gclient_unix.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gclient.h gaddress.h ../../src/glib/gexception.h gconnection.h \ gclient.h gaddress.h ../../src/glib/gexception.h gconnection.h \
gsocket.h gevent.h gdescriptor.h gsocket.h gevent.h ../../src/glib/gdatetime.h gdescriptor.h
gconnection.o: gconnection.cpp ../../src/glib/gdef.h ../../config.h \ gconnection.o: gconnection.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
@ -250,19 +250,21 @@ gdescriptor_unix.o: gdescriptor_unix.cpp ../../src/glib/gdef.h \
gevent.o: gevent.cpp ../../src/glib/gdef.h ../../config.h \ gevent.o: gevent.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gevent.h gdescriptor.h ../../src/glib/gdebug.h \ gevent.h ../../src/glib/gdatetime.h ../../src/glib/gexception.h \
gdescriptor.h ../../src/glib/gdebug.h \
../../src/glib/glogoutput.h ../../src/glib/glog.h \ ../../src/glib/glogoutput.h ../../src/glib/glog.h \
../../src/glib/gassert.h ../../src/glib/gassert.h
gevent_unix.o: gevent_unix.cpp ../../src/glib/gdef.h ../../config.h \ gevent_unix.o: gevent_unix.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gevent.h gdescriptor.h gselect.h ../../src/glib/gexception.h gevent.h ../../src/glib/gdatetime.h ../../src/glib/gexception.h \
gdescriptor.h gselect.h
geventserver.o: geventserver.cpp ../../src/glib/gdef.h ../../config.h \ geventserver.o: geventserver.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
geventserver.h gserver.h gsocket.h gaddress.h \ geventserver.h gserver.h gsocket.h gaddress.h \
../../src/glib/gexception.h gevent.h gdescriptor.h \ ../../src/glib/gexception.h gevent.h ../../src/glib/gdatetime.h \
gconnection.h gselect.h ../../src/glib/glog.h gdescriptor.h gconnection.h gselect.h ../../src/glib/glog.h
glinebuffer.o: glinebuffer.cpp ../../src/glib/gdef.h ../../config.h \ glinebuffer.o: glinebuffer.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
@ -278,17 +280,17 @@ gmonitor.o: gmonitor.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gmonitor.h gclient.h gaddress.h ../../src/glib/gexception.h \ gmonitor.h gclient.h gaddress.h ../../src/glib/gexception.h \
gconnection.h gsocket.h gevent.h gdescriptor.h gserver.h \ gconnection.h gsocket.h gevent.h ../../src/glib/gdatetime.h \
gselect.h ../../src/glib/gassert.h ../../src/glib/glogoutput.h \ gdescriptor.h gserver.h gselect.h ../../src/glib/gassert.h \
../../src/glib/glog.h ../../src/glib/glogoutput.h ../../src/glib/glog.h
gresolve.o: gresolve.cpp ../../src/glib/gdef.h ../../config.h \ gresolve.o: gresolve.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gresolve.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gresolve.h \
gnet.h gaddress.h ../../src/glib/gexception.h gsocket.h \ gnet.h gaddress.h ../../src/glib/gexception.h gsocket.h \
gevent.h gdescriptor.h ../../src/glib/gstr.h \ gevent.h ../../src/glib/gdatetime.h gdescriptor.h \
../../src/glib/gstrings.h ../../src/glib/gdebug.h \ ../../src/glib/gstr.h ../../src/glib/gstrings.h \
../../src/glib/glogoutput.h ../../src/glib/glog.h \ ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/gassert.h ../../src/glib/glog.h ../../src/glib/gassert.h
gresolve_ipv4.o: gresolve_ipv4.cpp ../../src/glib/gdef.h ../../config.h \ gresolve_ipv4.o: gresolve_ipv4.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gresolve.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gresolve.h \
@ -297,35 +299,45 @@ gresolve_unix.o: gresolve_unix.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gresolve.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gresolve.h \
gnet.h gaddress.h ../../src/glib/gexception.h gsocket.h \ gnet.h gaddress.h ../../src/glib/gexception.h gsocket.h \
gevent.h gdescriptor.h ../../src/glib/gstr.h \ gevent.h ../../src/glib/gdatetime.h gdescriptor.h \
../../src/glib/gstrings.h ../../src/glib/gdebug.h \ ../../src/glib/gstr.h ../../src/glib/gstrings.h \
../../src/glib/glogoutput.h ../../src/glib/glog.h \ ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/gassert.h ../../src/glib/glog.h ../../src/glib/gassert.h
gselect.o: gselect.cpp ../../src/glib/gdef.h ../../config.h \ gselect.o: gselect.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gselect.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gselect.h \
gnet.h gevent.h gdescriptor.h ../../src/glib/gexception.h \ gnet.h gevent.h ../../src/glib/gdatetime.h \
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \ ../../src/glib/gexception.h gdescriptor.h ../../src/glib/gstr.h \
../../src/glib/glog.h ../../src/glib/gassert.h ../../src/glib/gstrings.h gtimer.h ../../src/glib/gdebug.h \
../../src/glib/glogoutput.h ../../src/glib/glog.h \
../../src/glib/gassert.h
gserver.o: gserver.cpp ../../src/glib/gdef.h ../../config.h \ gserver.o: gserver.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gserver.h gsocket.h gaddress.h ../../src/glib/gexception.h \ gserver.h gsocket.h gaddress.h ../../src/glib/gexception.h \
gevent.h gdescriptor.h gconnection.h gselect.h gmonitor.h \ gevent.h ../../src/glib/gdatetime.h gdescriptor.h gconnection.h \
gclient.h ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \ gselect.h gmonitor.h gclient.h ../../src/glib/gdebug.h \
../../src/glib/glog.h ../../src/glib/gassert.h ../../src/glib/glogoutput.h ../../src/glib/glog.h \
../../src/glib/gassert.h ../../src/glib/gmemory.h
gsocket.o: gsocket.cpp ../../src/glib/gdef.h ../../config.h \ gsocket.o: gsocket.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
../../src/glib/gassert.h ../../src/glib/glogoutput.h \ ../../src/glib/gassert.h ../../src/glib/glogoutput.h \
../../src/glib/glog.h gsocket.h gaddress.h \ ../../src/glib/glog.h gsocket.h gaddress.h \
../../src/glib/gexception.h gevent.h gdescriptor.h \ ../../src/glib/gexception.h gevent.h ../../src/glib/gdatetime.h \
../../src/glib/gmemory.h ../../src/glib/gdebug.h gdescriptor.h ../../src/glib/gmemory.h ../../src/glib/gdebug.h
gsocket_unix.o: gsocket_unix.cpp ../../src/glib/gdef.h ../../config.h \ gsocket_unix.o: gsocket_unix.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gnet.h \
gsocket.h gaddress.h ../../src/glib/gexception.h gevent.h \ gsocket.h gaddress.h ../../src/glib/gexception.h gevent.h \
gdescriptor.h ../../src/glib/gdebug.h \ ../../src/glib/gdatetime.h gdescriptor.h \
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/glog.h ../../src/glib/gassert.h
gtimer.o: gtimer.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gtimer.h \
gnet.h ../../src/glib/gdatetime.h ../../src/glib/gexception.h \
gevent.h gdescriptor.h ../../src/glib/gdebug.h \
../../src/glib/glogoutput.h ../../src/glib/glog.h \ ../../src/glib/glogoutput.h ../../src/glib/glog.h \
../../src/glib/gassert.h ../../src/glib/gassert.h

View File

@ -80,6 +80,7 @@ private:
ClientResolver m_resolver ; ClientResolver m_resolver ;
StreamSocket * m_s ; StreamSocket * m_s ;
Address m_address ; Address m_address ;
std::string m_peer_name ;
Client & m_interface ; Client & m_interface ;
bool m_priviledged ; bool m_priviledged ;
enum Status { Success , Failure , Retry , ImmediateSuccess } ; enum Status { Success , Failure , Retry , ImmediateSuccess } ;
@ -96,7 +97,7 @@ public:
void writeEvent() ; void writeEvent() ;
void exceptionEvent() ; void exceptionEvent() ;
bool connect( std::string host , std::string service , std::string *error , bool sync_dns ) ; bool connect( std::string host , std::string service , std::string *error , bool sync_dns ) ;
std::string startConnecting( const Address & , bool & ) ; std::string startConnecting( const Address & , const std::string & , bool & ) ;
Status connectCore( Address , std::string * , bool , unsigned int ) ; Status connectCore( Address , std::string * , bool , unsigned int ) ;
void disconnect() ; void disconnect() ;
StreamSocket & s() ; StreamSocket & s() ;
@ -108,6 +109,7 @@ public:
void setState( State ) ; void setState( State ) ;
std::pair<bool,Address> localAddress() const ; std::pair<bool,Address> localAddress() const ;
std::pair<bool,Address> peerAddress() const ; std::pair<bool,Address> peerAddress() const ;
std::string peerName() const ;
private: private:
ClientImp( const ClientImp & ) ; ClientImp( const ClientImp & ) ;
@ -166,17 +168,22 @@ std::pair<bool,GNet::Address> GNet::Client::peerAddress() const
return m_imp->peerAddress() ; return m_imp->peerAddress() ;
} }
std::string GNet::Client::peerName() const
{
return m_imp->peerName() ;
}
// === // ===
bool GNet::ClientImp::m_first = true ; bool GNet::ClientImp::m_first = true ;
GNet::ClientImp::ClientImp( Client &intaface , bool priviledged , bool quit_on_disconnect ) : GNet::ClientImp::ClientImp( Client &intaface , bool priviledged , bool quit_on_disconnect ) :
m_interface(intaface) ,
m_state(Idle) ,
m_s(NULL) ,
m_resolver(*this) , m_resolver(*this) ,
m_priviledged(priviledged) , m_s(NULL) ,
m_address(Address::invalidAddress()) , m_address(Address::invalidAddress()) ,
m_interface(intaface) ,
m_priviledged(priviledged) ,
m_state(Idle) ,
m_quit_on_disconnect(quit_on_disconnect) m_quit_on_disconnect(quit_on_disconnect)
{ {
G_DEBUG( "ClientImp::ctor" ) ; G_DEBUG( "ClientImp::ctor" ) ;
@ -252,7 +259,7 @@ bool GNet::ClientImp::connect( std::string host , std::string service ,
return false ; return false ;
} }
bool immediate = false ; bool immediate = false ;
std::string connect_reason = startConnecting( pair.first.address , immediate ) ; std::string connect_reason = startConnecting( pair.first.address, pair.first.canonical_name, immediate);
if( connect_reason.length() != 0U ) if( connect_reason.length() != 0U )
{ {
error = connect_reason ; error = connect_reason ;
@ -295,8 +302,9 @@ void GNet::ClientImp::resolveCon( bool success , const Address &address ,
if( success ) if( success )
{ {
G_DEBUG( "GNet::ClientImp::resolveCon: " << address.displayString() ) ; G_DEBUG( "GNet::ClientImp::resolveCon: " << address.displayString() ) ;
std::string peer_name = resolve_reason ;
bool immediate = false ; bool immediate = false ;
std::string connect_reason = startConnecting( address , immediate ) ; std::string connect_reason = startConnecting( address , peer_name , immediate ) ;
if( connect_reason.length() ) if( connect_reason.length() )
{ {
close() ; close() ;
@ -314,11 +322,12 @@ void GNet::ClientImp::resolveCon( bool success , const Address &address ,
} }
} }
std::string GNet::ClientImp::startConnecting( const Address & address , bool & immediate ) std::string GNet::ClientImp::startConnecting( const Address & address , const std::string & peer_name , bool & immediate )
{ {
// save the target address // save the target address
G_DEBUG( "GNet::ClientImp::startConnecting: " << address.displayString() ) ; G_DEBUG( "GNet::ClientImp::startConnecting: " << address.displayString() ) ;
m_address = address ; m_address = address ;
m_peer_name = peer_name ;
// create and open a socket // create and open a socket
// //
@ -444,7 +453,7 @@ void GNet::ClientImp::readEvent()
else if( n != -1 ) else if( n != -1 )
{ {
G_ASSERT( n <= sizeof(buffer) ) ; G_ASSERT( n <= sizeof(buffer) ) ;
G_DEBUG( "GNet::ClientImp::readEvent: " << n << " byte(s)" ) ; //G_DEBUG( "GNet::ClientImp::readEvent: " << n << " byte(s)" ) ;
m_interface.onData( buffer , n ) ; m_interface.onData( buffer , n ) ;
} }
else else
@ -489,6 +498,11 @@ std::pair<bool,GNet::Address> GNet::ClientImp::peerAddress() const
return s().getPeerAddress() ; return s().getPeerAddress() ;
} }
std::string GNet::ClientImp::peerName() const
{
return m_peer_name ;
}
// === // ===
void GNet::ClientResolver::resolveCon( bool success , const Address &address , void GNet::ClientResolver::resolveCon( bool success , const Address &address ,

View File

@ -89,13 +89,17 @@ public:
// Destructor. // Destructor.
virtual std::pair<bool,Address> localAddress() const ; virtual std::pair<bool,Address> localAddress() const ;
// Returns the local address. // Override from Connection. Returns the local address.
// Pair.first is false on error. // Pair.first is false on error.
virtual std::pair<bool,Address> peerAddress() const ; virtual std::pair<bool,Address> peerAddress() const ;
// Returns the peer address. // Override from Connection. Returns the peer address.
// Pair.first is false on error. // Pair.first is false on error.
std::string peerName() const ;
// Returns the peer's canonical name if available.
// Returns the empty string if not.
protected: protected:
friend class ClientImp ; friend class ClientImp ;

View File

@ -83,7 +83,8 @@ GNet::EventHandlerList::EventHandlerList( std::string type ) :
//static //static
bool GNet::EventHandlerList::contains( const EventHandlerListImp & list , Descriptor fd ) bool GNet::EventHandlerList::contains( const EventHandlerListImp & list , Descriptor fd )
{ {
for( List::const_iterator p = list.begin() ; p != list.end() ; ++p ) const List::const_iterator end = list.end() ;
for( List::const_iterator p = list.begin() ; p != end ; ++p )
{ {
if( (*p).m_fd == fd ) if( (*p).m_fd == fd )
return true ; return true ;
@ -153,7 +154,8 @@ void GNet::EventHandlerList::remove( Descriptor fd )
GNet::EventHandler * GNet::EventHandlerList::find( Descriptor fd ) GNet::EventHandler * GNet::EventHandlerList::find( Descriptor fd )
{ {
for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p ) const List::iterator end = m_list.end() ;
for( List::iterator p = m_list.begin() ; p != end ; ++p )
{ {
if( (*p).m_fd == fd ) if( (*p).m_fd == fd )
return (*p).m_handler ; return (*p).m_handler ;
@ -162,30 +164,6 @@ GNet::EventHandler * GNet::EventHandlerList::find( Descriptor fd )
return NULL ; return NULL ;
} }
GNet::EventHandlerList::Iterator GNet::EventHandlerList::begin() const
{
return m_list.begin() ;
}
GNet::EventHandlerList::Iterator GNet::EventHandlerList::end() const
{
return m_list.end() ;
}
//static
GNet::Descriptor GNet::EventHandlerList::fd( Iterator i )
{
return (*i).m_fd ;
}
//static
GNet::EventHandler & GNet::EventHandlerList::handler( Iterator i )
{
EventHandler * p = (*i).m_handler ;
G_ASSERT( p != NULL ) ;
return *p ;
}
void GNet::EventHandlerList::lock() void GNet::EventHandlerList::lock()
{ {
m_lock++ ; m_lock++ ;

View File

@ -26,6 +26,7 @@
#include "gdef.h" #include "gdef.h"
#include "gnet.h" #include "gnet.h"
#include "gdatetime.h"
#include "gdescriptor.h" #include "gdescriptor.h"
#include <list> #include <list>
#include <string> #include <string>
@ -55,9 +56,20 @@ class GNet::EventHandler
{ {
public: public:
virtual ~EventHandler() ; virtual ~EventHandler() ;
virtual void readEvent() /*=0*/ ; // Destructor.
virtual void writeEvent() /*=0*/ ;
virtual void exceptionEvent() /*=0*/ ; virtual void readEvent() ;
// Called for a read event. The default
// implementation does nothing.
virtual void writeEvent() ;
// Called for a write event. The default
// implementation does nothing.
virtual void exceptionEvent() ;
// Called for an exception event. The default
// implementation does nothing.
private: private:
void operator=( const EventHandler & ) ; // not implemented void operator=( const EventHandler & ) ; // not implemented
} ; } ;
@ -80,9 +92,6 @@ private:
// //
class GNet::EventSources class GNet::EventSources
{ {
private:
static EventSources *m_this ;
protected: protected:
EventSources() ; EventSources() ;
// Constructor. // Constructor.
@ -139,6 +148,17 @@ public:
// Removes the given event source descriptor // Removes the given event source descriptor
// from the list of exception sources. // from the list of exception sources.
// See also Socket::dropExceptionHandler(). // See also Socket::dropExceptionHandler().
virtual void setTimeout( G::DateTime::EpochTime t ) = 0 ;
// Used by GNet::TimerList. Sets the time at which
// TimerList::doTimeouts() is to be called.
// A parameter of zero is used to cancel the
// timer. Some concrete implementations of this
// interface may use TimerList::interval()
// rather than setTimeout()/doTimeouts().
private:
static EventSources * m_this ;
} ; } ;
@ -152,10 +172,16 @@ public:
Descriptor m_fd ; Descriptor m_fd ;
EventHandler * m_handler ; EventHandler * m_handler ;
EventHandlerListItem( Descriptor fd = Descriptor__invalid() , EventHandlerListItem( Descriptor fd = Descriptor__invalid() ,
EventHandler * handler = NULL ) : EventHandler * handler = NULL ) ;
m_fd(fd) , m_handler(handler) {}
} ; } ;
inline
GNet::EventHandlerListItem::EventHandlerListItem( Descriptor fd , EventHandler * handler ) :
m_fd(fd) ,
m_handler(handler)
{
}
namespace GNet namespace GNet
{ {
typedef std::list< EventHandlerListItem GAllocator(EventHandlerListItem) > typedef std::list< EventHandlerListItem GAllocator(EventHandlerListItem) >
@ -164,7 +190,7 @@ namespace GNet
// Class: GNet::EventHandlerList // Class: GNet::EventHandlerList
// Description: A class which can be used in the implemention // Description: A class which can be used in the implemention
// of classes derived from GEventSources. // of classes derived from GNet::EventSources.
// //
class GNet::EventHandlerList class GNet::EventHandlerList
{ {
@ -231,6 +257,31 @@ private:
bool m_copied ; bool m_copied ;
} ; } ;
inline
GNet::EventHandlerList::Iterator GNet::EventHandlerList::begin() const
{
return m_list.begin() ;
}
inline
GNet::EventHandlerList::Iterator GNet::EventHandlerList::end() const
{
return m_list.end() ;
}
//static
inline
GNet::Descriptor GNet::EventHandlerList::fd( Iterator i )
{
return (*i).m_fd ;
}
//static
inline
GNet::EventHandler & GNet::EventHandlerList::handler( Iterator i )
{
return *((*i).m_handler) ;
}
#endif #endif

View File

@ -51,8 +51,8 @@ std::string GNet::Local::domainname()
if( pos == std::string::npos ) if( pos == std::string::npos )
throw Error( "invalid fqdn" ) ; throw Error( "invalid fqdn" ) ;
G_DEBUG( "GNet::Local::domainname: \"" << full.substr(0U,pos) << "\"" ) ; G_DEBUG( "GNet::Local::domainname: \"" << full.substr(pos+1U) << "\"" ) ;
return full.substr( 0U , pos ) ; return full.substr( pos+1U ) ;
} }
GNet::Address GNet::Local::canonicalAddress() GNet::Address GNet::Local::canonicalAddress()

View File

@ -43,6 +43,7 @@ std::string GNet::Local::domainname()
size_t pos = full.find( '.' ) ; size_t pos = full.find( '.' ) ;
if( pos == std::string::npos ) if( pos == std::string::npos )
throw Error( std::stringstream() << "invalid fqdn: no dots in \"" << full << "\"" ) ; throw Error( std::stringstream() << "invalid fqdn: no dots in \"" << full << "\"" ) ;
return full.substr(pos+1U) ; return full.substr(pos+1U) ;
} }
@ -85,6 +86,13 @@ std::string GNet::Local::fqdn()
throw Error( std::stringstream() << "resolve: " << rc.second ) ; throw Error( std::stringstream() << "resolve: " << rc.second ) ;
result = rc.first.canonical_name ; result = rc.first.canonical_name ;
size_t pos = result.find( '.' ) ;
if( pos == std::string::npos )
{
G_WARNING( "GNet::Local: no valid domain in \"" << result << "\": defaulting to \".local\"" ) ;
result.append( ".local" ) ;
}
} }
return result ; return result ;
} }

View File

@ -27,6 +27,9 @@
#include "gassert.h" #include "gassert.h"
#include <set> #include <set>
// Class: GNet::MontiorImp
// Description: A pimple pattern implementation class for GNet::Monitor.
//
class GNet::MonitorImp class GNet::MonitorImp
{ {
public: public:

View File

@ -160,6 +160,21 @@ GNet::Address GNet::HostRequest::result() const
} }
} }
std::string GNet::HostRequest::fqdn() const
{
G_ASSERT( m_done && m_handle == 0 ) ;
if( m_numeric )
{
return std::string() ;
}
else
{
const hostent *h = reinterpret_cast<const hostent*>(m_buffer) ;
G_ASSERT( h != NULL && h->h_name != NULL ) ;
return std::string( h->h_name ) ;
}
}
// SERVICE... // SERVICE...
GNet::ServiceRequest::ServiceRequest( std::string service_name , bool udp , HWND hwnd , unsigned msg ) : GNet::ServiceRequest::ServiceRequest( std::string service_name , bool udp , HWND hwnd , unsigned msg ) :

View File

@ -38,7 +38,8 @@ namespace GNet
// Class: GNet::Request // Class: GNet::Request
// Description: A base class for making // Description: A base class for making
// asynchronous DNS requests. // asynchronous DNS requests under Windows.
// See also: WSAAsyncGetHostByName()
// //
class GNet::Request class GNet::Request
{ {
@ -56,7 +57,9 @@ protected:
protected: protected:
explicit Request( bool host ) ; explicit Request( bool host ) ;
// Constructor. Derived class constructors // Constructor. Derived class constructors
// should issue the appropriate request. // should issue the appropriate WSAAsync..()
// request, with m_buffer[] given as the
// result buffer.
public: public:
virtual ~Request() ; virtual ~Request() ;
@ -90,7 +93,14 @@ class GNet::HostRequest : public GNet:: Request
{ {
public: public:
HostRequest( std::string host_name , HWND hwnd , unsigned msg ) ; HostRequest( std::string host_name , HWND hwnd , unsigned msg ) ;
Address result() const ; // zero port // Constructor.
Address result() const ;
// Returns the resolved address with a zero port number.
std::string fqdn() const ;
// Returns the fully-qualified canonical hostname, if
// available.
private: private:
bool numeric( std::string s , Address & address ) ; bool numeric( std::string s , Address & address ) ;
@ -104,8 +114,12 @@ private:
class GNet::ServiceRequest : public GNet:: Request class GNet::ServiceRequest : public GNet:: Request
{ {
public: public:
ServiceRequest( std::string service_name , bool udp , HWND hwnd , unsigned msg ) ; ServiceRequest( std::string service_name , bool udp ,
Address result() const ; // zero host address HWND hwnd , unsigned msg ) ;
// Constructor.
Address result() const ;
// Returns the address with a zeroed host part.
private: private:
static const char * protocol( bool udp ) ; static const char * protocol( bool udp ) ;

View File

@ -74,8 +74,8 @@ public:
// A zero-length host_name defaults to "0.0.0.0". A // A zero-length host_name defaults to "0.0.0.0". A
// zero-length service name defaults to "0". // zero-length service name defaults to "0".
virtual void resolveCon( bool success, const Address &address, virtual void resolveCon( bool success, const Address & address ,
std::string failure_reason ) ; std::string fqdn_or_failure_reason ) ;
// Called when the resolution process is complete. // Called when the resolution process is complete.
// This function is never called from within // This function is never called from within
// resolveReq(). // resolveReq().

View File

@ -59,9 +59,9 @@ private:
// === // ===
GNet::ResolverImp::ResolverImp( Resolver & resolver , unsigned int port ) : GNet::ResolverImp::ResolverImp( Resolver & resolver , unsigned int port ) :
m_s(NULL) , m_address(Address::localhost(port)) ,
m_outer(resolver) , m_outer(resolver) ,
m_address(Address::localhost(port)) m_s(NULL)
{ {
} }
@ -131,10 +131,14 @@ void GNet::ResolverImp::readEvent()
{ {
std::string result( buffer , rc ) ; std::string result( buffer , rc ) ;
G_DEBUG( "GNet::ResolverImp::readEvent: \"" << result << "\"" ) ; G_DEBUG( "GNet::ResolverImp::readEvent: \"" << result << "\"" ) ;
G::Str::trimRight( result , " \n" ) ; G::Str::trim( result , " \n" ) ;
if( Address::validString(result) ) size_t pos = result.find( ' ' ) ;
std::string head = pos == std::string::npos ? result : result.substr(0U,pos) ;
std::string tail = pos == std::string::npos ? std::string() : result.substr(pos+1U) ;
if( Address::validString(head) )
{ {
m_outer.resolveCon( true , Address(result) , "" ) ; G::Str::trim( tail , " \n" ) ;
m_outer.resolveCon( true , Address(result) , tail ) ;
} }
else else
{ {

View File

@ -45,6 +45,7 @@ private:
bool m_udp ; bool m_udp ;
Address m_result ; Address m_result ;
std::string m_fqdn ;
public: public:
explicit ResolverImp( Resolver & resolver ) ; explicit ResolverImp( Resolver & resolver ) ;
@ -59,11 +60,9 @@ private:
ResolverImp( const ResolverImp & ) ; ResolverImp( const ResolverImp & ) ;
const char *errorString( bool host_error , int error ) ; const char *errorString( bool host_error , int error ) ;
void cleanup() ; void cleanup() ;
void saveHost( const Address &address ) ; void saveHost( const Address &address , const std::string & fqdn ) ;
void saveService( const Address &address ) ; void saveService( const Address &address ) ;
virtual LRESULT onUser( WPARAM wparam , LPARAM lparam ) ;
protected:
LRESULT onUser( WPARAM wparam , LPARAM lparam ) ;
} ; } ;
// === // ===
@ -97,7 +96,7 @@ bool GNet::ResolverImp::resolveReq( std::string host_part, std::string service_p
m_service = service_part ; m_service = service_part ;
m_udp = udp ; m_udp = udp ;
m_host_request = new HostRequest( host_part , handle() , WM_USER ) ; m_host_request = new HostRequest( host_part , handle() , Cracker::wm_user() ) ;
if( !m_host_request->valid() ) if( !m_host_request->valid() )
{ {
std::string reason = m_host_request->reason() ; // not used std::string reason = m_host_request->reason() ; // not used
@ -129,9 +128,10 @@ bool GNet::ResolverImp::busy() const
m_host_request != NULL ; m_host_request != NULL ;
} }
void GNet::ResolverImp::saveHost( const Address & address ) void GNet::ResolverImp::saveHost( const Address & address , const std::string & fqdn )
{ {
m_result = address ; m_result = address ;
m_fqdn = fqdn ;
} }
void GNet::ResolverImp::saveService( const Address & address ) void GNet::ResolverImp::saveService( const Address & address )
@ -148,10 +148,10 @@ LRESULT GNet::ResolverImp::onUser( WPARAM wparam , LPARAM lparam )
{ {
if( m_host_request->onMessage( wparam , lparam ) ) if( m_host_request->onMessage( wparam , lparam ) )
{ {
saveHost( m_host_request->result() ) ; saveHost( m_host_request->result() , m_host_request->fqdn() ) ;
cleanup() ; cleanup() ;
m_service_request = new ServiceRequest( m_service , m_udp , handle() , WM_USER ) ; m_service_request = new ServiceRequest( m_service , m_udp , handle() , Cracker::wm_user() ) ;
if( !m_service_request->valid() ) if( !m_service_request->valid() )
{ {
std::string reason = m_service_request->reason() ; std::string reason = m_service_request->reason() ;
@ -173,7 +173,7 @@ LRESULT GNet::ResolverImp::onUser( WPARAM wparam , LPARAM lparam )
saveService( m_service_request->result() ) ; saveService( m_service_request->result() ) ;
Address address( m_result ) ; Address address( m_result ) ;
cleanup() ; cleanup() ;
m_if.resolveCon( true , address , std::string() ) ; // success m_if.resolveCon( true , address , m_fqdn ) ; // success
} }
else else
{ {

View File

@ -23,10 +23,14 @@
#include "gdef.h" #include "gdef.h"
#include "gselect.h" #include "gselect.h"
#include "gstr.h"
#include "gtimer.h"
#include "gdebug.h" #include "gdebug.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
typedef struct timeval Timeval ; // std:: ??
namespace GNet namespace GNet
{ {
class Lock ; class Lock ;
@ -83,7 +87,8 @@ GNet::Lock::~Lock()
int GNet::FdSet::init( int n , fd_set * set , const EventHandlerList & list ) int GNet::FdSet::init( int n , fd_set * set , const EventHandlerList & list )
{ {
FD_ZERO( set ) ; FD_ZERO( set ) ;
for( EventHandlerList::Iterator p = list.begin() ; p != list.end() ; ++p ) const EventHandlerList::Iterator end = list.end() ;
for( EventHandlerList::Iterator p = list.begin() ; p != end ; ++p )
{ {
Descriptor fd = EventHandlerList::fd( p ) ; Descriptor fd = EventHandlerList::fd( p ) ;
FD_SET( fd , set ) ; FD_SET( fd , set ) ;
@ -95,15 +100,16 @@ int GNet::FdSet::init( int n , fd_set * set , const EventHandlerList & list )
//static //static
void GNet::FdSet::raiseEvents( fd_set * set , EventHandlerList & list , void GNet::FdSet::raiseEvents( fd_set * set , EventHandlerList & list ,
void (EventHandler::*method)() , const char * type ) void (EventHandler::*method)() , const char * /*type*/ )
{ {
GNet::Lock lock( list ) ; GNet::Lock lock( list ) ; // since event handlers may change the list while we iterate
for( EventHandlerList::Iterator p = list.begin() ; p != list.end() ; ++p ) const EventHandlerList::Iterator end = list.end() ;
for( EventHandlerList::Iterator p = list.begin() ; p != end ; ++p )
{ {
Descriptor fd = EventHandlerList::fd( p ) ; Descriptor fd = EventHandlerList::fd( p ) ;
if( FD_ISSET( fd , set ) ) if( FD_ISSET( fd , set ) )
{ {
G_DEBUG( "raiseEvents: " << type << " event on fd " << fd ) ; //G_DEBUG( "raiseEvents: " << type << " event on fd " << fd ) ;
EventHandler & h = EventHandlerList::handler( p ) ; EventHandler & h = EventHandlerList::handler( p ) ;
(h.*method)() ; (h.*method)() ;
} }
@ -113,10 +119,10 @@ void GNet::FdSet::raiseEvents( fd_set * set , EventHandlerList & list ,
// === // ===
GNet::Select::Select() : GNet::Select::Select() :
m_quit(false) ,
m_read_list(std::string("read")) , m_read_list(std::string("read")) ,
m_write_list(std::string("write")) , m_write_list(std::string("write")) ,
m_exception_list(std::string("exception")) , m_exception_list(std::string("exception"))
m_quit(false)
{ {
} }
@ -150,22 +156,40 @@ void GNet::Select::runOnce()
fd_set w ; n = FdSet::init( n , &w , m_write_list ) ; fd_set w ; n = FdSet::init( n , &w , m_write_list ) ;
fd_set e ; n = FdSet::init( n , &e , m_exception_list ) ; fd_set e ; n = FdSet::init( n , &e , m_exception_list ) ;
struct timeval * const infinite = NULL ; Timeval timeout ;
Timeval * timeout_p = NULL ;
if( TimerList::instance(TimerList::NoThrow()) != NULL )
{
bool infinite = false ;
timeout.tv_sec = TimerList::instance().interval( infinite ) ;
timeout.tv_usec = 0 ; // micro seconds
timeout_p = infinite ? NULL : &timeout ;
}
G_DEBUG( "GNet::Select::runOnce: selecting: fd(max) = " << (n-1) << ": " const bool debug = false ;
<< "read-list=\"" << m_read_list.asString() << "\": " if( debug )
<< "write-list=\"" << m_write_list.asString() << "\": " {
<< "exception-list=\"" << m_exception_list.asString() << "\"" ) ; G_DEBUG( "GNet::Select::runOnce: selecting: fd(max) = " << (n-1) << ": "
<< "read-list=\"" << m_read_list.asString() << "\": "
<< "write-list=\"" << m_write_list.asString() << "\": "
<< "exception-list=\"" << m_exception_list.asString() << "\": "
<< "timeout=" << (timeout_p?G::Str::fromUInt(timeout_p->tv_sec):std::string("infinite")) ) ;
}
int rc = ::select( n , &r , &w , &e , infinite ) ; int rc = ::select( n , &r , &w , &e , timeout_p ) ;
if( rc > 0 ) if( rc == 0 )
{
G_DEBUG( "GNet::Select::runOnce: select() timeout" ) ;
TimerList::instance().doTimeouts() ;
}
else if( rc > 0 )
{ {
G_DEBUG( "GNet::Select::runOnce: detected event(s) on " << rc << " fd(s)" ) ; G_DEBUG( "GNet::Select::runOnce: detected event(s) on " << rc << " fd(s)" ) ;
FdSet::raiseEvents( &r , m_read_list , & EventHandler::readEvent , "read" ) ; FdSet::raiseEvents( &r , m_read_list , & EventHandler::readEvent , "read" ) ;
FdSet::raiseEvents( &w , m_write_list , & EventHandler::writeEvent , "write" ) ; FdSet::raiseEvents( &w , m_write_list , & EventHandler::writeEvent , "write" ) ;
FdSet::raiseEvents( &e , m_exception_list , & EventHandler::exceptionEvent , "exception" ) ; FdSet::raiseEvents( &e , m_exception_list , & EventHandler::exceptionEvent , "exception" ) ;
} }
else if( rc < 0 ) else
{ {
throw Error() ; throw Error() ;
} }
@ -201,3 +225,8 @@ void GNet::Select::dropException( Descriptor fd )
m_exception_list.remove( fd ) ; m_exception_list.remove( fd ) ;
} }
void GNet::Select::setTimeout( G::DateTime::EpochTime )
{
// not used -- interval() in runOnce() suffices
}

View File

@ -79,6 +79,7 @@ private:
Select( const Select & ) ; Select( const Select & ) ;
void operator=( const Select & ) ; void operator=( const Select & ) ;
void runOnce() ; void runOnce() ;
virtual void setTimeout( G::DateTime::EpochTime t ) ;
private: private:
bool m_quit ; bool m_quit ;

View File

@ -27,11 +27,12 @@
#include "gmonitor.h" #include "gmonitor.h"
#include "gdebug.h" #include "gdebug.h"
#include "gassert.h" #include "gassert.h"
#include "gmemory.h"
GNet::ServerPeer::ServerPeer( StreamSocket * s , Address a ) : GNet::ServerPeer::ServerPeer( StreamSocket * s , Address a ) :
m_socket(s) , m_ref_count(1U) ,
m_address(a) , m_address(a) ,
m_ref_count(1U) m_socket(s)
{ {
G_ASSERT( m_socket != NULL ) ; G_ASSERT( m_socket != NULL ) ;
G_DEBUG( "GNet::ServerPeer::ctor: fd " << m_socket->asString() << ": " << m_address.displayString() ) ; G_DEBUG( "GNet::ServerPeer::ctor: fd " << m_socket->asString() << ": " << m_address.displayString() ) ;
@ -121,32 +122,31 @@ std::pair<bool,GNet::Address> GNet::ServerPeer::peerAddress() const
// === // ===
GNet::Server::Server( unsigned int listening_port ) : GNet::Server::Server( unsigned int listening_port )
m_socket(NULL)
{ {
try init( listening_port ) ;
{
init( listening_port ) ;
}
catch(...)
{
delete m_socket ;
throw ;
}
} }
GNet::Server::Server() : GNet::Server::Server( const Address & listening_address )
m_socket(NULL) {
init( listening_address ) ;
}
GNet::Server::Server()
{ {
} }
void GNet::Server::init( unsigned int listening_port ) void GNet::Server::init( unsigned int listening_port )
{ {
m_socket = new StreamSocket ; init( Address(listening_port) ) ;
G_DEBUG( "GNet::Server::init: " << (void*)this << ": listening on port " << listening_port ) ; }
Address local_address( listening_port ) ;
if( ! m_socket->bind( local_address ) ) void GNet::Server::init( const Address & listening_address )
throw CannotBind( local_address.displayString() ) ; {
m_socket <<= new StreamSocket ;
G_DEBUG( "GNet::Server::init: listening on " << listening_address.displayString() ) ;
if( ! m_socket->bind( listening_address ) )
throw CannotBind( listening_address.displayString() ) ;
if( ! m_socket->listen() ) if( ! m_socket->listen() )
throw CannotListen() ; throw CannotListen() ;
m_socket->addReadHandler( *this ) ; m_socket->addReadHandler( *this ) ;
@ -154,7 +154,6 @@ void GNet::Server::init( unsigned int listening_port )
GNet::Server::~Server() GNet::Server::~Server()
{ {
delete m_socket ;
} }
void GNet::Server::readEvent() void GNet::Server::readEvent()
@ -162,7 +161,7 @@ void GNet::Server::readEvent()
// read-event-on-listening-port => new connection to accept // read-event-on-listening-port => new connection to accept
G_DEBUG( "GNet::Server::readEvent: " << (void*)this ) ; G_DEBUG( "GNet::Server::readEvent: " << (void*)this ) ;
G_ASSERT( m_socket != NULL ) ; G_ASSERT( m_socket.get() != NULL ) ;
AcceptPair pair = m_socket->accept() ; AcceptPair pair = m_socket->accept() ;
if( pair.first.get() == NULL ) if( pair.first.get() == NULL )
{ {

View File

@ -31,6 +31,7 @@
#include "gselect.h" #include "gselect.h"
#include "gevent.h" #include "gevent.h"
#include <list> #include <list>
#include <memory>
#include <string> #include <string>
namespace GNet namespace GNet
@ -52,8 +53,12 @@ public:
G_EXCEPTION( CannotListen , "cannot listen" ) ; G_EXCEPTION( CannotListen , "cannot listen" ) ;
explicit Server( unsigned int listening_port ) ; explicit Server( unsigned int listening_port ) ;
// Constructor. Throws exceptions on // Constructor taking a port number. The server
// error. // listens on all local interfaces.
explicit Server( const Address & listening_address ) ;
// Constructor. The server listens only on the
// specific (local) interface.
Server() ; Server() ;
// Default constructor. Initialise with init(). // Default constructor. Initialise with init().
@ -61,6 +66,9 @@ public:
void init( unsigned int listening_port ) ; void init( unsigned int listening_port ) ;
// Iniailisation after default construction. // Iniailisation after default construction.
void init( const Address & listening_address ) ;
// Iniailisation after default construction.
virtual ~Server() ; virtual ~Server() ;
// Destructor. // Destructor.
@ -90,7 +98,7 @@ private:
virtual void exceptionEvent() ; // from EventHandler virtual void exceptionEvent() ; // from EventHandler
private: private:
StreamSocket * m_socket ; std::auto_ptr<StreamSocket> m_socket ;
} ; } ;
// Class: GNet::ServerPeer // Class: GNet::ServerPeer

View File

@ -57,8 +57,8 @@ bool GNet::Socket::open( int domain, int type, int protocol )
} }
GNet::Socket::Socket( Descriptor s ) : GNet::Socket::Socket( Descriptor s ) :
m_socket(s) , m_reason(0) ,
m_reason( 0 ) m_socket(s)
{ {
; ;
} }
@ -168,7 +168,7 @@ ssize_t GNet::Socket::write( const char *buf, size_t len )
G_DEBUG( "GNet::Socket::write: write error " << m_reason ) ; G_DEBUG( "GNet::Socket::write: write error " << m_reason ) ;
return -1 ; return -1 ;
} }
else if( nsent < len ) else if( nsent < 0 || static_cast<size_t>(nsent) < len )
{ {
m_reason = reason() ; m_reason = reason() ;
} }
@ -183,7 +183,7 @@ void GNet::Socket::setNoLinger()
options.l_onoff = 0 ; options.l_onoff = 0 ;
options.l_linger = 0 ; options.l_linger = 0 ;
socklen_t sizeof_options = sizeof(options) ; socklen_t sizeof_options = sizeof(options) ;
(void)setsockopt( m_socket , SOL_SOCKET , SO_LINGER , (void)::setsockopt( m_socket , SOL_SOCKET , SO_LINGER ,
(char*)&options , sizeof_options ) ; (char*)&options , sizeof_options ) ;
} }

230
src/gnet/gtimer.cpp Normal file
View File

@ -0,0 +1,230 @@
//
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ===
//
// gtimer.cpp
//
#include "gdef.h"
#include "gtimer.h"
#include "gevent.h"
#include "gdebug.h"
namespace GNet
{
class TimerUpdate ;
} ;
// Class: GNet::TimerUpdate
// Description: A private implementation class used by GNet::Timer.
//
class GNet::TimerUpdate
{
public:
TimerUpdate( Timer & , const std::string & ) ;
~TimerUpdate() ;
private:
TimerUpdate( const TimerUpdate & ) ; // not implemented
void operator=( const TimerUpdate & ) ; // not implemented
private:
Timer & m_timer ;
std::string m_type ;
G::DateTime::EpochTime m_soonest ;
} ;
// ===
GNet::TimeoutHandler::~TimeoutHandler()
{
}
// ===
GNet::Timer::Timer( TimeoutHandler & handler ) :
m_time(0UL) ,
m_handler(&handler)
{
TimerUpdate update( *this , "ctor" ) ;
TimerList::instance().add( *this ) ;
}
GNet::Timer::Timer() :
m_time(0UL) ,
m_handler(NULL)
{
TimerUpdate update( *this , "ctor" ) ;
TimerList::instance().add( *this ) ;
}
GNet::Timer::~Timer()
{
try
{
TimerUpdate update( *this , "dtor" ) ;
TimerList::instance().remove( *this ) ;
}
catch(...)
{
}
}
void GNet::Timer::startTimer( unsigned int time )
{
TimerUpdate update( *this , "start" ) ;
m_time = G::DateTime::now() + time ;
}
void GNet::Timer::cancelTimer()
{
TimerUpdate update( *this , "cancel" ) ;
m_time = 0U ;
}
void GNet::Timer::doTimeout()
{
if( m_time != 0U )
{
m_time = 0U ;
G_DEBUG( "GNet::Timer::doTimeout" ) ;
onTimeout() ;
if( m_handler != NULL )
m_handler->onTimeout(*this) ;
}
}
void GNet::Timer::onTimeout()
{
// no-op
}
G::DateTime::EpochTime GNet::Timer::t() const
{
return m_time ;
}
// ===
GNet::TimerList * GNet::TimerList::m_this = NULL ;
GNet::TimerList::TimerList()
{
if( m_this == NULL )
m_this = this ;
}
GNet::TimerList::~TimerList()
{
if( m_this == this )
m_this = NULL ;
}
void GNet::TimerList::add( Timer & t )
{
m_set.insert( &t ) ;
}
void GNet::TimerList::remove( Timer & t )
{
m_set.erase( &t ) ;
}
void GNet::TimerList::update( G::DateTime::EpochTime t_old ,
const std::string & op )
{
G::DateTime::EpochTime t_new = soonest() ;
G_DEBUG( "GNet::TimerList::update: " << op << ": " << t_old << " -> " << t_new ) ;
(void) op.length() ; // pacify the compiler
if( t_old != t_new )
{
EventSources::instance().setTimeout( t_new ) ;
}
}
G::DateTime::EpochTime GNet::TimerList::soonest() const
{
G::DateTime::EpochTime result = 0U ;
const Set::const_iterator end = m_set.end() ;
for( Set::const_iterator p = m_set.begin() ; p != end ; ++p )
{
if( (*p)->t() != 0UL && ( result == 0U || (*p)->t() < result ) )
result = (*p)->t() ;
}
return result ;
}
unsigned int GNet::TimerList::interval( bool & infinite ) const
{
G::DateTime::EpochTime then = soonest() ;
infinite = then == 0U ;
if( infinite )
{
return 0U ;
}
else
{
G::DateTime::EpochTime now = G::DateTime::now() ;
return now >= then ? 0U : (then-now) ;
}
}
GNet::TimerList * GNet::TimerList::instance( const NoThrow & )
{
return m_this ;
}
GNet::TimerList & GNet::TimerList::instance()
{
if( m_this == NULL )
throw NoInstance() ;
return * m_this ;
}
void GNet::TimerList::doTimeouts()
{
G_DEBUG( "GNet::TimerList::doTimeouts" ) ;
G::DateTime::EpochTime now = G::DateTime::now() ;
for( Set::iterator p = m_set.begin() ; p != m_set.end() ; ++p )
{
if( now >= (*p)->t() )
(*p)->doTimeout() ;
}
EventSources::instance().setTimeout( soonest() ) ;
}
// ===
GNet::TimerUpdate::TimerUpdate( Timer & timer , const std::string & type ) :
m_timer(timer) ,
m_type(type)
{
m_soonest = TimerList::instance().soonest() ;
}
GNet::TimerUpdate::~TimerUpdate()
{
try
{
TimerList::instance().update( m_soonest , m_type ) ;
}
catch(...)
{
}
}

156
src/gnet/gtimer.h Normal file
View File

@ -0,0 +1,156 @@
//
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ===
//
// gtimer.h
//
#ifndef G_NET_TIMER_H
#define G_NET_TIMER_H
#include "gdef.h"
#include "gnet.h"
#include "gdatetime.h"
#include "gexception.h"
#include <set>
namespace GNet
{
class Timer ;
class TimeoutHandler ;
class TimerList ;
} ;
// Class: GNet::TimeoutHandler
// Description: An interface used by GNet::Timer.
//
class GNet::TimeoutHandler
{
public:
virtual ~TimeoutHandler() ;
// Destructor.
virtual void onTimeout( Timer & ) = 0 ;
// Called when the associated timer
// expires.
private:
void operator=( const TimeoutHandler & ) ; // not implemented
} ;
// Class: GNet::Timer
// Description: A timer class.
//
class GNet::Timer
{
public:
explicit Timer( TimeoutHandler & handler ) ;
// Constructor.
Timer() ;
// Default constructor.
virtual ~Timer() ;
// Destructor.
void startTimer( unsigned int time ) ;
// Starts the timer.
void cancelTimer() ;
// Cancels the timer.
protected:
virtual void onTimeout() ;
// Called when the timer expires (or soon
// after).
private:
Timer( const Timer & ) ; // not implemented
void operator=( const Timer & ) ; // not implemented
private:
friend class TimerList ;
void doTimeout() ; // called by friendly TimerList
G::DateTime::EpochTime t() const ; // called by friendly TimerList
private:
G::DateTime::EpochTime m_time ;
TimeoutHandler * m_handler ;
} ;
// Class: GNet::TimerList
// Description: A singleton which maintains a list of all Timer
// objects, and interfaces to the event loop on their behalf.
//
class GNet::TimerList
{
public:
G_EXCEPTION( NoInstance , "no TimerList instance" ) ;
class NoThrow // Overload discriminator class for TimerList.
{} ;
TimerList() ;
// Default constructor.
~TimerList() ;
// Destructor.
void add( Timer & ) ;
// Adds a timer. Used by Timer::Timer().
void remove( Timer & ) ;
// Removes a timer from the list.
// Used by Timer::~Timer().
void update( G::DateTime::EpochTime previous_soonest ,
const std::string & why ) ;
// Called when one of the list's timers
// has changed.
G::DateTime::EpochTime soonest() const ;
// Returns the time of the first timer to expire,
// or zero if none.
unsigned int interval( bool & infinite ) const ;
// Returns the interval to the next
// timer expiry. The 'infinite' value is
// set to true if there are no timers
// running.
void doTimeouts() ;
// Triggers the timeout callbacks of any expired
// timers. Called by the event loop (GNet::EventSources).
static TimerList * instance( const NoThrow & ) ;
// Singleton access. Returns NULL if none.
static TimerList & instance() ;
// Singleton access. Throws an exception if none.
private:
TimerList( const TimerList & ) ; // not implemented
void operator=( const TimerList & ) ; // not implemented
private:
static TimerList * m_this ;
typedef std::set<Timer* GLessAllocator(Timer*,Timer*) > Set ;
Set m_set ;
} ;
#endif

View File

@ -27,6 +27,8 @@
#include "gappinst.h" #include "gappinst.h"
#include "gwinhid.h" #include "gwinhid.h"
#include "gwinsock.h" #include "gwinsock.h"
#include "gexception.h"
#include "gtimer.h"
#include "gassert.h" #include "gassert.h"
#include "gdebug.h" #include "gdebug.h"
#include "glog.h" #include "glog.h"
@ -45,7 +47,8 @@ class GNet::WinsockWindow : public GGui::WindowHidden
public: public:
WinsockWindow( Winsock & ws , HINSTANCE h ) ; WinsockWindow( Winsock & ws , HINSTANCE h ) ;
private: private:
virtual LRESULT onUser( WPARAM , LPARAM ) ; virtual void onWinsock( WPARAM , LPARAM ) ;
virtual void onTimer( unsigned int ) ;
Winsock & m_ws ; Winsock & m_ws ;
} ; } ;
@ -55,11 +58,15 @@ GNet::WinsockWindow::WinsockWindow( Winsock & ws , HINSTANCE hinstance ) :
{ {
} }
// (wm_winsock is WM_USER -- should be called onWinsock()) void GNet::WinsockWindow::onWinsock( WPARAM w , LPARAM l )
LRESULT GNet::WinsockWindow::onUser( WPARAM w , LPARAM l )
{ {
m_ws.onMessage( w , l ) ; m_ws.onMessage( w , l ) ;
return 0 ; }
void GNet::WinsockWindow::onTimer( unsigned int timer_id )
{
G_DEBUG( "GNet::WinsockWindow::onTimer: " << timer_id ) ;
m_ws.onTimer() ;
} }
// === // ===
@ -71,7 +78,8 @@ GNet::Winsock::Winsock() :
m_exception_list("exception") , m_exception_list("exception") ,
m_success(false) , m_success(false) ,
m_hwnd(0) , m_hwnd(0) ,
m_msg(0) m_msg(0) ,
m_timer_id(1U)
{ {
} }
@ -95,13 +103,14 @@ bool GNet::Winsock::init()
G_WARNING( "GNet::Winsock::init: cannot create hidden window" ) ; G_WARNING( "GNet::Winsock::init: cannot create hidden window" ) ;
return false ; return false ;
} }
return attach( m_window->handle() , GGui::Cracker::wm_winsock() ) ; return attach( m_window->handle() , GGui::Cracker::wm_winsock() , 1U ) ;
} }
bool GNet::Winsock::attach( HWND hwnd , unsigned msg ) bool GNet::Winsock::attach( HWND hwnd , unsigned msg , unsigned int timer_id )
{ {
m_hwnd = hwnd ; m_hwnd = hwnd ;
m_msg = msg ; m_msg = msg ;
m_timer_id = timer_id ;
WSADATA info ; WSADATA info ;
WORD version = MAKEWORD( 1 , 1 ) ; WORD version = MAKEWORD( 1 , 1 ) ;
@ -248,6 +257,36 @@ void GNet::Winsock::onMessage( WPARAM wparam , LPARAM lparam )
} }
} }
void GNet::Winsock::onTimer()
{
G_DEBUG( "GNet::Winsock::onTimer" ) ;
::KillTimer( m_hwnd , m_timer_id ) ; // since periodic
TimerList::instance().doTimeouts() ;
}
void GNet::Winsock::setTimeout( G::DateTime::EpochTime t )
{
G_DEBUG( "GNet::Winsock::setTimeout: " << t ) ;
if( t != 0U )
{
G::DateTime::EpochTime now = G::DateTime::now() ;
unsigned int interval = t > now ? (t - now) : 0U ;
unsigned long ms = interval ;
ms *= 1000UL ;
G_DEBUG( "GNet::Winsock::setTimeout: SetTimer(): " << ms << "ms" ) ;
::KillTimer( m_hwnd , m_timer_id ) ;
unsigned int rc = ::SetTimer( m_hwnd , m_timer_id , ms , NULL ) ;
if( rc == 0U )
throw G::Exception( "GNet::Winsock: SetTimer() failure" ) ;
G_ASSERT( rc == m_timer_id ) ;
}
else
{
G_DEBUG( "GNet::Winsock::setTimeout: KillTimer()" ) ;
::KillTimer( m_hwnd , m_timer_id ) ;
}
}
void GNet::Winsock::run() void GNet::Winsock::run()
{ {
GGui::Pump::run() ; GGui::Pump::run() ;

View File

@ -59,8 +59,11 @@ public:
// WinSock library, passing it the handle // WinSock library, passing it the handle
// of an internally-created hidden window. // of an internally-created hidden window.
// Returns false on error. // Returns false on error.
//
// Use either init() for an internally-created
// window, or attach().
bool attach( HWND hwnd , unsigned int msg ) ; bool attach( HWND hwnd , unsigned int msg , unsigned int timer_id = 0U ) ;
// Initialises the WinSock library, passing // Initialises the WinSock library, passing
// it the specified window handle and // it the specified window handle and
// message number. WinSock events are sent // message number. WinSock events are sent
@ -68,6 +71,10 @@ public:
// //
// For simple, synchronous programs // For simple, synchronous programs
// the window handle may be zero. // the window handle may be zero.
//
// Use either init() or attach().
//
// See also onMessage() and onTimer().
std::string reason() const ; std::string reason() const ;
// Returns the reason for initialisation // Returns the reason for initialisation
@ -83,9 +90,13 @@ public:
// if this is the last Winsock object. // if this is the last Winsock object.
void onMessage( WPARAM wparam , LPARAM lparam ) ; void onMessage( WPARAM wparam , LPARAM lparam ) ;
// To be called on receipt of a window // To be called when the attach()ed window
// message corresponding to the constructor's // receives a message with a message-id
// 'msg' parameter. // equal to attach() 'msg' parameter.
void onTimer() ;
// To be called when the attach()ed window
// receives a WM_TIMER message.
virtual void run() ; virtual void run() ;
// Override from EventSources. Calls GGui::Pump::run(). // Override from EventSources. Calls GGui::Pump::run().
@ -100,6 +111,7 @@ protected:
virtual void dropRead( Descriptor fd ) ; virtual void dropRead( Descriptor fd ) ;
virtual void dropWrite( Descriptor fd ) ; virtual void dropWrite( Descriptor fd ) ;
virtual void dropException( Descriptor fd ) ; virtual void dropException( Descriptor fd ) ;
virtual void setTimeout( G::DateTime::EpochTime ) ;
private: private:
Winsock( const Winsock & other ) ; Winsock( const Winsock & other ) ;
@ -119,6 +131,7 @@ private:
EventHandlerList m_read_list ; EventHandlerList m_read_list ;
EventHandlerList m_write_list ; EventHandlerList m_write_list ;
EventHandlerList m_exception_list ; EventHandlerList m_exception_list ;
unsigned int m_timer_id ;
} ; } ;
#endif #endif

View File

@ -24,7 +24,7 @@ AM_INSTALL_PROGRAM_FLAGS=-s
# change the local-state directory from .../var to .../var/spool/emailrelay # change the local-state directory from .../var to .../var/spool/emailrelay
localstatedir = ${prefix}/var/spool/emailrelay localstatedir = ${prefix}/var/spool/emailrelay
EXTRA_DIST=commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico icon2.ico icon3.ico empty_file doxygen.cfg emailrelay.rc resource.h EXTRA_DIST=commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico icon2.ico icon3.ico icon4.ico empty_file doxygen.cfg emailrelay.rc resource.h gsasl_cyrus.cpp
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib -I$(top_srcdir)/src/gnet INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib -I$(top_srcdir)/src/gnet
sbin_PROGRAMS = emailrelay sbin_PROGRAMS = emailrelay
libexec_PROGRAMS = emailrelay-poke libexec_PROGRAMS = emailrelay-poke
@ -32,6 +32,8 @@ localstate_DATA = empty_file
emailrelay_SOURCES = \ emailrelay_SOURCES = \
gadminserver.cpp \ gadminserver.cpp \
gadminserver.h \ gadminserver.h \
gbase64.cpp \
gbase64.h \
gclientprotocol.cpp \ gclientprotocol.cpp \
gclientprotocol.h \ gclientprotocol.h \
gfilestore.cpp \ gfilestore.cpp \
@ -49,6 +51,10 @@ emailrelay_SOURCES = \
gprotocolmessageforward.h \ gprotocolmessageforward.h \
gprotocolmessagestore.cpp \ gprotocolmessagestore.cpp \
gprotocolmessagestore.h \ gprotocolmessagestore.h \
gsasl_login.cpp \
gsasl.h \
gsecrets.cpp \
gsecrets.h \
gserverprotocol.cpp \ gserverprotocol.cpp \
gserverprotocol.h \ gserverprotocol.h \
gsmtp.h \ gsmtp.h \
@ -62,6 +68,8 @@ emailrelay_SOURCES = \
gstoredmessage.h \ gstoredmessage.h \
gverifier.cpp \ gverifier.cpp \
gverifier.h \ gverifier.h \
gxtext.cpp \
gxtext.h \
main_unix.cpp \ main_unix.cpp \
configuration.cpp \ configuration.cpp \
configuration.h \ configuration.h \

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am # Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -95,12 +95,12 @@ AM_INSTALL_PROGRAM_FLAGS = -s
# change the local-state directory from .../var to .../var/spool/emailrelay # change the local-state directory from .../var to .../var/spool/emailrelay
localstatedir = ${prefix}/var/spool/emailrelay localstatedir = ${prefix}/var/spool/emailrelay
EXTRA_DIST = commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico icon2.ico icon3.ico empty_file doxygen.cfg emailrelay.rc resource.h EXTRA_DIST = commandline_win32.cpp main_win32.cpp gmessagestore_win32.cpp emailrelay.dsp icon-32.ico icon2.ico icon3.ico icon4.ico empty_file doxygen.cfg emailrelay.rc resource.h gsasl_cyrus.cpp
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib -I$(top_srcdir)/src/gnet INCLUDES = -I$(top_srcdir)/lib/gcc2.95 -I$(top_srcdir)/src/glib -I$(top_srcdir)/src/gnet
sbin_PROGRAMS = emailrelay sbin_PROGRAMS = emailrelay
libexec_PROGRAMS = emailrelay-poke libexec_PROGRAMS = emailrelay-poke
localstate_DATA = empty_file localstate_DATA = empty_file
emailrelay_SOURCES = gadminserver.cpp gadminserver.h gclientprotocol.cpp gclientprotocol.h gfilestore.cpp gfilestore.h gmessagestore.cpp gmessagestore.h gmessagestore_unix.cpp gnewfile.cpp gnewfile.h gnewmessage.cpp gnewmessage.h gprotocolmessage.cpp gprotocolmessage.h gprotocolmessageforward.cpp gprotocolmessageforward.h gprotocolmessagestore.cpp gprotocolmessagestore.h gserverprotocol.cpp gserverprotocol.h gsmtp.h gsmtpclient.cpp gsmtpclient.h gsmtpserver.cpp gsmtpserver.h gstoredfile.cpp gstoredfile.h gstoredmessage.cpp gstoredmessage.h gverifier.cpp gverifier.h main_unix.cpp configuration.cpp configuration.h run.cpp run.h commandline.cpp commandline_unix.cpp commandline.h emailrelay_SOURCES = gadminserver.cpp gadminserver.h gbase64.cpp gbase64.h gclientprotocol.cpp gclientprotocol.h gfilestore.cpp gfilestore.h gmessagestore.cpp gmessagestore.h gmessagestore_unix.cpp gnewfile.cpp gnewfile.h gnewmessage.cpp gnewmessage.h gprotocolmessage.cpp gprotocolmessage.h gprotocolmessageforward.cpp gprotocolmessageforward.h gprotocolmessagestore.cpp gprotocolmessagestore.h gsasl_login.cpp gsasl.h gsecrets.cpp gsecrets.h gserverprotocol.cpp gserverprotocol.h gsmtp.h gsmtpclient.cpp gsmtpclient.h gsmtpserver.cpp gsmtpserver.h gstoredfile.cpp gstoredfile.h gstoredmessage.cpp gstoredmessage.h gverifier.cpp gverifier.h gxtext.cpp gxtext.h main_unix.cpp configuration.cpp configuration.h run.cpp run.h commandline.cpp commandline_unix.cpp commandline.h
emailrelay_poke_SOURCES = poke.c emailrelay_poke_SOURCES = poke.c
emailrelay_LDADD = $(top_builddir)/src/glib/libglib.a $(top_builddir)/src/gnet/libgnet.a emailrelay_LDADD = $(top_builddir)/src/glib/libglib.a $(top_builddir)/src/gnet/libgnet.a
@ -118,12 +118,13 @@ emailrelay_poke_OBJECTS = poke.o
emailrelay_poke_LDADD = $(LDADD) emailrelay_poke_LDADD = $(LDADD)
emailrelay_poke_DEPENDENCIES = emailrelay_poke_DEPENDENCIES =
emailrelay_poke_LDFLAGS = emailrelay_poke_LDFLAGS =
emailrelay_OBJECTS = gadminserver.o gclientprotocol.o gfilestore.o \ emailrelay_OBJECTS = gadminserver.o gbase64.o gclientprotocol.o \
gmessagestore.o gmessagestore_unix.o gnewfile.o gnewmessage.o \ gfilestore.o gmessagestore.o gmessagestore_unix.o gnewfile.o \
gprotocolmessage.o gprotocolmessageforward.o gprotocolmessagestore.o \ gnewmessage.o gprotocolmessage.o gprotocolmessageforward.o \
gserverprotocol.o gsmtpclient.o gsmtpserver.o gstoredfile.o \ gprotocolmessagestore.o gsasl_login.o gsecrets.o gserverprotocol.o \
gstoredmessage.o gverifier.o main_unix.o configuration.o run.o \ gsmtpclient.o gsmtpserver.o gstoredfile.o gstoredmessage.o gverifier.o \
commandline.o commandline_unix.o gxtext.o main_unix.o configuration.o run.o commandline.o \
commandline_unix.o
emailrelay_DEPENDENCIES = $(top_builddir)/src/glib/libglib.a \ emailrelay_DEPENDENCIES = $(top_builddir)/src/glib/libglib.a \
$(top_builddir)/src/gnet/libgnet.a $(top_builddir)/src/gnet/libgnet.a
emailrelay_LDFLAGS = emailrelay_LDFLAGS =
@ -293,7 +294,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
@ -333,14 +334,22 @@ gadminserver.o: gadminserver.cpp ../../src/glib/gdef.h ../../config.h \
gadminserver.h ../../src/gnet/gserver.h \ gadminserver.h ../../src/gnet/gserver.h \
../../src/gnet/gsocket.h ../../src/gnet/gaddress.h \ ../../src/gnet/gsocket.h ../../src/gnet/gaddress.h \
../../src/glib/gexception.h ../../src/gnet/gevent.h \ ../../src/glib/gexception.h ../../src/gnet/gevent.h \
../../src/gnet/gdescriptor.h ../../src/gnet/gconnection.h \ ../../src/glib/gdatetime.h ../../src/gnet/gdescriptor.h \
../../src/gnet/gselect.h ../../src/gnet/glinebuffer.h \ ../../src/gnet/gconnection.h ../../src/gnet/gselect.h \
../../src/glib/gstrings.h gserverprotocol.h gprotocolmessage.h \ ../../src/gnet/glinebuffer.h ../../src/glib/gstrings.h \
gverifier.h gsmtpclient.h ../../src/gnet/gclient.h \ gserverprotocol.h gprotocolmessage.h gverifier.h gsasl.h \
gclientprotocol.h gmessagestore.h gnewmessage.h \ gsecrets.h ../../src/glib/gpath.h gsmtpclient.h \
gstoredmessage.h ../../src/glib/gpath.h \ ../../src/gnet/gclient.h gclientprotocol.h gmessagestore.h \
gnewmessage.h gstoredmessage.h ../../src/gnet/gtimer.h \
../../src/gnet/gmonitor.h ../../src/glib/gstr.h \ ../../src/gnet/gmonitor.h ../../src/glib/gstr.h \
../../src/glib/gmemory.h ../../src/glib/gmemory.h
gbase64.o: gbase64.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
../../src/gnet/gnet.h ../../src/glib/glog.h gbase64.h \
../../src/glib/gexception.h ../../src/glib/gassert.h \
../../src/glib/glogoutput.h ../../src/glib/gstr.h \
../../src/glib/gstrings.h
gclientprotocol.o: gclientprotocol.cpp ../../src/glib/gdef.h \ gclientprotocol.o: gclientprotocol.cpp ../../src/glib/gdef.h \
../../config.h ../../lib/gcc2.95/iostream \ ../../config.h ../../lib/gcc2.95/iostream \
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \ ../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
@ -348,9 +357,11 @@ gclientprotocol.o: gclientprotocol.cpp ../../src/glib/gdef.h \
../../src/glib/glog.h ../../src/gnet/glocal.h \ ../../src/glib/glog.h ../../src/gnet/glocal.h \
../../src/gnet/gaddress.h ../../src/glib/gexception.h \ ../../src/gnet/gaddress.h ../../src/glib/gexception.h \
../../src/glib/gfile.h ../../src/glib/gpath.h \ ../../src/glib/gfile.h ../../src/glib/gpath.h \
../../src/glib/gstrings.h ../../src/glib/gstr.h \ ../../src/glib/gstrings.h gsasl.h gsecrets.h gbase64.h \
../../src/glib/gmemory.h gclientprotocol.h gmessagestore.h \ ../../src/glib/gstr.h ../../src/glib/gmemory.h gxtext.h \
gnewmessage.h gstoredmessage.h ../../src/gnet/gresolve.h \ gclientprotocol.h gmessagestore.h gnewmessage.h \
gstoredmessage.h ../../src/gnet/gtimer.h \
../../src/glib/gdatetime.h ../../src/gnet/gresolve.h \
../../src/glib/gassert.h ../../src/glib/glogoutput.h ../../src/glib/gassert.h ../../src/glib/glogoutput.h
gfilestore.o: gfilestore.cpp ../../src/glib/gdef.h ../../config.h \ gfilestore.o: gfilestore.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
@ -385,7 +396,7 @@ gnewfile.o: gnewfile.cpp ../../src/glib/gdef.h ../../config.h \
../../src/glib/gpath.h ../../src/glib/gexception.h gnewfile.h \ ../../src/glib/gpath.h ../../src/glib/gexception.h gnewfile.h \
gfilestore.h ../../src/glib/gdatetime.h \ gfilestore.h ../../src/glib/gdatetime.h \
../../src/glib/gmemory.h ../../src/glib/gprocess.h \ ../../src/glib/gmemory.h ../../src/glib/gprocess.h \
../../src/glib/gfile.h ../../src/glib/gassert.h \ ../../src/glib/gfile.h gxtext.h ../../src/glib/gassert.h \
../../src/glib/glogoutput.h ../../src/glib/glogoutput.h
gnewmessage.o: gnewmessage.cpp ../../src/glib/gdef.h ../../config.h \ gnewmessage.o: gnewmessage.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
@ -405,13 +416,14 @@ gprotocolmessageforward.o: gprotocolmessageforward.cpp \
../../lib/gcc2.95/limits gsmtp.h ../../src/gnet/gnet.h \ ../../lib/gcc2.95/limits gsmtp.h ../../src/gnet/gnet.h \
../../src/glib/glog.h gprotocolmessageforward.h \ ../../src/glib/glog.h gprotocolmessageforward.h \
gprotocolmessage.h ../../src/glib/gstrings.h gverifier.h \ gprotocolmessage.h ../../src/glib/gstrings.h gverifier.h \
gprotocolmessagestore.h gnewmessage.h gsmtpclient.h \ gprotocolmessagestore.h gnewmessage.h gsmtpclient.h gsecrets.h \
../../src/glib/gpath.h ../../src/glib/gexception.h \
../../src/gnet/glinebuffer.h ../../src/gnet/gclient.h \ ../../src/gnet/glinebuffer.h ../../src/gnet/gclient.h \
../../src/gnet/gaddress.h ../../src/glib/gexception.h \ ../../src/gnet/gaddress.h ../../src/gnet/gconnection.h \
../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \ ../../src/gnet/gsocket.h ../../src/gnet/gevent.h \
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \ ../../src/glib/gdatetime.h ../../src/gnet/gdescriptor.h \
gclientprotocol.h gmessagestore.h gstoredmessage.h \ gclientprotocol.h gmessagestore.h gstoredmessage.h gsasl.h \
../../src/glib/gpath.h ../../src/glib/gmemory.h \ ../../src/gnet/gtimer.h ../../src/glib/gmemory.h \
../../src/glib/gstr.h ../../src/glib/gassert.h \ ../../src/glib/gstr.h ../../src/glib/gassert.h \
../../src/glib/glogoutput.h ../../src/glib/glogoutput.h
gprotocolmessagestore.o: gprotocolmessagestore.cpp ../../src/glib/gdef.h \ gprotocolmessagestore.o: gprotocolmessagestore.cpp ../../src/glib/gdef.h \
@ -424,13 +436,28 @@ gprotocolmessagestore.o: gprotocolmessagestore.cpp ../../src/glib/gdef.h \
../../src/glib/gpath.h ../../src/glib/gexception.h \ ../../src/glib/gpath.h ../../src/glib/gexception.h \
../../src/glib/gmemory.h ../../src/glib/gstr.h \ ../../src/glib/gmemory.h ../../src/glib/gstr.h \
../../src/glib/gassert.h ../../src/glib/glogoutput.h ../../src/glib/gassert.h ../../src/glib/glogoutput.h
gsasl_login.o: gsasl_login.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
../../src/gnet/gnet.h ../../src/glib/glog.h gsasl.h gsecrets.h \
../../src/glib/gpath.h ../../src/glib/gstrings.h \
../../src/glib/gexception.h ../../src/glib/gstr.h \
../../src/glib/gmemory.h ../../src/glib/gdebug.h \
../../src/glib/glogoutput.h ../../src/glib/gassert.h
gsecrets.o: gsecrets.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
../../src/gnet/gnet.h ../../src/glib/glog.h gsecrets.h \
../../src/glib/gpath.h ../../src/glib/gstrings.h \
../../src/glib/gexception.h gxtext.h ../../src/glib/gstr.h
gserverprotocol.o: gserverprotocol.cpp ../../src/glib/gdef.h \ gserverprotocol.o: gserverprotocol.cpp ../../src/glib/gdef.h \
../../config.h ../../lib/gcc2.95/iostream \ ../../config.h ../../lib/gcc2.95/iostream \
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \ ../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
../../lib/gcc2.95/limits gsmtp.h ../../src/gnet/gnet.h \ ../../lib/gcc2.95/limits gsmtp.h ../../src/gnet/gnet.h \
../../src/glib/glog.h gserverprotocol.h gprotocolmessage.h \ ../../src/glib/glog.h gserverprotocol.h gprotocolmessage.h \
../../src/glib/gstrings.h gverifier.h ../../src/glib/gdate.h \ ../../src/glib/gstrings.h gverifier.h gsasl.h gsecrets.h \
../../src/glib/gdatetime.h ../../src/glib/gexception.h \ ../../src/glib/gpath.h ../../src/glib/gexception.h gbase64.h \
../../src/glib/gdate.h ../../src/glib/gdatetime.h \
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \ ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/gassert.h ../../src/glib/gtime.h \ ../../src/glib/gassert.h ../../src/glib/gtime.h \
../../src/glib/gstr.h ../../src/glib/gstr.h
@ -441,26 +468,29 @@ gsmtpclient.o: gsmtpclient.cpp ../../src/glib/gdef.h ../../config.h \
../../src/gnet/glocal.h ../../src/gnet/gaddress.h \ ../../src/gnet/glocal.h ../../src/gnet/gaddress.h \
../../src/glib/gexception.h ../../src/glib/gfile.h \ ../../src/glib/gexception.h ../../src/glib/gfile.h \
../../src/glib/gpath.h ../../src/glib/gstrings.h \ ../../src/glib/gpath.h ../../src/glib/gstrings.h \
../../src/glib/gstr.h ../../src/glib/gmemory.h gsmtpclient.h \ ../../src/glib/gstr.h ../../src/glib/gmemory.h \
../../src/gnet/glinebuffer.h ../../src/gnet/gclient.h \ ../../src/gnet/gtimer.h ../../src/glib/gdatetime.h \
../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \ gsmtpclient.h gsecrets.h ../../src/gnet/glinebuffer.h \
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \ ../../src/gnet/gclient.h ../../src/gnet/gconnection.h \
gclientprotocol.h gmessagestore.h gnewmessage.h \ ../../src/gnet/gsocket.h ../../src/gnet/gevent.h \
gstoredmessage.h ../../src/gnet/gresolve.h \ ../../src/gnet/gdescriptor.h gclientprotocol.h gmessagestore.h \
../../src/glib/gassert.h ../../src/glib/glogoutput.h gnewmessage.h gstoredmessage.h gsasl.h \
../../src/gnet/gresolve.h ../../src/glib/gassert.h \
../../src/glib/glogoutput.h
gsmtpserver.o: gsmtpserver.cpp ../../src/glib/gdef.h ../../config.h \ gsmtpserver.o: gsmtpserver.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
../../src/gnet/gnet.h ../../src/glib/glog.h gsmtpserver.h \ ../../src/gnet/gnet.h ../../src/glib/glog.h gsmtpserver.h \
../../src/gnet/gserver.h ../../src/gnet/gsocket.h \ ../../src/gnet/gserver.h ../../src/gnet/gsocket.h \
../../src/gnet/gaddress.h ../../src/glib/gexception.h \ ../../src/gnet/gaddress.h ../../src/glib/gexception.h \
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \ ../../src/gnet/gevent.h ../../src/glib/gdatetime.h \
../../src/gnet/gconnection.h ../../src/gnet/gselect.h \ ../../src/gnet/gdescriptor.h ../../src/gnet/gconnection.h \
../../src/gnet/glinebuffer.h ../../src/glib/gstrings.h \ ../../src/gnet/gselect.h ../../src/gnet/glinebuffer.h \
gverifier.h gserverprotocol.h gprotocolmessage.h \ ../../src/glib/gstrings.h gverifier.h gserverprotocol.h \
gprotocolmessage.h gsasl.h gsecrets.h ../../src/glib/gpath.h \
gprotocolmessagestore.h gnewmessage.h gprotocolmessageforward.h \ gprotocolmessagestore.h gnewmessage.h gprotocolmessageforward.h \
gsmtpclient.h ../../src/gnet/gclient.h gclientprotocol.h \ gsmtpclient.h ../../src/gnet/gclient.h gclientprotocol.h \
gmessagestore.h gstoredmessage.h ../../src/glib/gpath.h \ gmessagestore.h gstoredmessage.h ../../src/gnet/gtimer.h \
../../src/glib/gmemory.h ../../src/gnet/glocal.h \ ../../src/glib/gmemory.h ../../src/gnet/glocal.h \
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \ ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/gassert.h ../../src/glib/gassert.h
@ -471,9 +501,9 @@ gstoredfile.o: gstoredfile.cpp ../../src/glib/gdef.h ../../config.h \
gmessagestore.h gnewmessage.h gstoredmessage.h \ gmessagestore.h gnewmessage.h gstoredmessage.h \
../../src/glib/gstrings.h ../../src/glib/gpath.h \ ../../src/glib/gstrings.h ../../src/glib/gpath.h \
../../src/glib/gexception.h ../../src/glib/gdatetime.h \ ../../src/glib/gexception.h ../../src/glib/gdatetime.h \
gstoredfile.h ../../src/glib/gmemory.h ../../src/glib/gfile.h \ gstoredfile.h ../../src/glib/gmemory.h gxtext.h \
../../src/glib/gstr.h ../../src/glib/gassert.h \ ../../src/glib/gfile.h ../../src/glib/gstr.h \
../../src/glib/glogoutput.h ../../src/glib/gassert.h ../../src/glib/glogoutput.h
gstoredmessage.o: gstoredmessage.cpp ../../src/glib/gdef.h \ gstoredmessage.o: gstoredmessage.cpp ../../src/glib/gdef.h \
../../config.h ../../lib/gcc2.95/iostream \ ../../config.h ../../lib/gcc2.95/iostream \
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \ ../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
@ -487,6 +517,11 @@ gverifier.o: gverifier.cpp ../../src/glib/gdef.h ../../config.h \
../../src/glib/gstr.h ../../src/glib/gexception.h \ ../../src/glib/gstr.h ../../src/glib/gexception.h \
../../src/glib/gstrings.h ../../src/glib/gassert.h \ ../../src/glib/gstrings.h ../../src/glib/gassert.h \
../../src/glib/glogoutput.h ../../src/glib/glogoutput.h
gxtext.o: gxtext.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
../../src/gnet/gnet.h ../../src/glib/glog.h gxtext.h \
../../src/glib/gassert.h ../../src/glib/glogoutput.h
main_unix.o: main_unix.cpp ../../src/glib/gdef.h ../../config.h \ main_unix.o: main_unix.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gsmtp.h \
@ -494,12 +529,13 @@ main_unix.o: main_unix.cpp ../../src/glib/gdef.h ../../config.h \
../../src/glib/garg.h run.h configuration.h \ ../../src/glib/garg.h run.h configuration.h \
../../src/glib/gpath.h ../../src/glib/gstrings.h commandline.h \ ../../src/glib/gpath.h ../../src/glib/gstrings.h commandline.h \
../../src/glib/ggetopt.h ../../src/glib/gexception.h \ ../../src/glib/ggetopt.h ../../src/glib/gexception.h \
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \ ../../src/gnet/gevent.h ../../src/glib/gdatetime.h \
../../src/glib/gdaemon.h gmessagestore.h gnewmessage.h \ ../../src/gnet/gdescriptor.h ../../src/glib/gdaemon.h \
gstoredmessage.h gsmtpclient.h ../../src/gnet/glinebuffer.h \ gmessagestore.h gnewmessage.h gstoredmessage.h gsmtpclient.h \
gsecrets.h ../../src/gnet/glinebuffer.h \
../../src/gnet/gclient.h ../../src/gnet/gaddress.h \ ../../src/gnet/gclient.h ../../src/gnet/gaddress.h \
../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \ ../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \
gclientprotocol.h gclientprotocol.h gsasl.h ../../src/gnet/gtimer.h
poke.o: poke.c poke.o: poke.c
run.o: run.cpp ../../src/glib/gdef.h ../../config.h \ run.o: run.cpp ../../src/glib/gdef.h ../../config.h \
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \ ../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
@ -508,15 +544,16 @@ run.o: run.cpp ../../src/glib/gdef.h ../../config.h \
configuration.h ../../src/glib/gpath.h \ configuration.h ../../src/glib/gpath.h \
../../src/glib/gstrings.h commandline.h ../../src/glib/garg.h \ ../../src/glib/gstrings.h commandline.h ../../src/glib/garg.h \
../../src/glib/ggetopt.h ../../src/glib/gexception.h \ ../../src/glib/ggetopt.h ../../src/glib/gexception.h \
../../src/gnet/gevent.h ../../src/gnet/gdescriptor.h \ ../../src/gnet/gevent.h ../../src/glib/gdatetime.h \
../../src/glib/gdaemon.h gmessagestore.h gnewmessage.h \ ../../src/gnet/gdescriptor.h ../../src/glib/gdaemon.h \
gstoredmessage.h gsmtpclient.h ../../src/gnet/glinebuffer.h \ gmessagestore.h gnewmessage.h gstoredmessage.h gsmtpclient.h \
gsecrets.h ../../src/gnet/glinebuffer.h \
../../src/gnet/gclient.h ../../src/gnet/gaddress.h \ ../../src/gnet/gclient.h ../../src/gnet/gaddress.h \
../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \ ../../src/gnet/gconnection.h ../../src/gnet/gsocket.h \
gclientprotocol.h gsmtpserver.h ../../src/gnet/gserver.h \ gclientprotocol.h gsasl.h ../../src/gnet/gtimer.h gsmtpserver.h \
../../src/gnet/gselect.h gverifier.h gserverprotocol.h \ ../../src/gnet/gserver.h ../../src/gnet/gselect.h gverifier.h \
gprotocolmessage.h gfilestore.h ../../src/glib/gdatetime.h \ gserverprotocol.h gprotocolmessage.h gfilestore.h gnewfile.h \
gnewfile.h gadminserver.h ../../src/gnet/gmonitor.h \ gadminserver.h ../../src/gnet/gmonitor.h \
../../src/glib/gprocess.h ../../src/glib/gmemory.h \ ../../src/glib/gprocess.h ../../src/glib/gmemory.h \
../../src/glib/gdebug.h ../../src/glib/glogoutput.h \ ../../src/glib/gdebug.h ../../src/glib/glogoutput.h \
../../src/glib/gassert.h ../../src/glib/gassert.h

View File

@ -36,6 +36,8 @@ std::string Main::CommandLine::switchSpec()
std::stringstream ss ; std::stringstream ss ;
ss ss
<< osSwitchSpec() << "|" << osSwitchSpec() << "|"
<< "C!client-auth!enables authentication with remote server, using the given secrets file!1!file|"
<< "S!server-auth!enables authentication of remote clients, using the given secrets file!1!file|"
<< "y!as-proxy!equivalent to \"--log --close-stderr --immediate --forward-to\"!1!host:port|" << "y!as-proxy!equivalent to \"--log --close-stderr --immediate --forward-to\"!1!host:port|"
<< "e!close-stderr!closes the standard error stream after start-up!0!|" << "e!close-stderr!closes the standard error stream after start-up!0!|"
<< "a!admin!enables the administration interface and specifies its listening port number!1!admin-port|" << "a!admin!enables the administration interface and specifies its listening port number!1!admin-port|"
@ -44,6 +46,8 @@ std::string Main::CommandLine::switchSpec()
<< "f!forward!forwards stored mail on startup (requires --forward-to)!0!|" << "f!forward!forwards stored mail on startup (requires --forward-to)!0!|"
<< "o!forward-to!specifies the remote smtp server (required by --forward and --admin)!1!host:port|" << "o!forward-to!specifies the remote smtp server (required by --forward and --admin)!1!host:port|"
<< "h!help!displays help text and exits!0!|" << "h!help!displays help text and exits!0!|"
<< "T!response-timeout!sets the client-side response timeout in seconds (default is 1800)!1!time|"
<< "U!connection-timeout!sets the client-side connection timeout in seconds (default is 40)!1!time|"
<< "m!immediate!forwards each message as soon as it is received (requires --forward-to)!0!|" << "m!immediate!forwards each message as soon as it is received (requires --forward-to)!0!|"
<< "i!pid-file!records the daemon process-id in the given file!1!pid-file|" << "i!pid-file!records the daemon process-id in the given file!1!pid-file|"
<< "p!port!specifies the smtp listening port number!1!port|" << "p!port!specifies the smtp listening port number!1!port|"
@ -81,7 +85,7 @@ void Main::CommandLine::showUsage( bool e ) const
{ {
Show show( e ) ; Show show( e ) ;
unsigned int columns = ttyColumns() ; unsigned int columns = ttyColumns() ;
m_getopt.showUsage( show.s() , m_arg.prefix() , "" , 30U , columns ) ; m_getopt.showUsage( show.s() , m_arg.prefix() , "" , 33U , columns ) ;
} }
bool Main::CommandLine::contains( const std::string & name ) const bool Main::CommandLine::contains( const std::string & name ) const
@ -108,6 +112,14 @@ std::string Main::CommandLine::semanticError() const
"be an absolute path" ; "be an absolute path" ;
} }
if( cfg().daemon() && (
( !cfg().clientSecretsFile().empty() && G::Path(cfg().clientSecretsFile()).isRelative() ) ||
( !cfg().serverSecretsFile().empty() && G::Path(cfg().serverSecretsFile()).isRelative() ) ) )
{
return "in daemon mode the authorisation secrets file(s) must "
"be absolute paths" ;
}
if( !m_getopt.contains("forward-to") && ( if( !m_getopt.contains("forward-to") && (
m_getopt.contains("forward") || m_getopt.contains("forward") ||
m_getopt.contains("immediate") || m_getopt.contains("immediate") ||

View File

@ -30,8 +30,9 @@ Main::CommandLine::Show * Main::CommandLine::Show::m_this = NULL ;
//static //static
std::string Main::CommandLine::osSwitchSpec() std::string Main::CommandLine::osSwitchSpec()
{ {
// (could use empty descriptions here so that G::GetOpt does // (could use empty descriptions for some switches so that they
// not put them in the --help listing) // do not appear in the "--help" listing, but that might be
// confusing)
std::stringstream ss ; std::stringstream ss ;
ss ss
@ -40,12 +41,19 @@ std::string Main::CommandLine::osSwitchSpec()
<< "n!no-syslog!has no effect on windows!0!|" << "n!no-syslog!has no effect on windows!0!|"
<< "q!as-client!equivalent to \"--log --no-daemon --dont-serve --forward --forward-to\"!" << "1!host:port|" << "q!as-client!equivalent to \"--log --no-daemon --dont-serve --forward --forward-to\"!" << "1!host:port|"
<< "d!as-server!equivalent to \"--log --close-stderr\" (has little effect on windows)!0!|" << "d!as-server!equivalent to \"--log --close-stderr\" (has little effect on windows)!0!|"
<< "I!icon!chooses the application icon!1!icon index {0,1,2}" << "I!icon!selects the application icon!1!0^|1^|2^|3"
; ;
return ss.str() ; return ss.str() ;
} }
unsigned int Main::CommandLine::ttyColumns() const
{
return 120U ;
}
// ===
Main::CommandLine::Show::Show( bool ) Main::CommandLine::Show::Show( bool )
{ {
if( m_this == NULL ) if( m_this == NULL )
@ -68,9 +76,3 @@ Main::CommandLine::Show::~Show()
} }
} }
unsigned int Main::CommandLine::ttyColumns() const
{
return 120U ;
}

View File

@ -173,6 +173,36 @@ std::string Main::Configuration::filter() const
unsigned int Main::Configuration::icon() const unsigned int Main::Configuration::icon() const
{ {
return m_cl.contains("icon") ? G::Str::toUInt(m_cl.value("icon")) : 0U ; unsigned int n = 0U ;
if( m_cl.contains("icon") )
{
n = G::Str::toUInt(m_cl.value("icon")) ;
n %= 4U ;
}
return n ;
}
std::string Main::Configuration::clientSecretsFile() const
{
return m_cl.contains("client-auth") ? m_cl.value("client-auth") : std::string() ;
}
std::string Main::Configuration::serverSecretsFile() const
{
return m_cl.contains("server-auth") ? m_cl.value("server-auth") : std::string() ;
}
unsigned int Main::Configuration::responseTimeout() const
{
const unsigned int default_timeout = 30U * 60U ;
return m_cl.contains("response-timeout") ?
G::Str::toUInt(m_cl.value("response-timeout")) : default_timeout ;
}
unsigned int Main::Configuration::connectionTimeout() const
{
const unsigned int default_timeout = 40U ;
return m_cl.contains("connection-timeout") ?
G::Str::toUInt(m_cl.value("connection-timeout")) : default_timeout ;
} }

View File

@ -109,6 +109,20 @@ public:
unsigned int icon() const ; unsigned int icon() const ;
// Returns the icon selector. // Returns the icon selector.
unsigned int responseTimeout() const ;
// Returns the client-side protocol timeout value.
unsigned int connectionTimeout() const ;
// Returns the client-side connection timeout value.
std::string clientSecretsFile() const ;
// Returns the client-side autentication secrets (password) file.
// Returns the empty string if none.
std::string serverSecretsFile() const ;
// Returns the server-side autentication secrets (password) file.
// Returns the empty string if none.
private: private:
const CommandLine & m_cl ; const CommandLine & m_cl ;

View File

@ -3,7 +3,7 @@
# General configuration options # General configuration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
PROJECT_NAME = E-MailRelay PROJECT_NAME = E-MailRelay
PROJECT_NUMBER = 0.9.5 PROJECT_NUMBER = 0.9.6
OUTPUT_DIRECTORY = OUTPUT_DIRECTORY =
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
EXTRACT_ALL = YES EXTRACT_ALL = YES

View File

@ -127,6 +127,10 @@ SOURCE=..\..\src\glib\garg_win32.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\gbase64.cpp
# End Source File
# Begin Source File
SOURCE=..\..\src\gnet\gclient.cpp SOURCE=..\..\src\gnet\gclient.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -307,10 +311,18 @@ SOURCE=..\..\src\gnet\gresolve_win32.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\gsasl_login.cpp
# End Source File
# Begin Source File
SOURCE=..\win32\gscmap.cpp SOURCE=..\win32\gscmap.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\gsecrets.cpp
# End Source File
# Begin Source File
SOURCE=..\gnet\gserver.cpp SOURCE=..\gnet\gserver.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -351,6 +363,10 @@ SOURCE=..\..\src\glib\gtime.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\gnet\gtimer.cpp
# End Source File
# Begin Source File
SOURCE=..\win32\gtray.cpp SOURCE=..\win32\gtray.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -375,6 +391,10 @@ SOURCE=..\..\src\gnet\gwinsock.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\gxtext.cpp
# End Source File
# Begin Source File
SOURCE=.\main_win32.cpp SOURCE=.\main_win32.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -30,6 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
IDI_ICON1 ICON DISCARDABLE "icon-32.ico" IDI_ICON1 ICON DISCARDABLE "icon-32.ico"
IDI_ICON2 ICON DISCARDABLE "icon2.ico" IDI_ICON2 ICON DISCARDABLE "icon2.ico"
IDI_ICON3 ICON DISCARDABLE "icon3.ico" IDI_ICON3 ICON DISCARDABLE "icon3.ico"
IDI_ICON4 ICON DISCARDABLE "icon4.ico"
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -39,8 +39,8 @@ GSmtp::AdminClient::AdminClient( AdminPeer & admin_peer ) :
GSmtp::AdminPeer::AdminPeer( GNet::StreamSocket * s , GNet::Address a , AdminServer & server , GSmtp::AdminPeer::AdminPeer( GNet::StreamSocket * s , GNet::Address a , AdminServer & server ,
const std::string & server_address ) : const std::string & server_address ) :
GNet::ServerPeer( s , a ) , GNet::ServerPeer( s , a ) ,
m_server(server) ,
m_buffer(crlf()) , m_buffer(crlf()) ,
m_server(server) ,
m_server_address(server_address) m_server_address(server_address)
{ {
// dont prompt() here -- it confuses the poke program // dont prompt() here -- it confuses the poke program
@ -146,7 +146,7 @@ void GSmtp::AdminPeer::prompt()
{ {
std::string p( "E-MailRelay> " ) ; std::string p( "E-MailRelay> " ) ;
ssize_t rc = socket().write( p.data() , p.length() ) ; ssize_t rc = socket().write( p.data() , p.length() ) ;
if( rc < p.length() ) if( rc < 0 || static_cast<size_t>(rc) < p.length() )
doDelete() ; // onDelete() and "delete this" doDelete() ; // onDelete() and "delete this"
} }
@ -154,7 +154,7 @@ void GSmtp::AdminPeer::send( std::string line )
{ {
line.append( crlf() ) ; line.append( crlf() ) ;
ssize_t rc = socket().write( line.data() , line.length() ) ; ssize_t rc = socket().write( line.data() , line.length() ) ;
if( rc < line.length() ) if( rc < 0 || static_cast<size_t>(rc) < line.length() )
doDelete() ; // onDelete() and "delete this" doDelete() ; // onDelete() and "delete this"
} }

183
src/main/gbase64.cpp Normal file
View File

@ -0,0 +1,183 @@
//
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ===
//
// gbase64.cpp
//
#include "gdef.h"
#include "gsmtp.h"
#include "gbase64.h"
#include "gassert.h"
#include "gstr.h"
namespace
{
const char * map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
char pad = '=' ;
} ;
g_uint32_t GSmtp::Base64::numeric( char c )
{
return static_cast<g_uint32_t>( static_cast<unsigned char>(c) ) ;
}
void GSmtp::Base64::accumulate_8( g_uint32_t & n , std::string::const_iterator & p ,
std::string::const_iterator end , int & i )
{
char c = p == end ? '\0' : *p ;
n <<= 8U ;
n |= numeric(c) ;
if( p != end )
{
++p ;
++i ;
}
}
size_t GSmtp::Base64::hi_6( g_uint32_t n )
{
return (n >> 18U) & 0x3F ;
}
void GSmtp::Base64::generate_6( g_uint32_t & n , int & i , std::string & result )
{
char c = i-- >= 0 ? map[hi_6(n)] : pad ;
result.append( 1U , c ) ;
n <<= 6U ;
}
std::string GSmtp::Base64::crlf()
{
return std::string( "\r\n" ) ;
}
std::string GSmtp::Base64::encode( const std::string & s_in , const std::string & eol )
{
std::string result ;
size_t blocks = 0U ;
for( std::string::const_iterator p = s_in.begin() ; p != s_in.end() ; blocks++ )
{
if( blocks && (blocks % 19U) == 0U )
result.append( eol ) ;
g_uint32_t n = 0UL ;
int i = 0 ;
accumulate_8( n , p , s_in.end() , i ) ;
accumulate_8( n , p , s_in.end() , i ) ;
accumulate_8( n , p , s_in.end() , i ) ;
generate_6( n , i , result ) ;
generate_6( n , i , result ) ;
generate_6( n , i , result ) ;
generate_6( n , i , result ) ;
}
// delete when tested...
if( decode(result) != s_in )
{
std::string decode_result = decode(result) ;
G_ERROR( "GSmtp::Base64::encode: mismatch: "
<< "in \"" << G::Str::toPrintableAscii(s_in) << "\", "
<< "encoded \"" << G::Str::toPrintableAscii(result) << "\", "
<< "decoded \"" << G::Str::toPrintableAscii(decode_result) << "\"" ) ;
G_ASSERT( !"encode/decode mismatch" ) ;
}
return result ;
}
// ---
char GSmtp::Base64::to_char( g_uint32_t n )
{
return static_cast<char>(static_cast<unsigned char>(n)) ;
}
size_t GSmtp::Base64::index( char c , bool & error )
{
const char * p = std::strchr( map , c ) ;
error = error || !c || !p ;
return p ? (p-map) : 0U ;
}
size_t GSmtp::Base64::accumulate_6( g_uint32_t & n , char c_in , int & n_out , bool & error )
{
n <<= 6U ;
if( c_in != pad )
{
n |= index(c_in,error) ;
n_out++ ;
}
return c_in != '\0' ;
}
g_uint32_t GSmtp::Base64::hi_8( g_uint32_t n )
{
return (n >> 16U) & 0xff ;
}
void GSmtp::Base64::generate_8( g_uint32_t & n , int & n_out , std::string & result )
{
if( n_out-- > 0 )
result.append( 1U , to_char(hi_8(n)) ) ;
n <<= 8U ;
}
std::string GSmtp::Base64::decode( const std::string & s )
{
bool error = false ;
std::string result = decode( s , error ) ;
if( error )
throw Error() ;
return result ;
}
std::string GSmtp::Base64::decode( const std::string & s , bool & error )
{
std::string result ;
for( const char * p = s.c_str() ; *p ; )
{
if( *p == '\r' || *p == '\n' )
{
p++ ;
continue ;
}
g_uint32_t n = 0UL ;
size_t i = 0U ;
int n_out = -1 ;
i += accumulate_6( n , p[i] , n_out , error ) ;
i += accumulate_6( n , p[i] , n_out , error ) ;
i += accumulate_6( n , p[i] , n_out , error ) ;
i += accumulate_6( n , p[i] , n_out , error ) ;
p += i ;
generate_8( n , n_out , result ) ;
generate_8( n , n_out , result ) ;
generate_8( n , n_out , result ) ;
}
return result ;
}
bool GSmtp::Base64::valid( const std::string & s )
{
bool error = false ;
(void) decode( s , error ) ;
return !error ;
}

75
src/main/gbase64.h Normal file
View File

@ -0,0 +1,75 @@
//
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ===
//
// gbase64.h
//
#ifndef G_BASE64_H
#define G_BASE64_H
#include "gdef.h"
#include "gsmtp.h"
#include "gexception.h"
#include <string>
namespace GSmtp
{
class Base64 ;
} ;
// Class: GSmtp::Base64
// Description: A base64 codec class.
// See also: RFC 1341 section 5.2
//
class GSmtp::Base64
{
public:
G_EXCEPTION( Error , "base64 encoding error" ) ;
static std::string encode( const std::string & s , const std::string & eol = crlf() ) ;
// Encodes the given string.
static std::string decode( const std::string & ) ;
// Decodes the given string. Throws an exception
// if not a valid encoding.
static bool valid( const std::string & ) ;
// Returns true if the string can be decoded.
static std::string crlf() ;
// Returns carriage-return-line-feed.
private:
Base64() ;
static inline g_uint32_t numeric( char c ) ;
static inline void accumulate_8( g_uint32_t & n , std::string::const_iterator & ,
std::string::const_iterator , int & ) ;
static inline size_t hi_6( g_uint32_t n ) ;
static inline void generate_6( g_uint32_t & n , int & i , std::string & result ) ;
static inline char to_char( g_uint32_t n ) ;
static inline size_t index( char c , bool & error ) ;
static inline size_t accumulate_6( g_uint32_t & n , char c_in , int & , bool & error ) ;
static inline g_uint32_t hi_8( g_uint32_t n ) ;
static inline void generate_8( g_uint32_t & n , int & i , std::string & result ) ;
static std::string decode( const std::string & s , bool & error ) ;
} ;
#endif

View File

@ -26,24 +26,33 @@
#include "gsmtp.h" #include "gsmtp.h"
#include "glocal.h" #include "glocal.h"
#include "gfile.h" #include "gfile.h"
#include "gsasl.h"
#include "gbase64.h"
#include "gstr.h" #include "gstr.h"
#include "gmemory.h" #include "gmemory.h"
#include "gxtext.h"
#include "gclientprotocol.h" #include "gclientprotocol.h"
#include "gresolve.h" #include "gresolve.h"
#include "glog.h" #include "glog.h"
#include "gassert.h" #include "gassert.h"
GSmtp::ClientProtocol::ClientProtocol( Sender & sender , const std::string & thishost ) : GSmtp::ClientProtocol::ClientProtocol( Sender & sender , const std::string & thishost_name ,
m_state(sStart) , unsigned int timeout , bool must_authenticate ) :
m_thishost(thishost) , m_sender(sender) ,
m_sender(sender) , m_thishost(thishost_name) ,
m_callback(NULL) , m_state(sStart) ,
m_server_has_8bitmime(false) , m_callback(NULL) ,
m_said_hello(false) m_server_has_8bitmime(false) ,
m_said_hello(false) ,
m_message_is_8bit(false) ,
m_authenticated_with_server(false) ,
m_must_authenticate(must_authenticate) ,
m_timeout(timeout)
{ {
} }
void GSmtp::ClientProtocol::start( const std::string & from , const G::Strings & to , bool eight_bit , void GSmtp::ClientProtocol::start( const std::string & from , const G::Strings & to , bool eight_bit ,
std::string authentication , std::string server_name ,
std::auto_ptr<std::istream> content , Callback & callback ) std::auto_ptr<std::istream> content , Callback & callback )
{ {
G_DEBUG( "GSmtp::ClientProtocol::start" ) ; G_DEBUG( "GSmtp::ClientProtocol::start" ) ;
@ -51,9 +60,10 @@ void GSmtp::ClientProtocol::start( const std::string & from , const G::Strings &
m_from = from ; m_from = from ;
m_content = content ; m_content = content ;
m_callback = &callback ; m_callback = &callback ;
m_server_has_8bitmime = false ;
m_message_is_8bit = eight_bit ; m_message_is_8bit = eight_bit ;
m_message_authentication = authentication ;
m_reply = Reply() ; m_reply = Reply() ;
m_sasl <<= new SaslClient( server_name ) ;
if( m_state != sStart && m_state != sEnd ) if( m_state != sStart && m_state != sEnd )
throw NotReady() ; throw NotReady() ;
@ -78,9 +88,7 @@ void GSmtp::ClientProtocol::sendDone()
{ {
if( m_state == sData ) if( m_state == sData )
{ {
size_t n = 0U ; size_t n = sendLines() ;
while( sendLine() )
n++ ;
G_LOG( "GSmtp::ClientProtocol: tx>>: [" << n << " line(s) of content]" ) ; G_LOG( "GSmtp::ClientProtocol: tx>>: [" << n << " line(s) of content]" ) ;
if( endOfContent() ) if( endOfContent() )
@ -141,15 +149,25 @@ void GSmtp::ClientProtocol::sendMail()
{ {
mail_from.append( " BODY=8BITMIME" ) ; mail_from.append( " BODY=8BITMIME" ) ;
} }
else if( m_message_is_8bit ) if( !m_server_has_8bitmime && m_message_is_8bit )
{ {
throw NarrowPipe() ; // (could do better) throw NarrowPipe() ; // (could do better)
} }
if( m_authenticated_with_server && !m_message_authentication.empty() )
{
mail_from.append( std::string(" AUTH=") + Xtext::encode(m_message_authentication) ) ;
}
else if( m_authenticated_with_server )
{
mail_from.append( " AUTH=<>" ) ;
}
send( mail_from ) ; send( mail_from ) ;
} }
void GSmtp::ClientProtocol::applyEvent( const Reply & reply ) void GSmtp::ClientProtocol::applyEvent( const Reply & reply )
{ {
cancelTimer() ;
if( reply.is(Reply::ServiceReady_220) ) if( reply.is(Reply::ServiceReady_220) )
{ {
; // no-op ; // no-op
@ -158,6 +176,7 @@ void GSmtp::ClientProtocol::applyEvent( const Reply & reply )
{ {
m_state = sStart ; m_state = sStart ;
m_said_hello = false ; m_said_hello = false ;
m_authenticated_with_server = false ;
} }
else if( m_state == sStart ) else if( m_state == sStart )
{ {
@ -170,11 +189,61 @@ void GSmtp::ClientProtocol::applyEvent( const Reply & reply )
} }
else if( (m_state==sSentEhlo || m_state==sSentHelo) && reply.is(Reply::Ok_250) ) else if( (m_state==sSentEhlo || m_state==sSentHelo) && reply.is(Reply::Ok_250) )
{ {
m_server_has_8bitmime = m_state == sSentEhlo && reply.textContains("8BITMIME") ; G_ASSERT( m_sasl.get() != NULL ) ;
G_DEBUG( "GSmtp::ClientProtocol::applyEvent: ehlo reply \"" << G::Str::toPrintableAscii(reply.text()) << "\"" ) ;
m_auth_mechanism = m_sasl->preferred( serverAuthMechanisms(reply) ) ;
m_server_has_8bitmime = m_state == sSentEhlo && reply.textContains("\n8BITMIME") ;
m_said_hello = true ; m_said_hello = true ;
m_state = sSentMail ; if( m_sasl->active() && !m_auth_mechanism.empty() )
sendMail() ; {
m_state = sAuth1 ;
send( std::string("AUTH ") + m_auth_mechanism ) ;
}
else if( m_sasl->active() && m_must_authenticate )
{
std::string reason = "cannot do mandatory authentication" ; // eg. no suitable mechanism
G_WARNING( "GSmtp::ClientProtocol: " << reason ) ;
m_state = sEnd ;
doCallback( false , true , reason ) ;
}
else
{
m_state = sSentMail ;
sendMail() ;
}
}
else if( m_state == sAuth1 && reply.is(Reply::Challenge_334) && Base64::valid(reply.text()) )
{
bool done = true ;
bool error = false ;
std::string rsp = m_sasl->response( m_auth_mechanism , Base64::decode(reply.text()) , done , error ) ;
if( error )
{
m_state = sAuth2 ;
send( "*" ) ; // ie. cancel authentication
}
else
{
m_state = done ? sAuth2 : m_state ;
send( Base64::encode(rsp) ) ;
}
}
else if( m_state == sAuth2 )
{
m_authenticated_with_server = reply.is(Reply::Authenticated_235) ;
if( !m_authenticated_with_server && m_must_authenticate )
{
m_state = sEnd ;
doCallback( false , true , "mandatory authentication failed" ) ;
}
else
{
m_state = sSentMail ;
sendMail() ; // (with or without sucessful authentication)
}
} }
else if( m_state == sSentMail && reply.is(Reply::Ok_250) ) else if( m_state == sSentMail && reply.is(Reply::Ok_250) )
{ {
@ -203,15 +272,13 @@ void GSmtp::ClientProtocol::applyEvent( const Reply & reply )
{ {
G_WARNING( "GSmtp::ClientProtocol: recipient rejected" ) ; G_WARNING( "GSmtp::ClientProtocol: recipient rejected" ) ;
m_state = sEnd ; m_state = sEnd ;
doCallback( false , reply.text() ) ; doCallback( false , false , reply.text() ) ;
} }
else if( m_state == sSentData && reply.is(Reply::OkForData_354) ) else if( m_state == sSentData && reply.is(Reply::OkForData_354) )
{ {
m_state = sData ; m_state = sData ;
size_t n = 0U ; size_t n = sendLines() ;
while( sendLine() )
n++ ;
G_LOG( "GSmtp::ClientProtocol: tx>>: [" << n << " line(s) of content]" ) ; G_LOG( "GSmtp::ClientProtocol: tx>>: [" << n << " line(s) of content]" ) ;
if( endOfContent() ) if( endOfContent() )
@ -224,38 +291,45 @@ void GSmtp::ClientProtocol::applyEvent( const Reply & reply )
{ {
const bool ok = reply.is(Reply::Ok_250) ; const bool ok = reply.is(Reply::Ok_250) ;
m_state = sEnd ; m_state = sEnd ;
doCallback( ok , ok ? std::string() : reply.text() ) ; doCallback( ok , false , ok ? std::string() : reply.text() ) ;
} }
else else
{ {
G_WARNING( "GSmtp::ClientProtocol: failure in client protocol: " << static_cast<int>(m_state) ) ; G_WARNING( "GSmtp::ClientProtocol: failure in client protocol: " << static_cast<int>(m_state) ) ;
m_state = sEnd ; // (was sReset) m_state = sEnd ; // (was sReset)
send( "RSET" ) ; // for good meausre if( 0 ) send( "RSET" ) ; // for good meausre
doCallback( false , std::string("unexpected response: ")+reply.text() ) ; doCallback( false , true , std::string("unexpected response: ")+reply.text() ) ;
} }
} }
void GSmtp::ClientProtocol::doCallback( bool ok , const std::string & reason ) void GSmtp::ClientProtocol::onTimeout()
{
G_WARNING( "GSmtp::ClientProtocol: timeout" ) ;
m_state = sEnd ;
doCallback( false , false , "timeout" ) ;
}
G::Strings GSmtp::ClientProtocol::serverAuthMechanisms( const ClientProtocolReply & reply ) const
{
G::Strings result ;
std::string auth_line = reply.textLine("AUTH") ;
if( ! auth_line.empty() )
{
G::Str::splitIntoTokens( auth_line , result , " \t" ) ;
if( result.size() )
result.pop_front() ; // remove "AUTH" ;
}
return result ;
}
void GSmtp::ClientProtocol::doCallback( bool ok , bool abort , const std::string & reason )
{ {
m_content <<= 0 ; m_content <<= 0 ;
if( m_callback ) if( m_callback )
{ {
Callback * cb = m_callback ; Callback * cb = m_callback ;
m_callback = NULL ; m_callback = NULL ;
cb->protocolDone( ok , reason ) ; cb->protocolDone( ok , abort , reason ) ;
}
}
bool GSmtp::ClientProtocol::sendLine()
{
std::string line = G::Str::readLineFrom( *(m_content.get()) , crlf() ) ;
if( m_content->good() )
{
return send( line , false , false ) ;
}
else
{
return false ;
} }
} }
@ -264,11 +338,37 @@ bool GSmtp::ClientProtocol::endOfContent() const
return !m_content->good() ; return !m_content->good() ;
} }
size_t GSmtp::ClientProtocol::sendLines()
{
size_t n = 0U ;
std::string line ;
while( sendLine(line) )
n++ ;
return n ;
}
bool GSmtp::ClientProtocol::sendLine( std::string & line )
{
G::Str::readLineFrom( *(m_content.get()) , crlf() , line ) ;
if( m_content->good() )
{
line.append( crlf() ) ;
return m_sender.protocolSend( line ) ;
}
else
{
return false ;
}
}
bool GSmtp::ClientProtocol::send( const std::string & line , bool eot , bool log ) bool GSmtp::ClientProtocol::send( const std::string & line , bool eot , bool log )
{ {
if( log ) if( log )
G_LOG( "GSmtp::ClientProtocol: tx>>: \"" << G::Str::toPrintableAscii(line) << "\"" ) ; G_LOG( "GSmtp::ClientProtocol: tx>>: \"" << G::Str::toPrintableAscii(line) << "\"" ) ;
if( m_timeout != 0U )
startTimer( m_timeout ) ;
if( !eot && line.length() && line.at(0U) == '.' ) if( !eot && line.length() && line.at(0U) == '.' )
return m_sender.protocolSend( std::string(".")+line+crlf() ) ; return m_sender.protocolSend( std::string(".")+line+crlf() ) ;
else else
@ -276,16 +376,17 @@ bool GSmtp::ClientProtocol::send( const std::string & line , bool eot , bool log
} }
//static //static
std::string GSmtp::ClientProtocol::crlf() const std::string & GSmtp::ClientProtocol::crlf()
{ {
return std::string("\015\012") ; static std::string s("\015\012") ;
return s ;
} }
// === // ===
GSmtp::ClientProtocolReply::ClientProtocolReply( const std::string & line ) : GSmtp::ClientProtocolReply::ClientProtocolReply( const std::string & line ) :
m_valid(false) , m_complete(false) ,
m_complete(false) m_valid(false)
{ {
if( line.length() >= 3U && if( line.length() >= 3U &&
is_digit(line.at(0U)) && is_digit(line.at(0U)) &&
@ -297,9 +398,9 @@ GSmtp::ClientProtocolReply::ClientProtocolReply( const std::string & line ) :
m_valid = true ; m_valid = true ;
m_complete = line.length() == 3U || line.at(3U) == ' ' ; m_complete = line.length() == 3U || line.at(3U) == ' ' ;
m_value = G::Str::toUInt( line.substr(0U,3U) ) ; m_value = G::Str::toUInt( line.substr(0U,3U) ) ;
if( line.length() > 3U ) if( line.length() > 4U )
{ {
m_text = line.substr(3U) ; m_text = line.substr(4U) ;
G::Str::trimLeft( m_text , " \t" ) ; G::Str::trimLeft( m_text , " \t" ) ;
} }
} }
@ -335,6 +436,21 @@ std::string GSmtp::ClientProtocolReply::text() const
return m_text ; return m_text ;
} }
std::string GSmtp::ClientProtocolReply::textLine( const std::string & prefix ) const
{
size_t start_pos = m_text.find( std::string("\n")+prefix ) ;
if( start_pos == std::string::npos )
{
return std::string() ;
}
else
{
start_pos++ ;
size_t end_pos = m_text.find( "\n" , start_pos + prefix.length() ) ;
return m_text.substr( start_pos , end_pos-start_pos ) ;
}
}
//static //static
bool GSmtp::ClientProtocolReply::is_digit( char c ) bool GSmtp::ClientProtocolReply::is_digit( char c )
{ {

View File

@ -28,7 +28,10 @@
#include "gnet.h" #include "gnet.h"
#include "gsmtp.h" #include "gsmtp.h"
#include "gmessagestore.h" #include "gmessagestore.h"
#include "gsasl.h"
#include "gsecrets.h"
#include "gstrings.h" #include "gstrings.h"
#include "gtimer.h"
#include "gexception.h" #include "gexception.h"
#include <memory> #include <memory>
#include <iostream> #include <iostream>
@ -64,13 +67,15 @@ public:
} ; } ;
enum Value enum Value
{ {
Invalid = 0 ,
ServiceReady_220 = 220 , ServiceReady_220 = 220 ,
SyntaxError_500 = 500 , Ok_250 = 250 ,
BadSequence_503 = 503 , Authenticated_235 = 235 ,
NotImplemented_502 = 502 , Challenge_334 = 334 ,
OkForData_354 = 354 , OkForData_354 = 354 ,
Ok_250 = 250 SyntaxError_500 = 500 ,
NotImplemented_502 = 502 ,
BadSequence_503 = 503 ,
Invalid = 0 ,
} ; } ;
explicit ClientProtocolReply( const std::string & line = std::string() ) ; explicit ClientProtocolReply( const std::string & line = std::string() ) ;
bool incomplete() const ; bool incomplete() const ;
@ -80,6 +85,7 @@ public:
bool is( Value v ) const ; bool is( Value v ) const ;
unsigned int value() const ; unsigned int value() const ;
std::string text() const ; std::string text() const ;
std::string textLine( const std::string & prefix ) const ;
Type type() const ; Type type() const ;
SubType subType() const ; SubType subType() const ;
bool textContains( std::string s ) const ; bool textContains( std::string s ) const ;
@ -95,7 +101,7 @@ private:
// Class: GSmtp::ClientProtocol // Class: GSmtp::ClientProtocol
// Description: Implements the client-side SMTP protocol. // Description: Implements the client-side SMTP protocol.
// //
class GSmtp::ClientProtocol class GSmtp::ClientProtocol : private GNet::Timer
{ {
public: public:
G_EXCEPTION( NotReady , "not ready" ) ; G_EXCEPTION( NotReady , "not ready" ) ;
@ -121,26 +127,44 @@ public:
class Callback // A callback interface used by ClientProtocol. class Callback // A callback interface used by ClientProtocol.
{ {
public: virtual void protocolDone( bool ok , const std::string & reason ) = 0 ; public: virtual void protocolDone( bool ok , bool abort , const std::string & reason ) = 0 ;
// Called once the protocol has finished with // Called once the protocol has finished with
// a given message. See ClientProtocol::start(). // a given message. See ClientProtocol::start().
//
// If 'ok' is false then 'abort' indicates
// whether there is any point in trying to
// send more messages to the same server.
// The 'abort' parameter will be true if,
// for example, authentication failed -- if
// it failed for one message then it will
// fail for all the others.
private: void operator=( const Callback & ) ; // not implemented private: void operator=( const Callback & ) ; // not implemented
public: virtual ~Callback() ; public: virtual ~Callback() ;
} ; } ;
ClientProtocol( Sender & sender , const std::string & thishost ) ; ClientProtocol( Sender & sender , const std::string & thishost_name ,
// Constructor. The sender reference is kept. unsigned int timeout , bool must_authenticate ) ;
// The Sender interface is used to send // Constructor. The 'sender' and 'secrets' references
// protocol messages to the peer. // are kept.
//
// The Sender interface is used to send protocol
// messages to the peer.
//
// The 'thishost_name' parameter is used in the
// SMTP EHLO request.
void start( const std::string & from , const G::Strings & to , bool eight_bit , void start( const std::string & from , const G::Strings & to , bool eight_bit ,
std::string authentication , std::string server_name ,
std::auto_ptr<std::istream> content , Callback & callback ) ; std::auto_ptr<std::istream> content , Callback & callback ) ;
// Starts transmission of the given message. // Starts transmission of the given message.
// //
// The 'callback' parameter is used to // The 'callback' parameter is used to signal that the
// signal that the message has been // message has been processed.
// processed. //
// The 'server_name' parameter is passed to the SASL
// authentication code. It should be a fully-qualified
// domain name where possible.
void sendDone() ; void sendDone() ;
// Called when a blocked connection becomes unblocked. // Called when a blocked connection becomes unblocked.
@ -154,16 +178,19 @@ public:
private: private:
bool send( const std::string & , bool eot = false , bool log = true ) ; bool send( const std::string & , bool eot = false , bool log = true ) ;
bool sendLine() ; bool sendLine( std::string & ) ;
size_t sendLines() ;
void sendMail() ; void sendMail() ;
bool endOfContent() const ; bool endOfContent() const ;
static std::string crlf() ; static const std::string & crlf() ;
void applyEvent( const Reply & event ) ; void applyEvent( const Reply & event ) ;
static bool parseReply( Reply & , const std::string & , std::string & ) ; static bool parseReply( Reply & , const std::string & , std::string & ) ;
void doCallback( bool , const std::string & ) ; void doCallback( bool , bool , const std::string & ) ;
G::Strings serverAuthMechanisms( const ClientProtocolReply & reply ) const ;
void onTimeout() ;
private: private:
enum State { sStart , sSentEhlo , sSentHelo , sSentMail , enum State { sStart , sSentEhlo , sSentHelo , sAuth1 , sAuth2 , sSentMail ,
sSentRcpt , sSentData , sData , sDone , sEnd , sReset } ; sSentRcpt , sSentData , sData , sDone , sEnd , sReset } ;
Sender & m_sender ; Sender & m_sender ;
std::string m_thishost ; std::string m_thishost ;
@ -175,7 +202,13 @@ private:
bool m_server_has_8bitmime ; bool m_server_has_8bitmime ;
bool m_said_hello ; bool m_said_hello ;
bool m_message_is_8bit ; bool m_message_is_8bit ;
std::string m_message_authentication ;
Reply m_reply ; Reply m_reply ;
bool m_authenticated_with_server ;
std::string m_auth_mechanism ;
std::auto_ptr<SaslClient> m_sasl ;
bool m_must_authenticate ;
unsigned int m_timeout ;
} ; } ;
#endif #endif

View File

@ -107,9 +107,12 @@ std::string GSmtp::FileStore::x()
} }
//static //static
std::string GSmtp::FileStore::format() std::string GSmtp::FileStore::format( int n )
{ {
return "#2821.2" ; if( n == 0 )
return "#2821.3" ; // current -- includes message authentication and client ip
else
return "#2821.2" ; // old
} }
//static //static
@ -168,7 +171,10 @@ G::Path GSmtp::FileStore::fullPath( const std::string & filename ) const
unsigned long GSmtp::FileStore::newSeq() unsigned long GSmtp::FileStore::newSeq()
{ {
return m_seq++ ; m_seq++ ;
if( m_seq == 0UL )
m_seq++ ;
return m_seq ;
} }
bool GSmtp::FileStore::empty() const bool GSmtp::FileStore::empty() const

View File

@ -63,7 +63,7 @@ public:
// directory by other processes. // directory by other processes.
unsigned long newSeq() ; unsigned long newSeq() ;
// Hands out a new sequence number. // Hands out a new non-zero sequence number.
std::auto_ptr<std::ostream> stream( const G::Path & path ); std::auto_ptr<std::ostream> stream( const G::Path & path );
// Returns a stream to the given content. // Returns a stream to the given content.
@ -93,9 +93,10 @@ public:
static std::string x() ; static std::string x() ;
// Returns the prefix for envelope header lines. // Returns the prefix for envelope header lines.
static std::string format() ; static std::string format( int n = 0 ) ;
// Returns an identifier for the storage format // Returns an identifier for the storage format
// implemented by this class. // implemented by this class. If n is -1 then
// it returns the previous format (etc.).
private: private:
static void checkPath( const G::Path & dir ) ; static void checkPath( const G::Path & dir ) ;

View File

@ -54,6 +54,7 @@ class GSmtp::MessageStore
{ {
public: public:
G_EXCEPTION( WriteError , "error writing file" ) ; G_EXCEPTION( WriteError , "error writing file" ) ;
G_EXCEPTION( StorageError , "error storing message" ) ;
G_EXCEPTION( NoInstance , "no message store instance" ) ; G_EXCEPTION( NoInstance , "no message store instance" ) ;
G_EXCEPTION( FormatError , "format error" ) ; G_EXCEPTION( FormatError , "format error" ) ;
class IteratorImp // A base class for MessageStore::Iterator implementations. class IteratorImp // A base class for MessageStore::Iterator implementations.

View File

@ -28,6 +28,7 @@
#include "gmemory.h" #include "gmemory.h"
#include "gprocess.h" #include "gprocess.h"
#include "gfile.h" #include "gfile.h"
#include "gxtext.h"
#include "gassert.h" #include "gassert.h"
#include "glog.h" #include "glog.h"
#include <iostream> #include <iostream>
@ -37,8 +38,8 @@ bool GSmtp::NewFile::m_preprocess = false ;
G::Path GSmtp::NewFile::m_preprocessor ; G::Path GSmtp::NewFile::m_preprocessor ;
GSmtp::NewFile::NewFile( const std::string & from , FileStore & store ) : GSmtp::NewFile::NewFile( const std::string & from , FileStore & store ) :
m_from(from) ,
m_store(store), m_store(store),
m_from(from) ,
m_eight_bit(false) m_eight_bit(false)
{ {
m_seq = store.newSeq() ; m_seq = store.newSeq() ;
@ -72,17 +73,17 @@ void GSmtp::NewFile::addText( const std::string & line )
bool GSmtp::NewFile::isEightBit( const std::string & line ) bool GSmtp::NewFile::isEightBit( const std::string & line )
{ {
const size_t n = line.length() ; std::string::const_iterator end = line.end() ;
for( size_t i = 0U ; i < n ; --i ) for( std::string::const_iterator p = line.begin() ; p != end ; ++p )
{ {
const unsigned char c = static_cast<unsigned char>(line.at(i)) ; const unsigned char c = static_cast<unsigned char>(*p) ;
if( c > 0x7fU ) if( c > 0x7fU )
return true ; return true ;
} }
return false ; return false ;
} }
void GSmtp::NewFile::store() bool GSmtp::NewFile::store( const std::string & auth_id , const std::string & client_ip )
{ {
// flush the content file // flush the content file
// //
@ -99,17 +100,19 @@ void GSmtp::NewFile::store()
std::string reason = p0.str() ; std::string reason = p0.str() ;
{ {
std::auto_ptr<std::ostream> envelope_stream = m_store.stream( p0 ) ; std::auto_ptr<std::ostream> envelope_stream = m_store.stream( p0 ) ;
ok = saveEnvelope( *(envelope_stream.get()) , p0.str() ) ; ok = saveEnvelope( *(envelope_stream.get()) , p0.str() , auth_id , client_ip ) ;
} }
// shell out to a message pre-processor // shell out to a message pre-processor
// //
bool cancelled = false ;
if( ok ) if( ok )
{ {
ok = preprocess( m_content_path ) ; ok = preprocess( m_content_path , cancelled ) ;
if( !ok ) if( !ok )
reason = "pre-processing failed" ; reason = "pre-processing failed" ;
} }
G_ASSERT( !(ok&&cancelled) ) ;
// deliver to local mailboxes // deliver to local mailboxes
// //
@ -124,18 +127,32 @@ void GSmtp::NewFile::store()
{ {
G_ASSERT( m_content_path.str().length() != 0U ) ; G_ASSERT( m_content_path.str().length() != 0U ) ;
G::File::remove( m_content_path , G::File::NoThrow() ) ; G::File::remove( m_content_path , G::File::NoThrow() ) ;
throw GSmtp::MessageStore::WriteError( reason ) ; if( !cancelled )
throw GSmtp::MessageStore::StorageError( reason ) ;
} }
return cancelled ;
} }
bool GSmtp::NewFile::preprocess( const G::Path & path ) bool GSmtp::NewFile::preprocess( const G::Path & path , bool & cancelled )
{ {
if( m_preprocess ) if( m_preprocess )
{ {
G_LOG( "GSmtp::NewFile::preprocess: " << m_preprocessor << " " << path ) ; G_LOG( "GSmtp::NewFile::preprocess: " << m_preprocessor << " " << path ) ;
int exit_code = G::Process::spawn( m_preprocessor , path.str() ) ; int exit_code = G::Process::spawn( m_preprocessor , path.str() ) ;
G_LOG( "GSmtp::NewFile::preprocess: exit status " << exit_code ) ; G_LOG( "GSmtp::NewFile::preprocess: exit status " << exit_code ) ;
if( exit_code != 0 ) if( exit_code == 100 )
{
// a special exit-code for pre-processors which
// do their own message handling -- the pre-processor
// should delete the files before returning this
// exit code
//
cancelled = true ;
G_LOG( "GSmtp::NewFile: message processing cancelled by preprocessor" ) ;
return false ;
}
else if( exit_code != 0 )
{ {
G_WARNING( "GSmtp::NewFile::preprocess: pre-processing failed: exit code " << exit_code ) ; G_WARNING( "GSmtp::NewFile::preprocess: pre-processing failed: exit code " << exit_code ) ;
return false ; return false ;
@ -144,7 +161,7 @@ bool GSmtp::NewFile::preprocess( const G::Path & path )
return true ; return true ;
} }
void GSmtp::NewFile::deliver( const G::Strings & to , void GSmtp::NewFile::deliver( const G::Strings & /*to*/ ,
const G::Path & content_path , const G::Path & envelope_path_now , const G::Path & content_path , const G::Path & envelope_path_now ,
const G::Path & envelope_path_later ) const G::Path & envelope_path_later )
{ {
@ -158,7 +175,8 @@ void GSmtp::NewFile::deliver( const G::Strings & to ,
G::File::copy( envelope_path_now.str() , envelope_path_later.str()+".local" ) ; G::File::copy( envelope_path_now.str() , envelope_path_later.str()+".local" ) ;
} }
bool GSmtp::NewFile::saveEnvelope( std::ostream & stream , const std::string & where ) const bool GSmtp::NewFile::saveEnvelope( std::ostream & stream , const std::string & where ,
const std::string & auth_id , const std::string & client_ip ) const
{ {
G_LOG( "GSmtp::NewMessage: envelope file: " << where ) ; G_LOG( "GSmtp::NewMessage: envelope file: " << where ) ;
@ -178,14 +196,17 @@ bool GSmtp::NewFile::saveEnvelope( std::ostream & stream , const std::string & w
for( ; to_p != m_to_remote.end() ; ++to_p ) for( ; to_p != m_to_remote.end() ; ++to_p )
stream << x << "To-Remote: " << *to_p << crlf() ; stream << x << "To-Remote: " << *to_p << crlf() ;
} }
stream << x << "Authentication: " << Xtext::encode(auth_id) << crlf() ;
stream << x << "Client: " << client_ip << crlf() ;
stream << x << "End: 1" << crlf() ; stream << x << "End: 1" << crlf() ;
stream.flush() ; stream.flush() ;
return stream.good() ; return stream.good() ;
} }
std::string GSmtp::NewFile::crlf() const const std::string & GSmtp::NewFile::crlf() const
{ {
return std::string( "\015\012" ) ; static std::string s( "\015\012" ) ;
return s ;
} }
unsigned long GSmtp::NewFile::id() const unsigned long GSmtp::NewFile::id() const

View File

@ -59,11 +59,13 @@ public:
virtual void addText( const std::string & line ) ; virtual void addText( const std::string & line ) ;
// Adds a line of content. // Adds a line of content.
virtual void store() ; virtual bool store( const std::string & auth_id , const std::string & client_ip ) ;
// Stores the message in the message store. // Stores the message in the message store.
// Returns true if storage was deliberately
// cancelled.
virtual unsigned long id() const ; virtual unsigned long id() const ;
// Returns the message's unique identifier. // Returns the message's unique non-zero identifier.
static void setPreprocessor( const G::Path & exe ) ; static void setPreprocessor( const G::Path & exe ) ;
// Defines a program which is used for pre-processing // Defines a program which is used for pre-processing
@ -82,11 +84,12 @@ private:
static G::Path m_preprocessor ; static G::Path m_preprocessor ;
private: private:
bool saveEnvelope( std::ostream & stream , const std::string & where ) const ; bool saveEnvelope( std::ostream & , const std::string & where ,
std::string crlf() const ; const std::string & auth_id , const std::string & client_ip ) const ;
const std::string & crlf() const ;
static bool isEightBit( const std::string & line ) ; static bool isEightBit( const std::string & line ) ;
void deliver( const G::Strings & , const G::Path & , const G::Path & , const G::Path & ) ; void deliver( const G::Strings & , const G::Path & , const G::Path & , const G::Path & ) ;
bool preprocess( const G::Path & ) ; bool preprocess( const G::Path & , bool & ) ;
} ; } ;
#endif #endif

View File

@ -47,11 +47,13 @@ public:
virtual void addText( const std::string & line ) = 0 ; virtual void addText( const std::string & line ) = 0 ;
// Adds a line of content. // Adds a line of content.
virtual void store() = 0 ; virtual bool store( const std::string & auth_id , const std::string & client_ip ) = 0 ;
// Stores the message in the message store. // Stores the message in the message store.
// Returns true if storage was deliberately
// cancelled.
virtual unsigned long id() const = 0 ; virtual unsigned long id() const = 0 ;
// Returns the message's unique identifier. // Returns the message's unique non-zero identifier.
virtual ~NewMessage() ; virtual ~NewMessage() ;
// Destructor. // Destructor.

View File

@ -51,6 +51,10 @@ public:
{ {
public: virtual ~Callback() ; public: virtual ~Callback() ;
public: virtual void processDone( bool success , unsigned long id , const std::string & reason ) = 0 ; public: virtual void processDone( bool success , unsigned long id , const std::string & reason ) = 0 ;
// Signals that ProtocolMessage::process() has completed.
// As a special case, if success is true and id is zero then
// the message processing was cancelled.
private: void operator=( const Callback & ) ; // not implemented private: void operator=( const Callback & ) ; // not implemented
} ; } ;
@ -86,12 +90,19 @@ public:
// Precondition: at least one // Precondition: at least one
// successful addTo() call // successful addTo() call
virtual void process( Callback & callback ) = 0 ; virtual void process( Callback & callback , const std::string & authenticated_client_id ,
// Starts asynchronous processing of the const std::string & peer_ip_address ) = 0 ;
// message. Once processing is complete the // Starts asynchronous processing of the
// message state is cleared and the callback // message. Once processing is complete the
// is triggered. The callback may be called // message state is cleared and the callback
// before process() returns. // is triggered. The callback may be called
// before process() returns.
//
// The client-id parameter is used to propogate
// authentication information from the SMTP
// AUTH command into individual messages.
// It is the empty string for unauthenticated
// clients. See also GSmtp::Sasl::id().
private: private:
void operator=( const ProtocolMessage & ) ; // not implemented void operator=( const ProtocolMessage & ) ; // not implemented

View File

@ -67,17 +67,18 @@ void GSmtp::ProtocolMessageForward::addText( const std::string & line )
m_pm.addText( line ) ; m_pm.addText( line ) ;
} }
void GSmtp::ProtocolMessageForward::process( ProtocolMessage::Callback & callback ) void GSmtp::ProtocolMessageForward::process( ProtocolMessage::Callback & callback , const std::string & auth_id ,
const std::string & client_ip )
{ {
m_callback = & callback ; m_callback = & callback ;
m_pm.process( *this ) ; m_pm.process( *this , auth_id , client_ip ) ;
} }
void GSmtp::ProtocolMessageForward::processDone( bool success , unsigned long id , const std::string & reason_in ) void GSmtp::ProtocolMessageForward::processDone( bool success , unsigned long id , const std::string & reason_in )
{ {
std::string reason( reason_in ) ; std::string reason( reason_in ) ;
bool nothing_to_do = false ; bool nothing_to_do = success && id == 0UL ;
if( success ) if( success && id != 0UL )
{ {
m_id = id ; m_id = id ;
success = forward( id , nothing_to_do , &reason ) ; success = forward( id , nothing_to_do , &reason ) ;

View File

@ -39,10 +39,14 @@ namespace GSmtp
} ; } ;
// Class: GSmtp::ProtocolMessageForward // Class: GSmtp::ProtocolMessageForward
// Description: A concrete implementation of the // Description: A concrete implementation of the ProtocolMessage
// ProtocolMessage interface which stores incoming // interface which stores incoming messages in the message store
// messages in the message store and then immediately // and then immediately forwards them on to the downstream server.
// forwards them on to the downstream server. //
// The implementation delegates to an instance of the ProtocolMessageStore
// class (ie. its sibling class) to do the storage, and to an instance
// of the Client class to do the forwarding.
//
// See also: ProtocolMessageStore // See also: ProtocolMessageStore
// //
class GSmtp::ProtocolMessageForward : public GSmtp:: ProtocolMessage , class GSmtp::ProtocolMessageForward : public GSmtp:: ProtocolMessage ,
@ -71,8 +75,9 @@ public:
virtual void addText( const std::string & ) ; virtual void addText( const std::string & ) ;
// See ProtocolMessage. // See ProtocolMessage.
virtual void process( ProtocolMessage::Callback & callback ) ; virtual void process( ProtocolMessage::Callback & callback , const std::string & auth_id ,
// See ProtocolMessage. const std::string & client_ip ) ;
// See ProtocolMessage.
private: private:
void operator=( const ProtocolMessageForward & ) ; // not implemented void operator=( const ProtocolMessageForward & ) ; // not implemented

View File

@ -101,16 +101,19 @@ void GSmtp::ProtocolMessageStore::addText( const std::string & line )
m_msg->addText( line ) ; m_msg->addText( line ) ;
} }
void GSmtp::ProtocolMessageStore::process( Callback & callback ) void GSmtp::ProtocolMessageStore::process( Callback & callback , const std::string & auth_id ,
const std::string & client_ip )
{ {
try try
{ {
G_ASSERT( m_msg.get() != NULL ) ; G_ASSERT( m_msg.get() != NULL ) ;
unsigned long id = 0UL ; unsigned long id = 0UL ;
bool cancelled = false ;
if( m_msg.get() != NULL ) if( m_msg.get() != NULL )
{ {
m_msg->store() ; cancelled = m_msg->store( auth_id , client_ip ) ;
id = m_msg->id() ; if( !cancelled )
id = m_msg->id() ;
} }
clear() ; clear() ;
callback.processDone( true , id , std::string() ) ; callback.processDone( true , id , std::string() ) ;

View File

@ -66,8 +66,9 @@ public:
virtual void addText( const std::string & ) ; virtual void addText( const std::string & ) ;
// See ProtocolMessage. // See ProtocolMessage.
virtual void process( ProtocolMessage::Callback & callback ) ; virtual void process( ProtocolMessage::Callback & callback , const std::string & auth_id ,
// See ProtocolMessage. const std::string & client_ip ) ;
// See ProtocolMessage.
private: private:
void operator=( const ProtocolMessageStore & ) ; // not implemented void operator=( const ProtocolMessageStore & ) ; // not implemented

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