This commit is contained in:
Graeme Walker 2002-03-17 12:00:00 +00:00
parent 2911440f23
commit 4905d3db56
244 changed files with 5195 additions and 2174 deletions

View File

@ -2,3 +2,10 @@
AUTHORS AUTHORS
======= =======
Graeme Walker <graeme_walker@users.sourceforge.net> Graeme Walker <graeme_walker@users.sourceforge.net>
The source in "glib/gmd5.cpp" is "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" by incorporating
the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" which
is "Copyright (C) 1991, RSA Data Security, Inc. All rights reserved".

View File

@ -1,6 +1,22 @@
E-MailRelay Change Log E-MailRelay Change Log
====================== ======================
0.9.6 -> 0.9.7
--------------
* CRAM-MD5 authentication mechanism added.
* Revoke root permissions at start up, and reclaim them when needed.
* Allow mail pre-processing ("--filter") when started as root.
* Domain-override switch ("--domain") added.
* Non-privileged user switch ("--user") added.
* Better handling of NarrowPipe exception (ie. 8-bit message to 7-bit server).
* Allow null return path in MAIL-FROM.
* Reject recipients which look like "<user>@localhost" (as used by fetchmail for local delivery).
* Treat recipients which look like "postmaster@localhost" or "postmaster@<fqdn>" as local postmaster.
* Optional timestamps on log output ("--log-time").
* Fix EHLO to HELO fallback for 501/502 responses in client protocol.
* Submission utility "emailrelay-submit" added.
* HTML4.0 compliant HTML documentation, using CSS.
0.9.5 -> 0.9.6 0.9.5 -> 0.9.6
-------------- --------------
* SMTP AUTHentication extension -- LOGIN mechanism only. * SMTP AUTHentication extension -- LOGIN mechanism only.

7
NEWS
View File

@ -1,2 +1,7 @@
no news
To do...
* optionally enforce authentication by clients
* OS-X port
* better windows gui (esp. client side)
* sample pre-processor script for spamassassin

View File

@ -1,7 +1,7 @@
noinst_SCRIPTS = emailrelay-doxygen-filter.sh emailrelay-test.sh emailrelay-soak.sh noinst_SCRIPTS = emailrelay-doxygen-filter.sh emailrelay-test.sh emailrelay-soak.sh
libexec_SCRIPTS = emailrelay.sh libexec_SCRIPTS = emailrelay.sh
pkgdata_DATA = emailrelay-notify.sh emailrelay-deliver.sh emailrelay-process.sh pkgdata_DATA = emailrelay-notify.sh emailrelay-deliver.sh emailrelay-process.sh
EXTRA_DIST = emailrelay-doxygen-filter.sh_ emailrelay-test.sh_ emailrelay-soak.sh_ emailrelay.sh_ txt2html.sh_ emailrelay-notify.sh_ emailrelay-deliver.sh_ emailrelay-process.sh_ EXTRA_DIST = emailrelay-doxygen-filter.sh_ emailrelay-test.sh_ emailrelay-soak.sh_ emailrelay.sh_ txt2html.sh_ txt2mu.sh_ mu2html.sh_ expand.sh_ emailrelay-notify.sh_ emailrelay-deliver.sh_ emailrelay-process.sh_
CLEANFILES = $(noinst_SCRIPTS) $(libexec_SCRIPTS) $(pkgdata_DATA) CLEANFILES = $(noinst_SCRIPTS) $(libexec_SCRIPTS) $(pkgdata_DATA)
TESTS = emailrelay-test.sh TESTS = emailrelay-test.sh
SUFFIXES = .sh_ .sh SUFFIXES = .sh_ .sh

View File

@ -72,7 +72,7 @@ VERSION = @VERSION@
noinst_SCRIPTS = emailrelay-doxygen-filter.sh emailrelay-test.sh emailrelay-soak.sh noinst_SCRIPTS = emailrelay-doxygen-filter.sh emailrelay-test.sh emailrelay-soak.sh
libexec_SCRIPTS = emailrelay.sh libexec_SCRIPTS = emailrelay.sh
pkgdata_DATA = emailrelay-notify.sh emailrelay-deliver.sh emailrelay-process.sh pkgdata_DATA = emailrelay-notify.sh emailrelay-deliver.sh emailrelay-process.sh
EXTRA_DIST = emailrelay-doxygen-filter.sh_ emailrelay-test.sh_ emailrelay-soak.sh_ emailrelay.sh_ txt2html.sh_ emailrelay-notify.sh_ emailrelay-deliver.sh_ emailrelay-process.sh_ EXTRA_DIST = emailrelay-doxygen-filter.sh_ emailrelay-test.sh_ emailrelay-soak.sh_ emailrelay.sh_ txt2html.sh_ txt2mu.sh_ mu2html.sh_ expand.sh_ emailrelay-notify.sh_ emailrelay-deliver.sh_ emailrelay-process.sh_
CLEANFILES = $(noinst_SCRIPTS) $(libexec_SCRIPTS) $(pkgdata_DATA) CLEANFILES = $(noinst_SCRIPTS) $(libexec_SCRIPTS) $(pkgdata_DATA)
TESTS = emailrelay-test.sh TESTS = emailrelay-test.sh
SUFFIXES = .sh_ .sh SUFFIXES = .sh_ .sh

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -110,7 +110,7 @@ RunPoke()
Content() Content()
{ {
echo "To: recipient-1@localhost, recipient-2@localhost" echo "To: recipient-1@f.q.d.n, recipient-2@f.q.d.n"
echo "Subject: test message 1" echo "Subject: test message 1"
echo "From: sender" echo "From: sender"
echo " " echo " "
@ -123,8 +123,8 @@ Envelope()
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@f.q.d.n"
echo "X-MailRelay-To-Remote: recipient-2@localhost" echo "X-MailRelay-To-Remote: recipient-2@f.q.d.n"
echo "X-MailRelay-Authentication: " echo "X-MailRelay-Authentication: "
echo "X-MailRelay-Client: 127.0.0.1" echo "X-MailRelay-Client: 127.0.0.1"
echo "X-MailRelay-End: 1" echo "X-MailRelay-End: 1"
@ -162,18 +162,22 @@ CreateAuth()
{ {
mkdir -p "${base_dir}" mkdir -p "${base_dir}"
# encrypted version "joes_password" provided by emailrelay-passwd
key="2168297042.2818429713.1297528852.2023008371.2713943401.1997919265.1829599518.235099638"
file="${base_dir}/server.auth" file="${base_dir}/server.auth"
echo "# server.auth" > ${file} echo "# server.auth" > ${file}
echo "login server fred freds_password" >> ${file} echo "LOGIN server fred freds_password" >> ${file}
echo "login server joe joe+00s_password" >> ${file} echo "CRAM-MD5 server joe ${key}" >> ${file}
echo "login client dummy pwd" >> ${file} echo "CRAM-MD5 server brian 1.1.1.1.2.2.2.2" >> ${file}
echo "cram-md5 client dummy digest" >> ${file}
file="${base_dir}/client.auth" file="${base_dir}/client-fred.auth"
echo "# client.auth" > ${file} echo "# client-fred.auth" > ${file}
echo "cram-md5 client foo bar" >> ${file} echo "LOGIN client fred freds_password" >> ${file}
echo "login client joe joe+00s_password" >> ${file}
echo "login server abc def" >> ${file} file="${base_dir}/client-joe.auth"
echo "# client-joe.auth" > ${file}
echo "CRAM-MD5 client joe ${key}" >> ${file}
} }
trap "Trap ; exit" 1 2 3 13 15 trap "Trap ; exit" 1 2 3 13 15
@ -182,8 +186,8 @@ trap "Trap 0 ; exit" 0
StartTimer StartTimer
CreateAuth 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 --client-auth ${base_dir}/client-joe.auth"
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}3 store-3 log-3 pid-3 "--immediate --forward-to localhost:${pp}4 --filter ${null_filter} --client-auth ${base_dir}/client-fred.auth --server-auth ${base_dir}/server.auth"
RunServer ${pp}4 store-4 log-4 pid-4 "--server-auth ${base_dir}/server.auth" 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

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

89
bin/expand.sh_ Normal file
View File

@ -0,0 +1,89 @@
#!/bin/sh
#
# Copyright (C) 2001-2002 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.
#
# ===
#
# expand.sh
#
# Expands "#include#<file>#" directives.
#
# Only does one sustitution per line. Directives which start the line are
# multi-line. Those within a line are one-line, expanded in-place.
#
# The "-t" switch can be used to suppress expansion of files
# with an extension of ".html".
#
# Bugs: Does not do nested expansion. Only supports one include statement
# per line.
#
# usage: expand.sh [-a <awk>] [-t]
#
awk="gawk"
if test "${1}" = "-a"
then
shift
awk="${1}"
shift
fi
expand_html="1"
if test "${1}" = "-t"
then
shift
expand_html="0"
fi
${awk} -v expand_html="${expand_html}" -v cat="${awk} '{print}'" '
{
line = $0
if( match(line,"#include#[^#]*#") )
{
rstart = RSTART
directive = substr(line,RSTART,RLENGTH)
path = substr(line,RSTART+9,RLENGTH-10)
if( !expand_html && match(path,".html$") )
{
print line
}
else
{
head = substr(line,1,rstart-1)
if( match(head,"^[[:space:]]*$") )
{
system( cat " " path )
}
else
{
getline text <path
if( length(text) == 0 )
printf( "expand.sh: warning: line %d: empty text sustitution for %s\n" , NR , path ) >"/dev/fd/2"
sub( directive , text , line )
print line
}
}
}
else
{
print line
}
}
' $@

279
bin/mu2html.sh_ Normal file
View File

@ -0,0 +1,279 @@
#!/bin/sh
#
# Copyright (C) 2001-2002 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.
#
# ===
#
# mu2html.sh
#
# Mark-up to html converter. Converts the output of "txt2mu.sh"
# into html. (Also see "index.sh".)
#
# Does some in-line formatting independently of the line-based
# mark-up in the input. For example, it converts quoted words into
# "<em></em>" tags, and it converts "*foo* [bar]" text into
# hypertext links.
#
# The "-x" flag suppresses the output of html header and
# footer sections. This is useful when the output is to be
# spliced into another html document.
#
# usage: mu2html.sh [-a <awk>] [-x] [<title> [<stylesheet>]]
#
# (If the title is not supplied then the input is copied
# to a temporary file in order to extract the H1 header
# text for the title.)
#
awk="gawk"
if test "${1}" = "-a"
then
shift
if test "${1}" != "" ; then awk="${1}" ; fi
shift
fi
full="1"
if test "${1}" = "-x"
then
full="0"
shift
fi
title="${1}"
stylesheet="${2}"
if test "${stylesheet}" != "" -a \! -f "${stylesheet}"
then
echo `basename $0`: warning: missing stylesheet: ${stylesheet} >&2
fi
Main()
{
${awk} -v prefix="`basename $0`" -v title="${1}" -v stylesheet="${2}" -v full="${3}" '
BEGIN {
if( full )
{
colour = "#ffffff"
dtd_name = "-//W3C//DTD HTML 4.01//EN"
dtd_ref = "http://www.w3.org/TR/html4/strict.dtd"
printf( "<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n" , dtd_name , dtd_ref )
printf( "<html>\n" )
printf( " <head>\n" )
printf( " <title>%s</title>\n" , title )
printf( " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n" )
if( length(stylesheet) )
printf( " <link rel=\"stylesheet\" href=\"%s\" type=\"text/css\">\n" , stylesheet )
printf( " </head>\n" )
printf( " <body bgcolor=\"%s\">\n" , colour )
printf( " <!-- index:0::::%s -->\n" , title )
printf( " <div class=\"div-main\">\n" )
}
}
function arg1( type )
{
sub( "[^,]*," , "" , type )
sub( ",.*" , "" , type )
return type
}
function arg2( type )
{
sub( "[^,]*," , "" , type )
sub( "[^,]*," , "" , type )
sub( ",.*" , "" , type )
return type
}
function escape( line )
{
gsub( "&" , "\\&amp;" , line )
gsub( "<" , "\\&lt;" , line )
gsub( ">" , "\\&gt;" , line )
return line
}
function dequote( line )
{
quote = "\""
not_quote = "[^" quote "]"
start_tag="<em class=\"quote\">"
end_tag="</em>"
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
}
function fn( line )
{
gsub( "[^[:space:]][^[:space:]]*\\(\\)" , "<em class=\"fn\">&</em>" , line )
return line
}
{
pos = index( $0 , ":" )
type = substr( $0 , 1 , pos )
tail = substr( $0 , pos+1 )
etail_raw = escape(tail)
etail = fn(dequote(escape(tail)))
# h1
if( match(type,"^h1[:,]") )
{
printf( " <h1><a class=\"a-header\" name=\"H_%d\">%s</a></h1> " , arg1(type) , etail )
printf( "<!-- index:1:H:%d::%s -->\n" , arg1(type) , etail )
}
# h2
else if( match(type,"^h2[:,]") )
{
printf( " <h2><a class=\"a-header\" name=\"SH_%d_%d\">%s</a></h2> " , arg1(type) , arg2(type) , etail )
printf( "<!-- index:2:SH:%d:%d:%s -->\n" , arg1(type) , arg2(type) , etail )
}
# item
else if( match(type,"^item,1[:,]") )
printf( " <ul>\n <li>%s</li>\n" , etail )
else if( match(type,"^item[:,]") )
printf( " <li>%s</li>\n" , etail )
else if( match(type,"^item-end[:,]") )
printf( " </ul>\n" , etail )
# item-numbered
else if( match(type,"^item-numbered,1[:,]") )
printf( " <ol>\n <li>%s</li>\n" , etail )
else if( match(type,"^item-numbered[:,]") )
printf( " <li>%s</li>\n" , etail )
else if( match(type,"^item-numbered-end[:,]") )
printf( " </ol>\n" , etail )
# item-outer
else if( match(type,"^item-outer,1[:,]") )
printf( " <ul>\n <li>%s</li>\n" , etail )
else if( match(type,"^item-outer[:,]") )
printf( " <li>%s</li>\n" , etail )
else if( match(type,"^item-outer-end[:,]") )
printf( " </ul>\n" , etail )
# item-inner
else if( match(type,"^item-inner,1[:,]") )
printf( " <ul>\n <li>%s</li>\n" , etail )
else if( match(type,"^item-inner[:,]") )
printf( " <li>%s</li>\n" , etail )
else if( match(type,"^item-inner-end[:,]") )
printf( " </ul>\n" , etail )
# item-name
else if( match(type,"^item-name,1[:,]") )
printf( " <dl>\n <dt>%s</dt>\n" , etail )
else if( match(type,"^item-name[:,]") )
printf( " <dt>%s</dt>\n" , etail )
else if( match(type,"^item-name-end[:,]") )
printf( " </dl>\n" , etail )
# item-detail
else if( match(type,"^item-detail,1[:,]") )
printf( " <dd>\n <p>\n %s\n" , etail )
else if( match(type,"^item-detail[:,]") )
printf( " %s\n" , etail )
else if( match(type,"^item-detail-end[:,]") )
printf( " </p>\n </dd>\n" )
else if( match(type,"^item-detail-blank[:,]") )
printf( " </p>\n <p>\n" )
# code
else if( match(type,"^code,1[:,]") )
printf( " <div class=\"div-pre\">\n <pre>%s" , etail_raw )
else if( match(type,"^code[:,]") )
printf( "\n%s" , etail_raw )
else if( match(type,"^code-end[:,]") )
printf( "</pre>\n </div><!-- div-pre -->\n" )
# text
else if( match(type,"^text,1[:,]") )
printf( " <p>\n %s\n" , etail )
else if( match(type,"^text[:,]") )
printf( " %s\n" , etail )
else if( match(type,"^text-end[:,]") )
printf( " </p>\n" , etail )
# footer-text
else if( match(type,"^footer,1[:,]") )
printf( " <div class=\"div-footer\">\n <p>\n %s\n" , etail )
else if( match(type,"^footer[:,]") )
printf( " %s\n" , etail )
else if( match(type,"^footer-end[:,]") )
printf( " </p>\n </div><!-- div-footer -->\n" , etail )
# citation-text
else if( match(type,"^citation,1[:,]") )
printf( " <p class=\"citation\">\n %s\n" , etail )
else if( match(type,"^citation[:,]") )
printf( " %s\n" , etail )
else if( match(type,"^citation-end[:,]") )
printf( " </p>\n" , etail )
# author-text
else if( match(type,"^author,1[:,]") )
printf( " <p class=\"author\">\n %s\n" , etail )
else if( match(type,"^author[:,]") )
printf( " %s\n" , etail )
else if( match(type,"^author-end[:,]") )
printf( " </p>\n" , etail )
# html
else if( match(type,"^html[:,]") )
printf( "%s\n" , tail )
# image
else if( match(type,"^image[:,]") )
printf( "<img src=\"%s\">\n" , tail )
# blank
else if( match(type,"^blank[:,]") )
printf( "\n" )
# ignore
else if( match(type,"^ignore") )
printf( "" )
else if( match(type,"[^[:space:]]") )
printf( "%s: unrecognised mark-up tag on line %d: \"%s\"\n" , prefix , NR , type )>"/dev/fd/2"
}
END {
if( full )
{
printf( " </div> <!-- div-main -->\n" )
printf( " </body>\n" )
printf( "</html>\n" )
}
} '
}
Anchorise()
{
sed 's/\*\([^\*]*\)\* \[\([^]]*\)\]/<a class=\"a-href\" href="\2">\1<\/a>/g'
}
if test "${title}" = ""
then
tmp="`basename $0`.tmp"
${awk} '{print}' > ${tmp}
title="`${awk} '/^h1/ { sub(\"[^:]*:\",\"\") ; print ; exit }' ${tmp}`"
${awk} '{print}' ${tmp} | Main "${title}" "${stylesheet}" "${full}" | Anchorise
else
Main "${title}" "${stylesheet}" "${full}" | Anchorise
fi

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -21,459 +21,76 @@
# #
# txt2html.sh # txt2html.sh
# #
# Converts plain-text to html. The plain-text has to use special # Converts specially-formatted plain-text to html.
# formating conventions (see "function process()", Anchorise_1() etc). # Uses "expand.sh", "txt2mu.sh" and "mu2html.sh".
# See also "index.sh".
# #
# Embeds comments in the html output which can be used by "index.sh" # The "-t" (text-mode) switch can be used for
# to create a document index. # non-technical input text.
# #
# Definition lists require a bullet graphic, "graphics/bullet.gif". # The "-x" (exclude) switch excludes html header
# and footer from the output.
# #
# usage: txt2html.sh [-a <awk-binary>] [-x] <input-file> [<title>] # usage: txt2html.sh [-a <awk-binary>] [-v] [-x] [-t] [<input-file> [<stylesheet> [<graphics-dir> [<title>]]]]
#
# The -x switch excludes header and footer stuff.
# #
awk="gawk" awk="gawk"
if test "${1}" = "-a" if test "${1}" = "-a"
then then
shift shift
if test "${1}" != "" if test "${1}" != "" ; then awk="${1}" ; fi
then
awk="${1}"
fi
shift shift
fi fi
full="1" v=""
if test "${1}" = "-x" if test "${1}" = "-v"
then then
shift shift
full="0" v="-v"
fi
x=""
if test "${1}" = "-x"
then
x="-x"
shift
fi
t=""
if test "${1}" = "-t"
then
t="-t"
shift
fi fi
file="${1}" file="${1}"
if test "${file}" = "" stylesheet="${2}"
graphics_dir="${3}"
title="${4}"
if test "${v}" != "" -a "${file}" != ""
then then
echo usage: `basename $0` '<txt-file>' >&2 echo `basename $0`: processing ${file} >&2
exit 2
fi fi
if test \! -f "${file}" if test "${file}" != "" -a \! -f "${file}"
then then
echo `basename $0`: no such file: ${file} >&2 echo `basename $0`: no such file: ${file} >&2
exit 1 exit 1
fi fi
title="`grep -v '^[[:space:]]*$' ${file} | head -1`" if test "${stylesheet}" != "" -a \! -f "${stylesheet}"
if test "${2}" != ""
then then
title="${2}" echo `basename $0`: warning: missing stylesheet: "${stylesheet}" >&2
fi fi
# === if test "${graphics_dir}" = ""
# Include() then
# graphics_dir="graphics"
# Expands #include# directives. Included text is then processed fi
# as plain text, just like the top-level file. An include directive
# within a line (ie. not on the lhs) is treated as an inline
# sustitution, like shell backticks.
#
Include()
{
${awk} -v cat="${awk} '{print}'" '
{
line = $0
if( match(line,"^#include#[^#]*#") )
{
path = substr(line,10,RLENGTH-10)
system( cat " " path )
}
else
{
print line
}
}
'
}
# === txt2mu="`dirname $0`/txt2mu.sh"
# Main() mu2html="`dirname $0`/mu2html.sh"
# expand="`dirname $0`/expand.sh"
# Does the bulk of the conversion. cat ${file} | ${expand} -a "${awk}" ${t} | ${txt2mu} -a "${awk}" ${t} | ${mu2html} -a "${awk}" ${x} "${title}" "${stylesheet}" | ${expand} -a "${awk}"
#
Main()
{
${awk} -v title="${1}" -v full="${2}" -v colour="${3}" '
BEGIN {
if( full )
{
dtd = "-//W3C//DTD HTML 4.01 Transitional//EN"
printf( "<!DOCTYPE HTML PUBLIC \"%s\">\n" , dtd )
printf( "<html>\n" )
printf( "<head>\n" )
printf( "<title>%s</title>\n" , title )
printf( "</head>\n" )
printf( "<body bgcolor=\"%s\">\n" , colour )
printf( "<!-- index:0::::%s -->\n" , title )
}
}
function escape( line )
{
gsub( "&" , "\\&amp;" , line )
gsub( "<" , "\\&lt;" , line )
gsub( ">" , "\\&gt;" , line )
return line
}
function dequote( line )
{
quote = "\""
not_quote = "[^" quote "]"
#start_tag="<kbd><b>"
#end_tag="</b></kbd>"
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
}
function fn( line )
{
gsub( "[^[:space:]][^[:space:]]*\\(\\)" , "<i>&</i>" , line )
return line
}
function output( line )
{
printf( "%s\n" , fn(dequote(escape(line))) )
}
function tagOutput( 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_ )
{
tab = " "
is_blank = match( line , "^ *$" )
is_heading = match( next_ , "^==* *$" )
is_sub_heading = match( next_ , "^--* *$" )
is_list_item = match( line , "^\\* " )
is_definition_term = match( line , "^\\# " )
is_definition_text = match( line , "^ [^- ]" )
is_outer_list_item = match( line , "^+ " )
is_inner_list_item = match( line , "^ - " )
is_sub_list_item = match( line , "^ + " )
is_numbered_item = match( line , "^\\([[:digit:]][[:digit:]]*\\)" )
is_heading_line = match( line , "^==* *$" )
is_sub_heading_line = match( line , "^--* *$" )
is_code = match( line , "^" tab )
if( is_blank )
{
printf( "<br><br>\n" )
}
else if( is_code )
{
tagOutputRaw( line , "pre" )
}
else if( is_definition_term )
{
gsub( "^# " , "" , line )
tagOutput( line , "dt" )
}
else if( is_definition_text )
{
tagOutput( line , "dd" )
}
else if( is_list_item )
{
gsub( "^\\* " , "" , line )
tagOutput( line , "li" )
}
else if( is_outer_list_item )
{
gsub( "^+ " , "" , line )
tagOutput( line , "Li" )
}
else if( is_inner_list_item )
{
gsub( "^ - " , "" , line )
tagOutput( line , "lI" )
}
else if( is_numbered_item )
{
gsub( "^\\([[:digit:]][[:digit:]]*\\) " , "" , line )
tagOutput( line , "LI" )
}
else if( is_heading )
{
major += 1
minor = 0
printf( "<h1><a name=\"H_%d\">%s</a></h1>" , major , line )
printf( "<!-- index:1:H:%d::%s -->\n" , major , line )
}
else if( is_sub_heading )
{
minor += 1
printf( "<h2><a name=\"SH_%d_%d\">%s</a></h2>" , major , minor , line )
printf( "<!-- index:2:SH:%d:%d:%s -->\n" , major , minor , line )
}
else if( !is_heading_line && !is_sub_heading_line )
{
output( line )
}
}
{
if( NR != 1 )
process( previous , $0 )
previous = $0
}
END {
process( previous , "" )
if( full )
{
printf( "</body>\n" )
printf( "</html>\n" )
}
} '
}
# ===
# AugmentLists()
#
# 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()
{
${awk} -v item_tag="${1}" -v list_tag="${2}" -v ignore_1_re="${3}" -v ignore_2_re="${4}" '
{
line = $0
ignore_1 = length(ignore_1_re) && match( line , ignore_1_re )
ignore_2 = length(ignore_2_re) && match( line , ignore_2_re )
ignore = ignore_1 || ignore_2
if( ignore )
{
print
}
else
{
is_list_item = match( line , "^<" item_tag ">.*</" item_tag ">$" )
if( is_list_item && !in_list )
printf( "<%s>\n" , list_tag )
else if( in_list && !is_list_item )
printf( "</%s>\n" , list_tag )
print
in_list = is_list_item
}
} '
}
# ===
# Elide()
#
# Converts repeated lines of <foo>lineN</foo> into
# <foo>
# line1
# line2
# </foo>
#
# Useful for <pre> and <sub>.
#
Elide()
{
${awk} -v tag="${1}" '
{
line = $0
is_tag_line = match( line , "^<" tag ">.*</" tag ">$" )
core = substr( line , length(tag)+3 , length(line)-length(tag)-length(tag)-5 )
if( is_tag_line && !in_tag )
printf( "<%s>%s" , tag , core )
else if( is_tag_line && in_tag )
printf( "\n%s" , core )
else if( !is_tag_line && in_tag )
printf( "</%s>\n%s\n" , tag , line )
else
print line
in_tag = is_tag_line
} '
}
# ===
# Decorate()
#
# Adds additional stuff after a given opening tag
# and optionally before a closing tag. The opening
# tag is expected to be at the start of the line.
#
Decorate()
{
${awk} -v tag="${1}" -v first="${2}" -v second="${3}" '
{
line = $0
sub( "^<" tag ">" , "<" tag ">" first , line )
sub( "</" tag ">" , second "</" tag ">" , line )
print line
} '
}
# ===
# Compress()
#
# Removes blank lines near to headings (etc).
#
Compress()
{
${awk} '
function process( previous , line , next_ )
{
re_blank = "^<br><br>$"
re_heading = "^<[Hh][[:digit:]]>"
re_dd = "^<dd>"
re_pre_start = "^<pre>"
re_pre_end = "</pre>$"
this_is_blank = match(line,re_blank)
next_is_special = match(next_,re_heading) || match(next_,re_dd)
previous_is_special = match(previous,re_heading) || match(previous,re_dd)
next_is_pre_start = match(next_,re_pre_start)
if( this_is_blank && ( next_is_special || previous_is_special ) )
{
}
else if( this_is_blank && next_is_pre_start )
{
}
else
{
print line
}
}
{
if( NR >= 2 )
process( l2 , l1 , $0 )
l2 = l1
l1 = $0
}
END {
process( l2 , l1 , "" )
process( l1 , "" , "" )
}
'
}
# ===
# Anchorise_1()
#
# Converts "*foo* [bar]" to <a href="bar">foo</a>.
#
Anchorise_1()
{
sed 's/\*\([^[:space:]]*\)\* \[\([^[:space:]]*\)\]/<a href="\2">\1<\/a>/g'
}
# ===
# Anchorise_2()
#
# Converts [[-foo-bar-]] to <a href="foo">bar</a>.
# Deprecated.
#
Anchorise_2()
{
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'
}
# ===
# Cat()
#
# An awk version of "cat" (cygwin cat is
# broken).
#
Cat()
{
${awk} '{print}' $@ | tr -d '\015'
}
# ===
# MoveIndex()
#
# Moves the index comments to a line before
# the header, rather than at the end of the
# header line.
#
MoveIndex()
{
${awk} '
{
line = $0
re = "<!-- index:"
pos = match(line,re)
if( pos )
{
head = substr(line,1,pos-1)
tail = substr(line,pos+length(re))
print head
print re tail
}
else
{
print line
}
}
'
}
# ==
colour="#FFFFFF"
Cat "${file}" | \
Include | \
Main "${title}" "${full}" "${colour}" | \
Compress | \
AugmentLists li ul | \
AugmentLists Li ul "^<lI>" "^<br><br>" | \
AugmentLists lI ul | \
AugmentLists LI ol | \
AugmentLists dt dl "^<dd>" "^<br><br>" | \
Elide "sub" | \
Elide "dd" | \
Elide "pre" | \
Decorate dt "<img src=\"graphics/bullet.gif\">\\\&nbsp;" | \
Decorate dd "<p>" "<p>" | \
Anchorise_1 | \
MoveIndex

338
bin/txt2mu.sh_ Normal file
View File

@ -0,0 +1,338 @@
#!/bin/sh
#
# Copyright (C) 2001-2002 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.
#
# ===
#
# txt2mu.sh
#
# Converts specially-formatted plain-text to marked-up text.
# The mark-up process works on complete lines; inline
# markup is handled by later processing (eg. "mu2html.sh").
#
# The "-t" (text-mode) switch modifies the set
# of available styles to suit non-technical texts.
#
# usage: txt2mu.sh [-a <awk-binary>] [-t] [<input-file>]
#
awk="gawk"
if test "${1}" = "-a"
then
shift
if test "${1}" != "" ; then awk="${1}" ; fi
shift
fi
text_mode="0"
if test "${1}" = "-t"
then
shift
text_mode="1"
fi
file="${1}"
# ===
# Main()
#
# Does most of the processing.
#
Main()
{
${awk} -v text_mode="${1}" '
BEGIN { in_footer = 0 }
function output( line )
{
printf( "%s\n" , line )
}
function tagOutput( line , tag )
{
printf( "%s:%s\n" , tag , line )
}
function tagOutputRaw( line , tag )
{
printf( "%s:%s\n" , tag , line )
}
function process( line , next_ )
{
tab = " "
is_blank = match( line , "^[[:space:]]*$" )
is_heading = match( next_ , "^==*[[:space:]]*$" )
is_footer = match( line , "^____*[[:space:]]*$" )
is_sub_heading = match( next_ , "^--*[[:space:]]*$" )
is_item = match( line , "^\\* " )
is_item_name = match( line , "^\\# " )
is_item_detail = match( line , "^ [^- ]" )
is_item_numbered = match( line , "^\\([[:digit:]][[:digit:]]*\\)" )
is_heading_line = match( line , "^==*[[:space:]]*$" )
is_sub_heading_line = match( line , "^--*[[:space:]]*$" )
is_image = match( line , "^[[:space:]]*<<.*>>[[:space:]]*$" )
if( text_mode )
{
is_citation = match( line , "^" tab "[^" tab "]" )
is_author = match( line , "^" tab tab )
is_html = match( line , "^<.*>[[:space:]]*$" )
is_code = 0
is_item_outer = 0
is_item_inner = 0
}
else
{
is_citation = 0
is_author = 0
is_html = 0
is_code = match( line , "^" tab )
is_item_outer = match( line , "^+ " )
is_item_inner = match( line , "^ - " )
}
if( is_footer )
{
in_footer = 1
}
else if( is_code )
{
sub( "^" tab , "" , line )
tagOutputRaw( line , "code" )
}
else if( is_image )
{
sub( "^<<" , "" , line )
sub( ">>[[:space:]]*$" , "" , line )
tagOutputRaw( line , "image" )
}
else if( is_html )
{
tagOutputRaw( line , "html" )
}
else if( is_blank )
{
tagOutput( "" , "blank" )
}
else if( is_item_name )
{
sub( "^# " , "" , line )
tagOutput( line , "item-name" )
}
else if( is_item_detail )
{
sub( "^ " , "" , line )
tagOutput( line , "item-detail" )
}
else if( is_item )
{
sub( "^\\* " , "" , line )
tagOutput( line , "item" )
}
else if( is_item_outer )
{
sub( "^+ " , "" , line )
tagOutput( line , "item-outer" )
}
else if( is_item_inner )
{
sub( "^ - " , "" , line )
tagOutput( line , "item-inner" )
}
else if( is_item_numbered )
{
gsub( "^\\([[:digit:]][[:digit:]]*\\) " , "" , line )
tagOutput( line , "item-numbered" )
}
else if( is_citation )
{
sub( "^" tab , "" , line )
tagOutput( line , "citation" )
}
else if( is_author )
{
sub( "^" tab tab , "" , line )
tagOutput( line , "author" )
}
else if( is_heading )
{
major += 1
minor = 0
h1_tag = "h1" "," major "," minor
tagOutput( line , h1_tag )
}
else if( is_sub_heading )
{
minor += 1
h2_tag = "h2" "," major "," minor
tagOutput( line , h2_tag )
}
else if( !is_heading_line && !is_sub_heading_line )
{
tagOutput( line , in_footer ? "footer" : "text" )
}
}
{
if( NR != 1 )
process( previous , $0 )
previous = $0
}
END {
process( previous , "" )
} '
}
# ===
# Number()
#
# Numbers a set of commonly-tagged lines, and inserts an end
# marker line at the end of the sequence.
#
# The 'ignore' parameters can be used to make sure that
# item lines separated with 'ignore' patterns are
# treated as being contiguous.
#
Number()
{
${awk} -v item_tag="${1}" -v ignore_1="${2}" -v ignore_2="${3}" -v ignore_3="${4}" '
function ignore_line( line )
{
i_0 = match( line , "^ignore" )
i_1 = length(ignore_1) && match( line , "^" ignore_1 "[:,]" )
i_2 = length(ignore_2) && match( line , "^" ignore_2 "[:,]" )
i_3 = length(ignore_3) && match( line , "^" ignore_3 "[:,]" )
return i_0 || i_1 || i_2 || i_3
}
BEGIN {
n = 1
}
{
if( match( $0 , "^" item_tag "[:,]" ) )
{
sub( "^" item_tag , "" )
printf( "%s,%d%s\n" , item_tag , n++ , $0 )
}
else
{
if( !ignore_line($0) )
{
if( n > 1 )
printf( "%s-end:\n" , item_tag )
n = 1
}
print
}
} '
}
# ===
# Compress()
#
# Removes blank lines near to headings (etc) by changing
# the "blank" tag to "ignore,blank".
#
# As a special case, converts single blank lines within an
# "item-detail" block to have a tag of "item-detail-blank"
# rather than "blank".
#
Compress()
{
${awk} '
function process( previous , line , next_ )
{
re_blank = "^blank:"
re_heading = "^h[[:digit:]][:,]"
re_detail = "^item-detail:"
re_pre_start = "^code,1[:,]"
this_is_blank = match(line,re_blank)
next_is_heading = match(next_,re_heading)
previous_is_heading = match(previous,re_heading)
next_is_detail = match(next_,re_detail)
previous_is_detail = match(previous,re_detail)
next_is_pre_start = match(next_,re_pre_start)
if( this_is_blank && ( next_is_heading || previous_is_heading ) )
{
print "ignore," line
}
else if( this_is_blank && !previous_is_detail && next_is_detail )
{
print "ignore," line
}
else if( this_is_blank && previous_is_detail && !next_is_detail )
{
print "ignore," line
}
else if( this_is_blank && next_is_detail && previous_is_detail )
{
print "item-detail-" line
}
else if( this_is_blank && next_is_pre_start )
{
print "ignore," line
}
else
{
print line
}
}
{
if( NR >= 2 )
process( l2 , l1 , $0 )
l2 = l1
l1 = $0
}
END {
process( l2 , l1 , "" )
process( l1 , "" , "" )
} '
}
# ===
# Cat()
#
# An awk version of "cat".
#
Cat()
{
${awk} '{print}' $@ | tr -d '\015'
}
# ==
Cat ${file} | \
Main "${text_mode}" | \
Compress | \
Number "item" | \
Number "item-outer" "item-inner" "blank" | \
Number "item-inner" "blank" | \
Number "item-numbered" | \
Number "item-name" "item-detail" "blank" "item-detail-blank" | \
Number "item-detail" "item-detail-blank" | \
Number "code" "blank" "image" | \
Number "footer" "blank" "image" | \
Number "citation" "blank" | \
Number "author" | \
Number "text" "image"

View File

@ -15,9 +15,6 @@
/* Define if you have the <ndir.h> header file, and it defines `DIR'. */ /* Define if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H #undef HAVE_NDIR_H
/* 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'. */ /* Define if you have the <sys/dir.h> header file, and it defines `DIR'. */
#undef HAVE_SYS_DIR_H #undef HAVE_SYS_DIR_H

93
configure vendored
View File

@ -1124,7 +1124,7 @@ fi
PACKAGE=emailrelay PACKAGE=emailrelay
VERSION=0.9.6 VERSION=0.9.7
if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
{ { echo "$as_me:1130: error: source directory already configured; run \"make distclean\" there first" >&5 { { echo "$as_me:1130: error: source directory already configured; run \"make distclean\" there first" >&5
@ -3453,47 +3453,12 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
cat >conftest.$ac_ext <<_ACEOF
#line 3457 "configure"
#include "confdefs.h"
#include <memory>
int
main ()
{
std::auto_ptr<int> lhs ; const std::auto_ptr<int> & rhs = lhs ; lhs = rhs ;
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:3469: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
echo "$as_me:3472: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -s conftest.$ac_objext'
{ (eval echo "$as_me:3475: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:3478: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
:
else
echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
cat >>confdefs.h <<\EOF
#define HAVE_NONCONST_AUTOPTR 1
EOF
fi
rm -f conftest.$ac_objext conftest.$ac_ext
ac_ext=cc ac_ext=cc
ac_cpp='$CXXCPP $CPPFLAGS' ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
echo "$as_me:3496: checking how to run the C++ preprocessor" >&5 echo "$as_me:3461: checking how to run the C++ preprocessor" >&5
echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6
if test -z "$CXXCPP"; then if test -z "$CXXCPP"; then
if test "${ac_cv_prog_CXXCPP+set}" = set; then if test "${ac_cv_prog_CXXCPP+set}" = set; then
@ -3510,18 +3475,18 @@ do
# On the NeXT, cc -E runs the code through the compiler's parser, # On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case. # not just through cpp. "Syntax error" is here to catch this case.
cat >conftest.$ac_ext <<_ACEOF cat >conftest.$ac_ext <<_ACEOF
#line 3513 "configure" #line 3478 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <assert.h> #include <assert.h>
Syntax error Syntax error
_ACEOF _ACEOF
if { (eval echo "$as_me:3518: \"$ac_cpp conftest.$ac_ext\"") >&5 if { (eval echo "$as_me:3483: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
ac_status=$? ac_status=$?
egrep -v '^ *\+' conftest.er1 >conftest.err egrep -v '^ *\+' conftest.er1 >conftest.err
rm -f conftest.er1 rm -f conftest.er1
cat conftest.err >&5 cat conftest.err >&5
echo "$as_me:3524: \$? = $ac_status" >&5 echo "$as_me:3489: \$? = $ac_status" >&5
(exit $ac_status); } >/dev/null; then (exit $ac_status); } >/dev/null; then
if test -s conftest.err; then if test -s conftest.err; then
ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cxx_preproc_warn_flag
@ -3544,17 +3509,17 @@ rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether non-existent headers # OK, works on sane cases. Now check whether non-existent headers
# can be detected and how. # can be detected and how.
cat >conftest.$ac_ext <<_ACEOF cat >conftest.$ac_ext <<_ACEOF
#line 3547 "configure" #line 3512 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <ac_nonexistent.h> #include <ac_nonexistent.h>
_ACEOF _ACEOF
if { (eval echo "$as_me:3551: \"$ac_cpp conftest.$ac_ext\"") >&5 if { (eval echo "$as_me:3516: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
ac_status=$? ac_status=$?
egrep -v '^ *\+' conftest.er1 >conftest.err egrep -v '^ *\+' conftest.er1 >conftest.err
rm -f conftest.er1 rm -f conftest.er1
cat conftest.err >&5 cat conftest.err >&5
echo "$as_me:3557: \$? = $ac_status" >&5 echo "$as_me:3522: \$? = $ac_status" >&5
(exit $ac_status); } >/dev/null; then (exit $ac_status); } >/dev/null; then
if test -s conftest.err; then if test -s conftest.err; then
ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cxx_preproc_warn_flag
@ -3591,7 +3556,7 @@ fi
else else
ac_cv_prog_CXXCPP=$CXXCPP ac_cv_prog_CXXCPP=$CXXCPP
fi fi
echo "$as_me:3594: result: $CXXCPP" >&5 echo "$as_me:3559: result: $CXXCPP" >&5
echo "${ECHO_T}$CXXCPP" >&6 echo "${ECHO_T}$CXXCPP" >&6
ac_preproc_ok=false ac_preproc_ok=false
for ac_cxx_preproc_warn_flag in '' yes for ac_cxx_preproc_warn_flag in '' yes
@ -3601,18 +3566,18 @@ do
# On the NeXT, cc -E runs the code through the compiler's parser, # On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case. # not just through cpp. "Syntax error" is here to catch this case.
cat >conftest.$ac_ext <<_ACEOF cat >conftest.$ac_ext <<_ACEOF
#line 3604 "configure" #line 3569 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <assert.h> #include <assert.h>
Syntax error Syntax error
_ACEOF _ACEOF
if { (eval echo "$as_me:3609: \"$ac_cpp conftest.$ac_ext\"") >&5 if { (eval echo "$as_me:3574: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
ac_status=$? ac_status=$?
egrep -v '^ *\+' conftest.er1 >conftest.err egrep -v '^ *\+' conftest.er1 >conftest.err
rm -f conftest.er1 rm -f conftest.er1
cat conftest.err >&5 cat conftest.err >&5
echo "$as_me:3615: \$? = $ac_status" >&5 echo "$as_me:3580: \$? = $ac_status" >&5
(exit $ac_status); } >/dev/null; then (exit $ac_status); } >/dev/null; then
if test -s conftest.err; then if test -s conftest.err; then
ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cxx_preproc_warn_flag
@ -3635,17 +3600,17 @@ rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether non-existent headers # OK, works on sane cases. Now check whether non-existent headers
# can be detected and how. # can be detected and how.
cat >conftest.$ac_ext <<_ACEOF cat >conftest.$ac_ext <<_ACEOF
#line 3638 "configure" #line 3603 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <ac_nonexistent.h> #include <ac_nonexistent.h>
_ACEOF _ACEOF
if { (eval echo "$as_me:3642: \"$ac_cpp conftest.$ac_ext\"") >&5 if { (eval echo "$as_me:3607: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
ac_status=$? ac_status=$?
egrep -v '^ *\+' conftest.er1 >conftest.err egrep -v '^ *\+' conftest.er1 >conftest.err
rm -f conftest.er1 rm -f conftest.er1
cat conftest.err >&5 cat conftest.err >&5
echo "$as_me:3648: \$? = $ac_status" >&5 echo "$as_me:3613: \$? = $ac_status" >&5
(exit $ac_status); } >/dev/null; then (exit $ac_status); } >/dev/null; then
if test -s conftest.err; then if test -s conftest.err; then
ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cxx_preproc_warn_flag
@ -3673,7 +3638,7 @@ rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then if $ac_preproc_ok; then
: :
else else
{ { echo "$as_me:3676: error: C++ preprocessor \"$CXXCPP\" fails sanity check" >&5 { { echo "$as_me:3641: error: C++ preprocessor \"$CXXCPP\" fails sanity check" >&5
echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check" >&2;} echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check" >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
fi fi
@ -3685,7 +3650,7 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
cat >conftest.$ac_ext <<_ACEOF cat >conftest.$ac_ext <<_ACEOF
#line 3688 "configure" #line 3653 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <time.h> #include <time.h>
@ -3701,7 +3666,7 @@ fi
rm -f conftest* rm -f conftest*
cat >conftest.$ac_ext <<_ACEOF cat >conftest.$ac_ext <<_ACEOF
#line 3704 "configure" #line 3669 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <time.h> #include <time.h>
@ -3798,7 +3763,7 @@ DEFS=-DHAVE_CONFIG_H
: ${CONFIG_STATUS=./config.status} : ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS" ac_clean_files="$ac_clean_files $CONFIG_STATUS"
{ echo "$as_me:3801: creating $CONFIG_STATUS" >&5 { echo "$as_me:3766: creating $CONFIG_STATUS" >&5
echo "$as_me: creating $CONFIG_STATUS" >&6;} echo "$as_me: creating $CONFIG_STATUS" >&6;}
cat >$CONFIG_STATUS <<_ACEOF cat >$CONFIG_STATUS <<_ACEOF
#! $SHELL #! $SHELL
@ -3974,7 +3939,7 @@ cat >>$CONFIG_STATUS <<\EOF
echo "$ac_cs_version"; exit 0 ;; echo "$ac_cs_version"; exit 0 ;;
--he | --h) --he | --h)
# Conflict between --help and --header # Conflict between --help and --header
{ { echo "$as_me:3977: error: ambiguous option: $1 { { echo "$as_me:3942: error: ambiguous option: $1
Try \`$0 --help' for more information." >&5 Try \`$0 --help' for more information." >&5
echo "$as_me: error: ambiguous option: $1 echo "$as_me: error: ambiguous option: $1
Try \`$0 --help' for more information." >&2;} Try \`$0 --help' for more information." >&2;}
@ -3993,7 +3958,7 @@ Try \`$0 --help' for more information." >&2;}
ac_need_defaults=false;; ac_need_defaults=false;;
# This is an error. # This is an error.
-*) { { echo "$as_me:3996: error: unrecognized option: $1 -*) { { echo "$as_me:3961: error: unrecognized option: $1
Try \`$0 --help' for more information." >&5 Try \`$0 --help' for more information." >&5
echo "$as_me: error: unrecognized option: $1 echo "$as_me: error: unrecognized option: $1
Try \`$0 --help' for more information." >&2;} Try \`$0 --help' for more information." >&2;}
@ -4048,7 +4013,7 @@ do
"doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
"config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
*) { { echo "$as_me:4051: error: invalid argument: $ac_config_target" >&5 *) { { echo "$as_me:4016: error: invalid argument: $ac_config_target" >&5
echo "$as_me: error: invalid argument: $ac_config_target" >&2;} echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
{ (exit 1); exit 1; }; };; { (exit 1); exit 1; }; };;
esac esac
@ -4274,7 +4239,7 @@ done; }
esac esac
if test x"$ac_file" != x-; then if test x"$ac_file" != x-; then
{ echo "$as_me:4277: creating $ac_file" >&5 { echo "$as_me:4242: creating $ac_file" >&5
echo "$as_me: creating $ac_file" >&6;} echo "$as_me: creating $ac_file" >&6;}
rm -f "$ac_file" rm -f "$ac_file"
fi fi
@ -4292,7 +4257,7 @@ echo "$as_me: creating $ac_file" >&6;}
-) echo $tmp/stdin ;; -) echo $tmp/stdin ;;
[\\/$]*) [\\/$]*)
# Absolute (can't be DOS-style, as IFS=:) # Absolute (can't be DOS-style, as IFS=:)
test -f "$f" || { { echo "$as_me:4295: error: cannot find input file: $f" >&5 test -f "$f" || { { echo "$as_me:4260: error: cannot find input file: $f" >&5
echo "$as_me: error: cannot find input file: $f" >&2;} echo "$as_me: error: cannot find input file: $f" >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
echo $f;; echo $f;;
@ -4305,7 +4270,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;}
echo $srcdir/$f echo $srcdir/$f
else else
# /dev/null tree # /dev/null tree
{ { echo "$as_me:4308: error: cannot find input file: $f" >&5 { { echo "$as_me:4273: error: cannot find input file: $f" >&5
echo "$as_me: error: cannot find input file: $f" >&2;} echo "$as_me: error: cannot find input file: $f" >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
fi;; fi;;
@ -4366,7 +4331,7 @@ for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
* ) ac_file_in=$ac_file.in ;; * ) ac_file_in=$ac_file.in ;;
esac esac
test x"$ac_file" != x- && { echo "$as_me:4369: creating $ac_file" >&5 test x"$ac_file" != x- && { echo "$as_me:4334: creating $ac_file" >&5
echo "$as_me: creating $ac_file" >&6;} echo "$as_me: creating $ac_file" >&6;}
# First look for the input files in the build tree, otherwise in the # First look for the input files in the build tree, otherwise in the
@ -4377,7 +4342,7 @@ echo "$as_me: creating $ac_file" >&6;}
-) echo $tmp/stdin ;; -) echo $tmp/stdin ;;
[\\/$]*) [\\/$]*)
# Absolute (can't be DOS-style, as IFS=:) # Absolute (can't be DOS-style, as IFS=:)
test -f "$f" || { { echo "$as_me:4380: error: cannot find input file: $f" >&5 test -f "$f" || { { echo "$as_me:4345: error: cannot find input file: $f" >&5
echo "$as_me: error: cannot find input file: $f" >&2;} echo "$as_me: error: cannot find input file: $f" >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
echo $f;; echo $f;;
@ -4390,7 +4355,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;}
echo $srcdir/$f echo $srcdir/$f
else else
# /dev/null tree # /dev/null tree
{ { echo "$as_me:4393: error: cannot find input file: $f" >&5 { { echo "$as_me:4358: error: cannot find input file: $f" >&5
echo "$as_me: error: cannot find input file: $f" >&2;} echo "$as_me: error: cannot find input file: $f" >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
fi;; fi;;
@ -4507,7 +4472,7 @@ cat >>$CONFIG_STATUS <<\EOF
rm -f $tmp/in rm -f $tmp/in
if test x"$ac_file" != x-; then if test x"$ac_file" != x-; then
if cmp -s $ac_file $tmp/config.h 2>/dev/null; then if cmp -s $ac_file $tmp/config.h 2>/dev/null; then
{ echo "$as_me:4510: $ac_file is unchanged" >&5 { echo "$as_me:4475: $ac_file is unchanged" >&5
echo "$as_me: $ac_file is unchanged" >&6;} echo "$as_me: $ac_file is unchanged" >&6;}
else else
ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \

View File

@ -1,5 +1,5 @@
dnl dnl
dnl Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> dnl Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
dnl dnl
dnl This program is free software; you can redistribute it and/or dnl This program is free software; you can redistribute it and/or
dnl modify it under the terms of the GNU General Public License dnl modify it under the terms of the GNU General Public License
@ -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.6) AM_INIT_AUTOMAKE(emailrelay,0.9.7)
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
dnl === dnl ===
@ -72,7 +72,6 @@ AC_CHECK_HEADERS(unistd.h)
AC_CHECK_HEADERS(sys/time.h) AC_CHECK_HEADERS(sys/time.h)
AC_CHECK_FUNCS(glob) AC_CHECK_FUNCS(glob)
AC_LANG_CPLUSPLUS AC_LANG_CPLUSPLUS
AC_TRY_COMPILE([#include <memory>],std::auto_ptr<int> lhs ; const std::auto_ptr<int> & rhs = lhs ; lhs = rhs ;,,AC_DEFINE(HAVE_NONCONST_AUTOPTR,1,auto_ptr assignment has non-const rhs))
dnl check for *_r() declarations -- using ac_check_funcs dnl check for *_r() declarations -- using ac_check_funcs
dnl is no good here since they may be in the library but dnl is no good here since they may be in the library but
dnl not the header (depending on preprocessor switches) dnl not the header (depending on preprocessor switches)

View File

@ -1,4 +1,4 @@
EXTRA_DIST = developer.txt reference.txt userguide.txt windows.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-passwd.1 emailrelay-poke.1 emailrelay-submit.1 doxygen_header.html graphics/bullet.gif emailrelay.css
noinst_SCRIPTS = .dox noinst_SCRIPTS = .dox
pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html windows.html changelog.html pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html windows.html changelog.html
@ -6,25 +6,44 @@ CLEANFILES = $(noinst_SCRIPTS) html *.ht readme.html developer.html reference.ht
SUFFIXES = .txt .html .ht SUFFIXES = .txt .html .ht
stylesheet=emailrelay.css
filter=$(top_builddir)/bin/emailrelay-doxygen-filter.sh filter=$(top_builddir)/bin/emailrelay-doxygen-filter.sh
filter_src=$(top_srcdir)/bin/emailrelay-doxygen-filter.sh_ filter_src=$(top_srcdir)/bin/emailrelay-doxygen-filter.sh_
converter=$(top_builddir)/bin/txt2html.sh converter=$(top_builddir)/bin/txt2html.sh
converter_src=$(top_srcdir)/bin/txt2html.sh_ converter_src=$(top_srcdir)/bin/txt2html.sh_
converter_helper1=$(top_builddir)/bin/txt2mu.sh
converter_helper1_src=$(top_srcdir)/bin/txt2mu.sh_
converter_helper2=$(top_builddir)/bin/mu2html.sh
converter_helper2_src=$(top_srcdir)/bin/mu2html.sh_
converter_helper3=$(top_builddir)/bin/expand.sh
converter_helper3_src=$(top_srcdir)/bin/expand.sh_
.txt.html: .txt.html:
$(converter) -a "$(AWK)" $< > $*.html $(converter) -a "$(AWK)" $< $(stylesheet) > $*.html
.txt.ht: .txt.ht:
$(converter) -a "$(AWK)" -x $< > $*.ht $(converter) -a "$(AWK)" -x $< $(stylesheet) > $*.ht
$(filter): $(filter_src) $(filter): $(filter_src)
cp $(filter_src) $(filter) cp $(filter_src) $(filter)
chmod ugo+x $(filter) chmod ugo+x $(filter)
$(converter): $(converter_src) $(converter): $(converter_src) $(converter_helper1) $(converter_helper2) $(converter_helper3)
cp $(converter_src) $(converter) cp $(converter_src) $(converter)
chmod ugo+x $(converter) chmod ugo+x $(converter)
$(converter_helper1): $(converter_helper1_src)
cp $(converter_helper1_src) $(converter_helper1)
chmod ugo+x $(converter_helper1)
$(converter_helper2): $(converter_helper2_src)
cp $(converter_helper2_src) $(converter_helper2)
chmod ugo+x $(converter_helper2)
$(converter_helper3): $(converter_helper3_src)
cp $(converter_helper3_src) $(converter_helper3)
chmod ugo+x $(converter_helper3)
.dox: $(filter) .dox: $(filter)
if test "$(HAVE_DOXYGEN)" = "yes" ; then cat $(top_srcdir)/src/main/doxygen.cfg | sed "s:__TOP_SRC__:$(top_srcdir):g" | sed "s:__TOP_BUILD__:$(top_builddir):g" | doxygen - && touch .dox ; else echo no doxygen ; fi if test "$(HAVE_DOXYGEN)" = "yes" ; then cat $(top_srcdir)/src/main/doxygen.cfg | sed "s:__TOP_SRC__:$(top_srcdir):g" | sed "s:__TOP_BUILD__:$(top_builddir):g" | doxygen - && touch .dox ; else echo no doxygen ; fi
@ -34,17 +53,25 @@ man.html: emailrelay.1
developer.html reference.html userguide.html: $(converter) 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 $(stylesheet) > readme.html
changelog.html: $(top_srcdir)/ChangeLog $(converter) changelog.html: $(top_srcdir)/ChangeLog $(converter)
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog > changelog.html $(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog $(stylesheet) > 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
$(INSTALL) $(top_srcdir)/doc/emailrelay-passwd.1 $(destdir)$(mandir)/man1/emailrelay-passwd.1
$(INSTALL) $(top_srcdir)/doc/emailrelay-poke.1 $(destdir)$(mandir)/man1/emailrelay-poke.1 $(INSTALL) $(top_srcdir)/doc/emailrelay-poke.1 $(destdir)$(mandir)/man1/emailrelay-poke.1
$(mkinstalldirs) $(destdir)$(pkgdatadir)/graphics $(mkinstalldirs) $(destdir)$(pkgdatadir)/graphics
$(INSTALL) $(top_srcdir)/doc/graphics/bullet.gif $(destdir)$(pkgdatadir)/graphics/bullet.gif $(INSTALL) $(top_srcdir)/doc/graphics/bullet.gif $(destdir)$(pkgdatadir)/graphics/bullet.gif
$(mkinstalldirs) $(destdir)$(pkgdatadir)/html $(mkinstalldirs) $(destdir)$(pkgdatadir)/html
if test "$(HAVE_DOXYGEN)" = "yes" ; then for file in html/* ; do $(INSTALL) $$file $(destdir)$(pkgdatadir)/$$file ; done ; fi if test "$(HAVE_DOXYGEN)" = "yes" ; then for file in html/* ; do $(INSTALL) $$file $(destdir)$(pkgdatadir)/$$file ; done ; fi
uninstall-local:
-rm -f $(destdir)$(pkgdatadir)/graphics/bullet.gif
-rm -f $(destdir)$(pkgdatadir)/html/* 2>/dev/null
-rm -f $(destdir)$(mandir)/man1/emailrelay.1
-rm -f $(destdir)$(mandir)/man1/emailrelay-passwd.1
-rm -f $(destdir)$(mandir)/man1/emailrelay-poke.1

View File

@ -69,7 +69,7 @@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
VERSION = @VERSION@ VERSION = @VERSION@
EXTRA_DIST = developer.txt reference.txt userguide.txt windows.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-passwd.1 emailrelay-poke.1 emailrelay-submit.1 doxygen_header.html graphics/bullet.gif emailrelay.css
noinst_SCRIPTS = .dox noinst_SCRIPTS = .dox
pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html windows.html changelog.html pkgdata_DATA = readme.html developer.html reference.html userguide.html man.html index.html windows.html changelog.html
@ -77,10 +77,17 @@ CLEANFILES = $(noinst_SCRIPTS) html *.ht readme.html developer.html reference.ht
SUFFIXES = .txt .html .ht SUFFIXES = .txt .html .ht
stylesheet = emailrelay.css
filter = $(top_builddir)/bin/emailrelay-doxygen-filter.sh filter = $(top_builddir)/bin/emailrelay-doxygen-filter.sh
filter_src = $(top_srcdir)/bin/emailrelay-doxygen-filter.sh_ filter_src = $(top_srcdir)/bin/emailrelay-doxygen-filter.sh_
converter = $(top_builddir)/bin/txt2html.sh converter = $(top_builddir)/bin/txt2html.sh
converter_src = $(top_srcdir)/bin/txt2html.sh_ converter_src = $(top_srcdir)/bin/txt2html.sh_
converter_helper1 = $(top_builddir)/bin/txt2mu.sh
converter_helper1_src = $(top_srcdir)/bin/txt2mu.sh_
converter_helper2 = $(top_builddir)/bin/mu2html.sh
converter_helper2_src = $(top_srcdir)/bin/mu2html.sh_
converter_helper3 = $(top_builddir)/bin/expand.sh
converter_helper3_src = $(top_srcdir)/bin/expand.sh_
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES = CONFIG_CLEAN_FILES =
@ -165,7 +172,7 @@ install-data: install-data-am
install-am: all-am install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am install: install-am
uninstall-am: uninstall-pkgdataDATA uninstall-am: uninstall-pkgdataDATA uninstall-local
uninstall: uninstall-am uninstall: uninstall-am
all-am: Makefile $(SCRIPTS) $(DATA) all-am: Makefile $(SCRIPTS) $(DATA)
all-redirect: all-am all-redirect: all-am
@ -206,26 +213,38 @@ maintainer-clean: maintainer-clean-am
.PHONY: uninstall-pkgdataDATA install-pkgdataDATA tags distdir info-am \ .PHONY: uninstall-pkgdataDATA install-pkgdataDATA tags distdir info-am \
info dvi-am dvi check check-am installcheck-am installcheck \ info dvi-am dvi check check-am installcheck-am installcheck \
install-exec-am install-exec install-data-local install-data-am \ install-exec-am install-exec install-data-local install-data-am \
install-data install-am install uninstall-am uninstall all-redirect \ install-data install-am install uninstall-local uninstall-am uninstall \
all-am all installdirs mostlyclean-generic distclean-generic \ all-redirect all-am all installdirs mostlyclean-generic \
clean-generic maintainer-clean-generic clean mostlyclean distclean \ distclean-generic clean-generic maintainer-clean-generic clean \
maintainer-clean mostlyclean distclean maintainer-clean
.txt.html: .txt.html:
$(converter) -a "$(AWK)" $< > $*.html $(converter) -a "$(AWK)" $< $(stylesheet) > $*.html
.txt.ht: .txt.ht:
$(converter) -a "$(AWK)" -x $< > $*.ht $(converter) -a "$(AWK)" -x $< $(stylesheet) > $*.ht
$(filter): $(filter_src) $(filter): $(filter_src)
cp $(filter_src) $(filter) cp $(filter_src) $(filter)
chmod ugo+x $(filter) chmod ugo+x $(filter)
$(converter): $(converter_src) $(converter): $(converter_src) $(converter_helper1) $(converter_helper2) $(converter_helper3)
cp $(converter_src) $(converter) cp $(converter_src) $(converter)
chmod ugo+x $(converter) chmod ugo+x $(converter)
$(converter_helper1): $(converter_helper1_src)
cp $(converter_helper1_src) $(converter_helper1)
chmod ugo+x $(converter_helper1)
$(converter_helper2): $(converter_helper2_src)
cp $(converter_helper2_src) $(converter_helper2)
chmod ugo+x $(converter_helper2)
$(converter_helper3): $(converter_helper3_src)
cp $(converter_helper3_src) $(converter_helper3)
chmod ugo+x $(converter_helper3)
.dox: $(filter) .dox: $(filter)
if test "$(HAVE_DOXYGEN)" = "yes" ; then cat $(top_srcdir)/src/main/doxygen.cfg | sed "s:__TOP_SRC__:$(top_srcdir):g" | sed "s:__TOP_BUILD__:$(top_builddir):g" | doxygen - && touch .dox ; else echo no doxygen ; fi if test "$(HAVE_DOXYGEN)" = "yes" ; then cat $(top_srcdir)/src/main/doxygen.cfg | sed "s:__TOP_SRC__:$(top_srcdir):g" | sed "s:__TOP_BUILD__:$(top_builddir):g" | doxygen - && touch .dox ; else echo no doxygen ; fi
@ -235,20 +254,28 @@ man.html: emailrelay.1
developer.html reference.html userguide.html: $(converter) 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 $(stylesheet) > readme.html
changelog.html: $(top_srcdir)/ChangeLog $(converter) changelog.html: $(top_srcdir)/ChangeLog $(converter)
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog > changelog.html $(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog $(stylesheet) > 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
$(INSTALL) $(top_srcdir)/doc/emailrelay-passwd.1 $(destdir)$(mandir)/man1/emailrelay-passwd.1
$(INSTALL) $(top_srcdir)/doc/emailrelay-poke.1 $(destdir)$(mandir)/man1/emailrelay-poke.1 $(INSTALL) $(top_srcdir)/doc/emailrelay-poke.1 $(destdir)$(mandir)/man1/emailrelay-poke.1
$(mkinstalldirs) $(destdir)$(pkgdatadir)/graphics $(mkinstalldirs) $(destdir)$(pkgdatadir)/graphics
$(INSTALL) $(top_srcdir)/doc/graphics/bullet.gif $(destdir)$(pkgdatadir)/graphics/bullet.gif $(INSTALL) $(top_srcdir)/doc/graphics/bullet.gif $(destdir)$(pkgdatadir)/graphics/bullet.gif
$(mkinstalldirs) $(destdir)$(pkgdatadir)/html $(mkinstalldirs) $(destdir)$(pkgdatadir)/html
if test "$(HAVE_DOXYGEN)" = "yes" ; then for file in html/* ; do $(INSTALL) $$file $(destdir)$(pkgdatadir)/$$file ; done ; fi if test "$(HAVE_DOXYGEN)" = "yes" ; then for file in html/* ; do $(INSTALL) $$file $(destdir)$(pkgdatadir)/$$file ; done ; fi
uninstall-local:
-rm -f $(destdir)$(pkgdatadir)/graphics/bullet.gif
-rm -f $(destdir)$(pkgdatadir)/html/* 2>/dev/null
-rm -f $(destdir)$(mandir)/man1/emailrelay.1
-rm -f $(destdir)$(mandir)/man1/emailrelay-passwd.1
-rm -f $(destdir)$(mandir)/man1/emailrelay-poke.1
# Tell versions [3.59,3.63) of GNU make to not export all variables. # Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded. # Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT: .NOEXPORT:

View File

@ -105,9 +105,7 @@ language/library features:
* static_cast<> & const_cast<> * static_cast<> & const_cast<>
but not: but not:
* defaulted template parameters
* templated member functions * templated member functions
* covariant return
* "mutable" * "mutable"
The header files "gdef.h" in "src/glib", and "gnet.h" in "src/gnet" are intended The header files "gdef.h" in "src/glib", and "gnet.h" in "src/gnet" are intended
@ -142,8 +140,7 @@ Porting to other compilers
-------------------------- --------------------------
If porting to a good ANSI C++ compiler then start by removing files from the If porting to a good ANSI C++ compiler then start by removing files from the
"lib/gcc2.95" directory (or edit makefiles to remove the include path), and then "lib/gcc2.95" directory (or edit makefiles to remove the include path), and then
review the following header files: "src/glib/gdef.h", "src/gnet/gnet.h", review the following header files "src/glib/gdef.h" and "src/gnet/gnet.h".
"src/glib/gmemory.h".
Compile-time features Compile-time features
--------------------- ---------------------
@ -162,9 +159,10 @@ The following features are available to source-code hackers:
# Multiple listening ports # Multiple listening ports
Refer to the Server constructor in "src/main/gsmtpserver.cpp". Set "normal" The server can be made to listen on several different addresses. Look at the
to false and edit the hard-coded address strings. If the addresses "Server" constructor in "src/main/gsmtpserver.cpp", set the boolean variable
need different port numbers then pass them to bind() in the third "normal" to false and then edit the hard-coded address strings as needed. If
the addresses need different port numbers then pass them to bind() in the third
parameter. parameter.
Windows build Windows build
@ -254,4 +252,4 @@ to reassign a std::auto_ptr<>.
Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved. Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved.

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>E-MailRelay: $title</title> <title>E-MailRelay: $title</title>
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">

39
doc/emailrelay-passwd.1 Normal file
View File

@ -0,0 +1,39 @@
.\"
.\" Copyright (C) 2001-2002 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.
.\"
.TH EMAILRELAY-PASSWD 1 local
.SH NAME
emailrelay-passwd \- a password encoding utility for E-MailRelay
.SH SYNOPSIS
.B emailrelay-passwd
.SH DESCRIPTION
.I emailrelay-passwd
is a utility which reads a plaintext password from the standard
input, and writes it out in an encoded form onto the standard
output. The encoded form is suitable for pasting into a CRAM-MD5
line in an
.B emailrelay
secrets file.
.SH SEE ALSO
.BR emailrelay (1)
.br
.B RFC2104
.br
.B RFC2195
.SH AUTHOR
Graeme Walker, mailto:graeme_walker@users.sourceforge.net

View File

@ -1,5 +1,5 @@
.\" .\"
.\" Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> .\" Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
.\" .\"
.\" This program is free software; you can redistribute it and/or .\" This program is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU General Public License .\" modify it under the terms of the GNU General Public License
@ -16,9 +16,9 @@
.\" along with this program; if not, write to the Free Software .\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
.\" .\"
.TH EMAILRELAY 1 local .TH EMAILRELAY-POKE 1 local
.SH NAME .SH NAME
emailrelay-poke \- e-mail transfer agent poke utility emailrelay-poke \- forces an E-MailRelay server to deliver spooled mail
.SH SYNOPSIS .SH SYNOPSIS
.B emailrelay-poke .B emailrelay-poke
[ admin-port [ admin-command ] ] [ admin-port [ admin-command ] ]

36
doc/emailrelay-submit.1 Normal file
View File

@ -0,0 +1,36 @@
.\"
.\" Copyright (C) 2001-2002 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.
.\"
.TH EMAILRELAY-SUBMIT 1 local
.SH NAME
emailrelay-submit \- a submission utility for E-MailRelay
.SH SYNOPSIS
.B emailrelay-submit
[--help] [--from
.IR from-address ]
.RI [ to-address \ ...]
.SH DESCRIPTION
.I emailrelay-submit
is a utility which reads an RFC822 email message from the standard
input, and writes it into the
.B E-MailRelay
spool directory.
.SH SEE ALSO
.BR emailrelay (1)
.SH AUTHOR
Graeme Walker, mailto:graeme_walker@users.sourceforge.net

View File

@ -1,5 +1,5 @@
.\" .\"
.\" Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> .\" Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
.\" .\"
.\" This program is free software; you can redistribute it and/or .\" This program is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU General Public License .\" modify it under the terms of the GNU General Public License
@ -35,8 +35,8 @@ emailrelay \- e-mail transfer agent
.I server-address .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 does store-and-forward
on stand-alone machines which have a dial-up connection to an ISP. mail relay to a fixed downstream server, without any routing.
.LP .LP
It runs in two main modes: a storage deamon It runs in two main modes: a storage deamon
.RI ( --as-server ) .RI ( --as-server )
@ -45,8 +45,8 @@ agent
.RI ( --as-client ). .RI ( --as-client ).
The storage daemon is an SMTP server which stores e-mail The storage daemon is an SMTP server which stores e-mail
messages in a local spool directory. The forwarding agent acts as an messages in a local spool directory. The forwarding agent acts as an
SMTP client, which passes the spooled e-mail messages on to an ISP's SMTP SMTP client, which passes the spooled e-mail messages on to a downstrema
server. SMTP server.
.LP .LP
It can also run in a third mode, as a proxy server It can also run in a third mode, as a proxy server
.RI ( --as-proxy ). .RI ( --as-proxy ).
@ -73,13 +73,16 @@ Enables authentication with remote server, using the given secrets file.
Closes the standard error stream after start-up. Closes the standard error stream after start-up.
.TP .TP
.B \-U,--connection-timeout \fItime\fR .B \-U,--connection-timeout \fItime\fR
Sets the client-side connection timeout in seconds (default is 40). Sets the timeout (in seconds) when connecting to a remote server (default is 40).
.TP
.B \-D,--domain \fIfqdn\fR
Sets an override for the host's fully qualified domain name.
.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 \-z,--filter \fIprogram\fR .B \-z,--filter \fIprogram\fR
Defines a mail pre-processor (disallowed if running as root). Defines a mail pre-processor.
.TP .TP
.B \-f,--forward .B \-f,--forward
Forwards stored mail on startup (requires \fI--forward-to\fR). Forwards stored mail on startup (requires \fI--forward-to\fR).
@ -96,6 +99,9 @@ Forwards each message as soon as it is received (requires \fI--forward-to\fR).
.B \-l,--log .B \-l,--log
Writes log information on standard error (if open) and syslog (if not disabled). Writes log information on standard error (if open) and syslog (if not disabled).
.TP .TP
.B \-L,--log-time
Adds a timestamp to the logging output.
.TP
.B \-t,--no-daemon .B \-t,--no-daemon
Does not detach from the terminal. Does not detach from the terminal.
.TP .TP
@ -112,7 +118,7 @@ Specifies the smtp listening port number.
Allows remote clients to connect. Allows remote clients to connect.
.TP .TP
.B \-T,--response-timeout \fItime\fR .B \-T,--response-timeout \fItime\fR
Sets the client-side response timeout in seconds (default is 1800). Sets the response timeout (in seconds) when talking to a remote server (default is 1800).
.TP .TP
.B \-S,--server-auth \fIfile\fR .B \-S,--server-auth \fIfile\fR
Enables authentication of remote clients, using the given secrets file. Enables authentication of remote clients, using the given secrets file.
@ -120,6 +126,9 @@ Enables authentication of remote clients, using the given secrets file.
.B \-s,--spool-dir \fIdir\fR .B \-s,--spool-dir \fIdir\fR
Specifies the spool directory (default is \fI/usr/local/var/spool/emailrelay\fR). Specifies the spool directory (default is \fI/usr/local/var/spool/emailrelay\fR).
.TP .TP
.B \-u,--user \fIusername\fR
Names the effective user to switch to when started as root (default is \fIdaemon\fR).
.TP
.B \-v,--verbose .B \-v,--verbose
Generates more verbose logging (if compiled-in and logging enabled and stderr open). Generates more verbose logging (if compiled-in and logging enabled and stderr open).
.TP .TP

183
doc/emailrelay.css Normal file
View File

@ -0,0 +1,183 @@
div.two-column-content
{
margin-left: 220px ;
padding: 40px ;
}
div.two-column-menu
{
background-color: #eee ;
position: absolute ;
top: 100px ;
left: 20px ;
padding: 10px ;
border-style: solid ;
border-width: 1px ;
border-color: #999 ;
width: 150px ;
}
body
{
font-family: verdana, arial, helvetica, sans-serif ;
background-color: white ;
}
div.div-main
{
margin-left: 10% ;
margin-right: 10% ;
}
div.div-toc
{
background: #eee ;
padding: 0.5em ;
}
div.two-column-menu div.div-toc
{
padding: 0px ;
}
div.div-pre
{
margin-left: 3% ;
/* font-size: smaller ; */ /* smaller is unreadable on ie5 */
background: #eee ;
padding: 0.5em ;
border: none ;
}
h1
{
text-align: center ;
color: #09c ;
}
img
{
margin-left: 8% ;
}
h2
{
color: #09c ;
}
p
{
font: verdana, arial, helvetica, sans-serif ;
text-align: justify ;
}
a.a-toc
{
color: #09c ;
text-decoration: none ;
padding-left: 0% ;
}
a.a-toc:hover
{
background-color: #ccc ;
}
a.a-header
{
text-decoration:none ;
}
a.a-href
{
text-decoration: none ;
font-weight: bold ;
}
a.a-href:link
{
color: #09c ;
}
a.a-href:visited
{
color: #07a ;
}
a.a-href:hover
{
background-color: #eee ;
}
div.two-column-header
{
background-color: #eee ;
border-style: solid ;
border-color: #999 ;
border-width: 1px 0px ; /* top/bottom left/right */
}
em.quote
{
font-weight: bold ;
}
em.fn
{
font-weight: bold ;
}
li em.fn
{
font-weight: normal ;
font-style: normal ;
}
dt
{
font-weight: bold ;
margin-left: 3% ;
}
dd
{
font-size: smaller ;
margin-left: 6% ;
padding-bottom: 4px ; /* for konqueror */
}
h3.h3-toc
{
margin-bottom: 0px ;
}
ul.ul-toc
{
list-style-type: none ;
margin-top: 0px ;
margin-bottom: 0px ;
padding-left: 15% ;
}
li.li-toc
{
padding-top: 3%
}
span.span-mailto
{
font-size: smaller ;
}
#img-sourceforge
{
border-width: 0px ;
border-style: none ; /* check */
}

View File

@ -1,19 +1,23 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html> <html>
<head> <head>
<title>E-MailRelay index</title> <title>E-MailRelay index</title>
</head> <link rel="stylesheet" href="emailrelay.css" type="text/css">
<body> </head>
<h1>E-MailRelay Documentation</h1> <body>
<ul> <div class="div-main">
<li><a href="readme.html">Readme</a></li> <h1>E-MailRelay Documentation</h1>
<li><a href="changelog.html">Change log</a></li> <ul>
<li><a href="userguide.html">User guide</a></li> <li><a href="readme.html">Readme</a></li>
<li><a href="reference.html">Reference manual</a></li> <li><a href="changelog.html">Change log</a></li>
<li><a href="windows.html">Windows installation guide</a></li> <li><a href="userguide.html">User guide</a></li>
<li><a href="developer.html">Notes for developers</a></li> <li><a href="reference.html">Reference manual</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="windows.html">Windows installation guide</a></li>
<li><a href="man.html">Man page</a> (generated by man2html, if available)</li> <li><a href="developer.html">Notes for developers</a></li>
<li><a href="http://emailrelay.sourceforge.net">Web site</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>
</ul> <li><a href="man.html">Man page</a> (generated by man2html, if available)</li>
</body> <li><a href="http://emailrelay.sourceforge.net">Web site</a></li>
</ul>
</div>
</body>
</html> </html>

View File

@ -33,13 +33,16 @@ where <switch> is:
Closes the standard error stream after start-up. Closes the standard error stream after start-up.
# --connection-timeout (-U) # --connection-timeout (-U)
Sets the client-side connection timeout in seconds (default is 40). Sets the timeout (in seconds) when connecting to a remote server (default is 40).
# --domain (-D)
Sets an override for the host's fully qualified domain name.
# --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).
# --filter (-z) # --filter (-z)
Defines a mail pre-processor (disallowed if running as root). Defines a mail pre-processor.
# --forward (-f) # --forward (-f)
Forwards stored mail on startup (requires --forward-to). Forwards stored mail on startup (requires --forward-to).
@ -56,6 +59,9 @@ where <switch> is:
# --log (-l) # --log (-l)
Writes log information on standard error (if open) and syslog (if not disabled). Writes log information on standard error (if open) and syslog (if not disabled).
# --log-time (-L)
Adds a timestamp to the logging output.
# --no-daemon (-t) # --no-daemon (-t)
Does not detach from the terminal. Does not detach from the terminal.
@ -72,7 +78,7 @@ where <switch> is:
Allows remote clients to connect. Allows remote clients to connect.
# --response-timeout (-T) # --response-timeout (-T)
Sets the client-side response timeout in seconds (default is 1800). Sets the response timeout (in seconds) when talking to a remote server (default is 1800).
# --server-auth (-S) # --server-auth (-S)
Enables authentication of remote clients, using the given secrets file. Enables authentication of remote clients, using the given secrets file.
@ -80,6 +86,9 @@ where <switch> is:
# --spool-dir (-s) # --spool-dir (-s)
Specifies the spool directory (default is "/usr/local/var/spool/emailrelay"). Specifies the spool directory (default is "/usr/local/var/spool/emailrelay").
# --user (-u)
Names the effective user to switch to when started as root (default is "daemon").
# --verbose (-v) # --verbose (-v)
Generates more verbose logging (if compiled-in and logging enabled and stderr open). Generates more verbose logging (if compiled-in and logging enabled and stderr open).
@ -95,6 +104,9 @@ behaviour is:
* disable the administration interface * disable the administration interface
* generate no logging or diagnostic messages * generate no logging or diagnostic messages
The "--as-server" switch makes sure that logging is enabled and that
the standard error stream is closed.
To foward spooled messages to the ISP the command-line switch "--as-client" To foward spooled messages to the ISP the command-line switch "--as-client"
is provided to run the program... is provided to run the program...
* in foreground, exiting when all spooled mail has been processed * in foreground, exiting when all spooled mail has been processed
@ -103,21 +115,12 @@ is provided to run the program...
* with error, warning and information messages sent to stderr * with error, warning and information messages sent to stderr
* without using syslog * without using syslog
The "--as-server" switch makes sure that logging is enabled and that
the standard error stream is closed.
Note that the test for allowing remote clients only takes account of the local
machine's canonical IP address: the connection is regarded as local if the
remote IP address matches the IP address of the local machine's canonical
hostname (ie. not any DNS aliases).
Message store Message store
------------- -------------
Mail messages are stored as text files in the configured spool directory. Each Mail messages are stored as text files in the configured spool directory. Each
message is represented as an envelope file and a content file. The envelope message is represented as an envelope file and a content file. The envelope
file contains parameters relevant to the SMTP dialogue, and the content file file contains parameters relevant to the SMTP dialogue, and the content file
contains the RFC822 headers and body text. Note that the content is largely contains the RFC822 headers and body text.
ignored by the SMTP protocol.
The filenames used in the message store have a prefix of "emailrelay", followed The filenames used in the message store have a prefix of "emailrelay", followed
by a process-id and sequence number, followed by "envelope" or "content". The by a process-id and sequence number, followed by "envelope" or "content". The
@ -141,24 +144,22 @@ SMTP issues
----------- -----------
# Authentication: # Authentication:
The AUTH extension is supported in V0.9.6, but only with the unofficial LOGIN The AUTH extension is supported, providing the CRAM-MD5 and LOGIN mechanisms.
mechanism.
# Local delivery: # Local delivery:
E-MailRelay will reject all local recipients, with the exception of Recipient addresses like "postmaster", "postmaster@localhost" and "postmaster@fqdn"
"postmaster". This is in line with its intended purpose as a simple mail (where "fqdn" is the host's fully qualified domain name) are treated as the local
relay, rather than a fully-fledged routing MTA. Any addressee (except postmaster, resulting in local delivery rather than mail forwarding.
"postmaster") without an "at" sign (@) will be rejected at the time the
message is submitted by the e-mail front-end. Receipient addresses (other than "postmaster" addresses) with no "at" sign (@) or
ending in "@localhost" will be rejected at the time the message is submitted by the
e-mail front-end. This is in line with E-MailRelay's intended purpose as a simple
mail relay, rather than a fully-fledged routing MTA.
Delivery of mail to a local "postmaster" is a feature of E-MailRelay which is Delivery of mail to a local "postmaster" is a feature of E-MailRelay which is
provided for completeness and for comformance to the SMTP specification. It is provided for completeness and for comformance to the SMTP specification.
only relevant if you are in the habit of sending mail to yourself as Note that the E-MailRelay daemon does not actually deliver mail to the postmaster
"postmaster"; mail to "postmaster" from an external source is not processed
by E-MailRelay and should be delivered normally.
Note that E-MailRelay daemon does not actually deliver mail to the postmaster
mailbox. All it does is create an envelope and content file in the spool mailbox. All it does is create an envelope and content file in the spool
directory with a ".local" suffix. Some external system, such as a shell directory with a ".local" suffix. Some external system, such as a shell
script run from cron calling "procmail", should be used to process the script run from cron calling "procmail", should be used to process the
@ -186,11 +187,11 @@ If enabled, the server will provide a network interface for performing
administration tasks. This is a simple command-line interface which is administration tasks. This is a simple command-line interface which is
compatible with "telnet". compatible with "telnet".
Currently the only supported command is "flush", which tries to forward spooled Currently the only supported commands are "flush" and "info". The "flush" command
mail to the configured dowstream SMTP server. The downstream server address is used to forward spooled mail to the configured dowstream SMTP server. The
must have been defined on the "emailrelay" command line at start-up using the downstream server address must have been defined on the "emailrelay" command
"--forward-to" switch; it cannot be specified through the administration line at start-up using the "--forward-to" switch; it cannot be specified through
interface. the administration interface.
The "flush" command allows you to run a single process which combines the The "flush" command allows you to run a single process which combines the
functionality of storage daemon and forwarding client. This might be useful functionality of storage daemon and forwarding client. This might be useful
@ -246,13 +247,24 @@ 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 "--filter" switch), and so the following precautions are taken:
process is running as root (effective userid is zero). The pre-processor will
run as the same userid as the E-MailRelay program, but with an almost empty set # effective userid
of environment variables, and no open file descriptors other than
"stdin"/"stdout"/"stderr" open onto "/dev/null". The pre-processor filename has Root or suid privileges are revoked at start-up, switching to the real userid
to be configured using a full path, so there is no dependence on the current or "daemon" if the real userid is root. Special privileges are only reclaimed
working directory or the PATH variable. when needed to bind sockets and do file i/o.
# execution environment
The pre-processor runs with an almost empty set of environment variables,
and with no open file descriptors other than "stdin"/"stdout"/"stderr" open
onto "/dev/null".
# configuration
The pre-processor filename has to be configured using a full path, so there is
no dependence on the current working directory or the PATH environment variable.
Security issues which relate to the SMTP protocol itself are beyond the scope of 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 this document, but RFC2821 makes the following observation: "SMTP mail is
@ -272,26 +284,28 @@ Some other points are:
Authentication Authentication
-------------- --------------
E-MailRelay has some support for the ESMTP "AUTH" extension, as defined in E-MailRelay supports the ESMTP "AUTH" extension, as defined in RFC2554, on both
RFC2554, on both the server-side and client-side. The only authentication the server-side and client-side. The only authentication mechanisms currently
mechanism currently provided is the non-standard (but widely used) "LOGIN" provided are the non-standard but widely used "LOGIN" mechanism, which uses
mechanism, using plaintext passwords. A future release may add "CRAM-MD5" plaintext passwords, and the "CRAM-MD5" mechanism, as defined in RFC2195.
(RFC2195).
Authentication is enabled with the "--auth-client" and "--auth-server" Authentication is enabled with the "--auth-client" and "--auth-server"
command-line switches. The switch parameter is the name of a "secrets" file, command-line switches. The switch parameter is the name of a "secrets" file,
containing (in the current release) plaintext passwords. containing usernames and passwords.
The secrets file has a line-based format: blank lines are ignored and the hash 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 character (#) is used for comments. Lines have four white-space delimited
fields: "mechanism", "client-or-server", "userid", and "secret". The "mechanism" fields: "mechanism", "client-or-server", "userid", and "secret". The "mechanism"
field must be "login" (case-insensitive); the "client-or-server" field must be field must be "LOGIN" or "CRAM-MD5" (case-insensitive); the "client-or-server"
"client" or "server"; the "userid" field is xtext-encoded user identifier; and field must be "client" or "server"; the "userid" field is xtext-encoded user
the "secret" field is the xtext-encoded plaintext password. (The "xtext" identifier; and the "secret" field is the xtext-encoded "LOGIN" password or
encoding scheme is defined in RFC1891.) A client-side secrets file should "CRAM-MD5" key. The "xtext" encoding scheme is defined in RFC1891. The
contain at least one "login client" entry, and a server-side secrets file should "CRAM-MD5" keys can be generated using the "emailrelay-passwd" utility.
contains zero or more "login server" entries. The same secrets file may be
specified for both "--auth-client" and "--auth-server" switches. A client-side secrets file should contain at least one "LOGIN client" or
"CRAM-MD5 client" entry. A server-side secrets file should contains zero or
more "LOGIN server" or "CRAM-MD5 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 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 used when E-MailRelay authenticates with a downstream server, and defines two
@ -301,31 +315,42 @@ authenticate with the E-MailRelay server:
# #
# emailrelay secrets file # emailrelay secrets file
# #
login client jsmith my+20password LOGIN client jsmith my+20password
login server user1 secret LOGIN server user1 secret
login server user2 ignorance+3Ddeath LOGIN server user2 e+3Dmc2
Clearly storing plaintext passwords in a file and then sending them unencypted A "CRAM-MD5" version would look like this:
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). # emailrelay secrets file
#
CRAM-MD5 client jsmith 688498119.2977922305.1278051807.3015243256.2216875978.2833592318.2902375592.3156808220
CRAM-MD5 server user1 4059553961.2316091643.3282746241.1444639637.3735501773.3404060330.2760590371.1201092398
CRAM-MD5 server user2 2798539199.3144534242.3784876256.2879973305.2327113479.216533878.2436460291.2361831919
When using the LOGIN mechanism you have to store plaintext passwords in a file
and then send them unencypted over a network. This 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 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 "EHLO" command if the "--auth-server" command line switch is used, but
authenticate then the authenticated user-id is stored with the message and authentication by the client is optional. If the client does authenticate then
then passed on to a downstream server using an "AUTH=userid" parameter on the the authenticated user-id is stored with the message and then passed on to a
SMTP "MAIL FROM" command. If the client chooses not to authenticate then the downstream server using an "AUTH=userid" parameter on the SMTP "MAIL FROM"
submitted messages will be forwarded using "AUTH=<>" on the "MAIL FROM" command. If the client chooses not to authenticate then the submitted messages
command. Note that any "AUTH=userid" information on incoming submitted messages will be forwarded using "AUTH=<>" on the "MAIL FROM" command. Note that any
is ignored and discarded: it is the authorised userid from the AUTH command "AUTH=userid" information on incoming submitted messages is ignored and
which is propogated, not the userid from the incoming "MAIL FROM" command's discarded: it is the authorised userid from the AUTH command which is
"AUTH=" parameter. propagated, 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 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 a server which supports the AUTH extension with the LOGIN or CRAM-MD5 mechanism.
authentication is enabled (with the "--auth-client" switch) but the server does not If client authentication is enabled (with the "--auth-client" switch) but the
support the AUTH extension, or does not support the LOGIN mechanism, then the server does not support the AUTH extension, or does not support the LOGIN or
client will fail the first message and terminate with an error message. CRAM-MD5 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 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 from a particular IP address is allowed. This type of POP-before-SMTP
@ -336,6 +361,7 @@ Files
----- -----
By default "make install" installs files in the following locations: By default "make install" installs files in the following locations:
* /usr/local/libexec/emailrelay-poke * /usr/local/libexec/emailrelay-poke
* /usr/local/libexec/emailrelay-passwd
* /usr/local/libexec/emailrelay.sh * /usr/local/libexec/emailrelay.sh
* /usr/local/sbin/emailrelay * /usr/local/sbin/emailrelay
* /usr/local/var/spool/emailrelay/empty_file * /usr/local/var/spool/emailrelay/empty_file
@ -352,4 +378,4 @@ than the Filesystem Hierarchy Standard.
Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved. Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved.

View File

@ -27,15 +27,20 @@ E-MailRelay runs on GNU/Linux, FreeBSD, Solaris and Windows.
What it's not What it's not
------------- -------------
E-MailRelay does not get involved in processing incoming e-mail messages; it With a dial-up connection E-MailRelay does not get involved in processing
only operates on outgoing messages. Incoming e-mail messages will probably be incoming e-mail messages; it only operates on outgoing messages. Incoming e-mail
retrieved from your ISP by your e-mail front-end program, using the POP3 or messages will probably be retrieved from your ISP by your e-mail front-end
IMAP protocols. program, using the POP3 or IMAP protocols.
E-MailRelay is not a routing MTA. It is designed to be used in situations where E-MailRelay is not a routing MTA. It is designed to be used in situations where
all outgoing e-mail message go out to the Internet, so it is not an appropriate all outgoing e-mail message go out over the dial-up connection, so it is not an
choice if you send e-mail to other people who use the same machine or to people appropriate choice if you send e-mail to other people who use the same machine
who are on the same local area network. or to people who are on the same local area network.
Also be careful with programs like "fetchmail" which will fetch incoming mail
using POP3 or IMAP, but then use a local SMTP server to deliver to local
mailboxes. If your local SMTP server is E-MailRelay then your incoming e-mail
will bounce back out.
Why use it? Why use it?
----------- -----------
@ -49,14 +54,13 @@ In particular the configuration of some popular MTAs is notoriously complex
and arcane, whereas the only thing the E-MailRelay system needs is the name of and arcane, whereas the only thing the E-MailRelay system needs is the name of
your ISP's mail server. your ISP's mail server.
Even with the move away from dial-up Internet connections a simple Because E-MailRelay can act as a proxy server, it may be useful handling
store-and-forward MTA like E-MailRelay may still be useful for mobile computers incoming mail from a permanent Internet connection. In this configuration the
and PDAs which need to store mail while away from the network. pre-processing feature could be used for spam filtering or virus checking.
E-MailRelay can also pre-process the e-mail messages which pass through it. This For outgoing mail pre-processing could be used to compensate for features, such
could be used to compensate for features, such as encryption, which are not as encryption, which are not available in your e-mail client program. Or it
available in your e-mail client program, or it could be used to enforce could be used to enforce formatting or legal requirements for all outgoing mail.
formatting or legal requirements for all outgoing mail.
Running E-MailRelay Running E-MailRelay
------------------- -------------------
@ -183,6 +187,23 @@ directory may be sufficient:
if test -f /usr/local/var/spool/emailrelay/*.envelope.bad ; then echo Failed mail >&2 ; fi if test -f /usr/local/var/spool/emailrelay/*.envelope.bad ; then echo Failed mail >&2 ; fi
EOF EOF
Logging
-------
The E-MailRelay program uses the "syslog" system to issue warnings and error messages,
using the "LOG_MAIL" facility. The "syslog" system is configured through the
"/etc/syslog.conf" file (try "man syslog.conf"), and in most cases you will find
that "LOG_MAIL" warnings and errors are directed to an appropriate log file (perhaps
"/var/log/messages").
To get a file which will accumulate all E-MailRelay log messages (and messages
from all other mail programs), add a line like this to "/etc/syslog.conf":
mail.info: /var/log/mail.log
You may have to restart the "syslogd" daemon, or send it a "SIGHUP" signal, in order
to have this change take effect.
For less verbose logging change "mail.info" to "mail.warning".
Troubleshooting Troubleshooting
--------------- ---------------
@ -297,4 +318,4 @@ Glossary
Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved. Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved.

View File

@ -83,7 +83,7 @@ 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 look for a directory "<windir>\spool\emailrelay", where "<windir>" is the
path of your main windows directory, typically "c:\win98" for Windows 98. 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 Finally you will need to configure your e-mail client program to use
the local E-MailRelay server for outgoing mail. Where it asks for the 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 name of the SMTP server for outgoing mail you should tell it to use
"localhost" or "127.0.0.1". "localhost" or "127.0.0.1".
@ -96,4 +96,4 @@ taskbar, desktop or "Start->Programs->StartUp" shortcuts.
Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved. Copyright (C) 2001-2002 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.6 Version: 0.9.7
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.6.tar.gz Source: http://emailrelay.sourceforge.net/.../emailrelay-src-0.9.7.tar.gz
BuildRoot: /tmp/emailrelay-install BuildRoot: /tmp/emailrelay-install
%description %description

View File

@ -1,5 +1,5 @@
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -11,7 +11,7 @@
# PARTICULAR PURPOSE. # PARTICULAR PURPOSE.
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -11,7 +11,7 @@
# PARTICULAR PURPOSE. # PARTICULAR PURPOSE.
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -34,6 +34,7 @@ namespace std
using ::gmtime ; using ::gmtime ;
using ::mktime ; using ::mktime ;
using ::_tzset ; using ::_tzset ;
using ::strftime ;
} ; } ;
#endif #endif

View File

@ -1,5 +1,5 @@
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -24,7 +24,9 @@ EXTRA_DIST=garg_win32.cpp \
gfs_win32.cpp \ gfs_win32.cpp \
glogoutput_win32.cpp \ glogoutput_win32.cpp \
gprocess_win32.cpp \ gprocess_win32.cpp \
gfile_win32.cpp gfile_win32.cpp \
md5c.c \
md5.h
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 INCLUDES = -I$(top_srcdir)/lib/gcc2.95
noinst_LIBRARIES = libglib.a noinst_LIBRARIES = libglib.a
libglib_a_SOURCES = \ libglib_a_SOURCES = \
@ -33,6 +35,7 @@ libglib_a_SOURCES = \
garg_unix.cpp \ garg_unix.cpp \
gassert.h \ gassert.h \
gconvert.h \ gconvert.h \
gcredentials.h \
gdaemon.h \ gdaemon.h \
gdaemon.cpp \ gdaemon.cpp \
gdaemon_unix.cpp \ gdaemon_unix.cpp \
@ -60,13 +63,20 @@ libglib_a_SOURCES = \
glogoutput.cpp \ glogoutput.cpp \
glogoutput.h \ glogoutput.h \
glogoutput_unix.cpp \ glogoutput_unix.cpp \
gmd5.cpp \
gmd5.h \
gmemory.h \ gmemory.h \
gnoncopyable.h \
gpath.cpp \ gpath.cpp \
gpath.h \ gpath.h \
gprocess.h \ gprocess.h \
gprocess_unix.cpp \ gprocess_unix.cpp \
groot.cpp \
groot.h \
gstatemachine.h \
gstr.cpp \ gstr.cpp \
gstr.h \ gstr.h \
gstrings.h \ gstrings.h \
gtime.cpp \ gtime.cpp \
gtime.h gtime.h

View File

@ -11,7 +11,7 @@
# PARTICULAR PURPOSE. # PARTICULAR PURPOSE.
# #
# Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> # Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -89,11 +89,11 @@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
VERSION = @VERSION@ VERSION = @VERSION@
EXTRA_DIST = garg_win32.cpp gdaemon_win32.cpp gdatetime_win32.cpp gdirectory_win32.cpp gfs_win32.cpp glogoutput_win32.cpp gprocess_win32.cpp gfile_win32.cpp EXTRA_DIST = garg_win32.cpp gdaemon_win32.cpp gdatetime_win32.cpp gdirectory_win32.cpp gfs_win32.cpp glogoutput_win32.cpp gprocess_win32.cpp gfile_win32.cpp md5c.c md5.h
INCLUDES = -I$(top_srcdir)/lib/gcc2.95 INCLUDES = -I$(top_srcdir)/lib/gcc2.95
noinst_LIBRARIES = libglib.a noinst_LIBRARIES = libglib.a
libglib_a_SOURCES = garg.cpp garg.h garg_unix.cpp gassert.h gconvert.h gdaemon.h gdaemon.cpp gdaemon_unix.cpp gdate.cpp gdate.h gdatetime.cpp gdatetime.h gdatetime_unix.cpp gdebug.h gdef.h gdirectory.cpp gdirectory.h gdirectory_unix.cpp gexception.cpp gexception.h gfile.cpp gfile.h gfile_unix.cpp gfs.h gfs_unix.cpp ggetopt.cpp ggetopt.h glog.cpp glog.h glogoutput.cpp glogoutput.h glogoutput_unix.cpp gmemory.h gpath.cpp gpath.h gprocess.h gprocess_unix.cpp gstr.cpp gstr.h gstrings.h gtime.cpp gtime.h libglib_a_SOURCES = garg.cpp garg.h garg_unix.cpp gassert.h gconvert.h gcredentials.h gdaemon.h gdaemon.cpp gdaemon_unix.cpp gdate.cpp gdate.h gdatetime.cpp gdatetime.h gdatetime_unix.cpp gdebug.h gdef.h gdirectory.cpp gdirectory.h gdirectory_unix.cpp gexception.cpp gexception.h gfile.cpp gfile.h gfile_unix.cpp gfs.h gfs_unix.cpp ggetopt.cpp ggetopt.h glog.cpp glog.h glogoutput.cpp glogoutput.h glogoutput_unix.cpp gmd5.cpp gmd5.h gmemory.h gnoncopyable.h gpath.cpp gpath.h gprocess.h gprocess_unix.cpp groot.cpp groot.h gstatemachine.h gstr.cpp gstr.h gstrings.h gtime.cpp gtime.h
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../../config.h CONFIG_HEADER = ../../config.h
@ -109,7 +109,8 @@ libglib_a_LIBADD =
libglib_a_OBJECTS = garg.o garg_unix.o gdaemon.o gdaemon_unix.o gdate.o \ libglib_a_OBJECTS = garg.o garg_unix.o gdaemon.o gdaemon_unix.o gdate.o \
gdatetime.o gdatetime_unix.o gdirectory.o gdirectory_unix.o \ gdatetime.o gdatetime_unix.o gdirectory.o gdirectory_unix.o \
gexception.o gfile.o gfile_unix.o gfs_unix.o ggetopt.o glog.o \ gexception.o gfile.o gfile_unix.o gfs_unix.o ggetopt.o glog.o \
glogoutput.o glogoutput_unix.o gpath.o gprocess_unix.o gstr.o gtime.o glogoutput.o glogoutput_unix.o gmd5.o gpath.o gprocess_unix.o groot.o \
gstr.o gtime.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)
@ -229,7 +230,7 @@ garg_unix.o: garg_unix.cpp gdef.h ../../config.h \
gdaemon.o: gdaemon.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \ gdaemon.o: gdaemon.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 gdaemon.h gexception.h gpath.h \ ../../lib/gcc2.95/limits gdaemon.h gexception.h gpath.h \
gstrings.h gprocess.h gstrings.h groot.h gprocess.h gnoncopyable.h
gdaemon_unix.o: gdaemon_unix.cpp gdef.h ../../config.h \ gdaemon_unix.o: gdaemon_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 gdaemon.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gdaemon.h \
@ -284,6 +285,10 @@ glogoutput_unix.o: glogoutput_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 glogoutput.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits glogoutput.h \
glog.h glog.h
gmd5.o: gmd5.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
../../lib/gcc2.95/limits gmd5.h gexception.h gstr.h gstrings.h \
gassert.h glogoutput.h glog.h md5.h md5c.c
gpath.o: gpath.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \ gpath.o: gpath.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 gpath.h gstrings.h gfs.h gstr.h \ ../../lib/gcc2.95/limits gpath.h gstrings.h gfs.h gstr.h \
@ -292,6 +297,11 @@ gprocess_unix.o: gprocess_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 gprocess.h \ ../../lib/gcc2.95/xlocale ../../lib/gcc2.95/limits gprocess.h \
gexception.h gpath.h gstrings.h gfs.h glog.h gexception.h gpath.h gstrings.h gfs.h glog.h
groot.o: groot.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
../../lib/gcc2.95/limits groot.h gprocess.h gexception.h \
gpath.h gstrings.h gnoncopyable.h gdebug.h glogoutput.h glog.h \
gassert.h
gstr.o: gstr.cpp gdef.h ../../config.h ../../lib/gcc2.95/iostream \ gstr.o: gstr.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 gstr.h gexception.h gstrings.h \ ../../lib/gcc2.95/limits gstr.h gexception.h gstrings.h \

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -27,22 +27,28 @@
#include "gdef.h" #include "gdef.h"
#include "gexception.h" #include "gexception.h"
G_EXCEPTION( GConvertOverflow , "arithmetic overflow" ) ; namespace G
{
// Template function: GConvert G_EXCEPTION( ConvertOverflow , "arithmetic overflow" ) ;
// Template function: G::Convert
// Description: Does arithmetic conversions with // Description: Does arithmetic conversions with
// overflow checking. // overflow checking.
// See also: boost::numeric_cast<>()
// //
template <class Tout, class Tin> template <class Tout, class Tin>
inline inline
Tout GConvert( const Tin & in ) Tout Convert( const Tin & in )
{ {
Tout out = in ; Tout out = in ;
Tin copy = out ; Tin copy = out ;
if( in != copy ) if( in != copy )
throw GConvertOverflow( std::stringstream() << in ) ; throw ConvertOverflow( std::stringstream() << in ) ;
return out ; return out ;
} }
} ;
#endif #endif

79
src/glib/gcredentials.h Normal file
View File

@ -0,0 +1,79 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// gcredentials.h
//
#ifndef G_CREDENTIALS_H
#define G_CREDENTIALS_H
#include "gdef.h"
namespace G
{
// Class: credentials
// Description: A class template which can be used to provide
// controlled access to public methods in a class. Note that
// all the constructors are private, but the template-parameter
// class is declared as a friend. (Because all the methods
// are private you will not see much in the doxygen output;
// have a look at the header.)
//
// Usage:
/// struct Foo
/// {
/// void methodForBar( const credentials<Bar> & ) ;
/// } ;
///
/// void Bar::fn()
/// {
/// Foo foo ;
/// foo.methodForBar( "" ) ;
/// }
//
template <class T>
class credentials
{
friend T ;
credentials() ;
// Private default constructor.
credentials( const char * ) ;
// Implicit private constructor.
} ;
template <class T>
inline
credentials<T>::credentials()
{
}
template <class T>
inline
credentials<T>::credentials( const char * )
{
}
} ;
#endif

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -23,6 +23,7 @@
#include "gdef.h" #include "gdef.h"
#include "gdaemon.h" #include "gdaemon.h"
#include "groot.h"
#include "gprocess.h" #include "gprocess.h"
//static //static
@ -72,4 +73,3 @@ void G::Daemon::PidFile::commit()
create( m_path ) ; create( m_path ) ;
} }

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -114,6 +114,7 @@
// Include commonly-used system headers (good for // Include commonly-used system headers (good for
// pre-compilation) // pre-compilation)
// //
#include <cstddef>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -138,9 +139,11 @@
// //
#if defined( G_WINDOWS ) #if defined( G_WINDOWS )
typedef int ssize_t ; typedef int ssize_t ;
typedef int uid_t ;
typedef int gid_t ;
#endif #endif
// STL portability macros // STL portability macros (no longer necessary)
// //
#if 1 #if 1
#define GAllocator(T) #define GAllocator(T)

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -39,28 +39,6 @@ G::GetOpt::GetOpt( const Arg & args_in , const std::string & spec ,
} }
void G::GetOpt::parseSpec( const std::string & spec , char sep_major , char sep_minor , char escape ) void G::GetOpt::parseSpec( const std::string & spec , char sep_major , char sep_minor , char escape )
{
if( spec.find(sep_minor) == std::string::npos )
parseOldSpec( spec ) ;
else
parseNewSpec( spec , sep_major , sep_minor , escape ) ;
}
void G::GetOpt::parseOldSpec( const std::string & spec )
{
for( size_t i = 0U ; i < spec.length() ; i++ )
{
char c = spec.at(i) ;
if( c != ':' )
{
bool valued = (i+1U) < spec.length() && spec.at(i+1U) == ':' ;
addSpec( std::string(1U,c) , c , valued ) ;
}
}
}
void G::GetOpt::parseNewSpec( const std::string & spec , char sep_major ,
char sep_minor , char escape )
{ {
Strings outer ; Strings outer ;
std::string ws_major( 1U , sep_major ) ; std::string ws_major( 1U , sep_major ) ;
@ -78,13 +56,8 @@ void G::GetOpt::parseNewSpec( const std::string & spec , char sep_major ,
} }
} }
void G::GetOpt::addSpec( const std::string & sort_key , char c , bool valued ) void G::GetOpt::addSpec( const std::string & sort_key , char c , const std::string & name ,
{ const std::string & description , bool valued , const std::string & value_description )
addSpec( sort_key , c , std::string() , std::string() , valued , std::string() ) ;
}
void G::GetOpt::addSpec( const std::string & sort_key , char c , const std::string & name , const std::string & description ,
bool valued , const std::string & value_description )
{ {
if( c == '\0' ) if( c == '\0' )
throw InvalidSpecification() ; throw InvalidSpecification() ;

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -50,12 +50,9 @@ public:
GetOpt( const Arg & arg , const std::string & spec , GetOpt( const Arg & arg , const std::string & spec ,
char sep_major = '|' , char sep_minor = '/' , char escape = '\\' ) ; char sep_major = '|' , char sep_minor = '/' , char escape = '\\' ) ;
// Constructor taking a Arg reference and a // Constructor taking a Arg reference and a
// specification string. Supports old-fashioned // specification string. Uses specifications like
// getopt specification strings such as "p:dv", and // "p/port/defines the port number/1/port|v/verbose/shows more logging/0/".
// also new-stye specifications like // made up of the following parts:
// "p/port/port number/1|d/debug/show debug/0|v/verbose/show more/0".
// In the new-style specification each switch definition
// is made up of the following...
// <single-character-switch-letter> // <single-character-switch-letter>
// <multi-character-switch-name> // <multi-character-switch-name>
// <switch-description> // <switch-description>
@ -107,7 +104,7 @@ public:
// prefix(es). The two prefixes are simply concatenated. // prefix(es). The two prefixes are simply concatenated.
void showErrors( std::ostream & stream ) const ; void showErrors( std::ostream & stream ) const ;
// An overload which uses prefix() as <prefix_1>. // An overload which uses Arg::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.
@ -150,9 +147,6 @@ private:
void operator=( const GetOpt & ) ; void operator=( const GetOpt & ) ;
GetOpt( const GetOpt & ) ; GetOpt( const GetOpt & ) ;
void parseSpec( const std::string & spec , char , char , char ) ; void parseSpec( const std::string & spec , char , char , char ) ;
void parseOldSpec( const std::string & spec ) ;
void parseNewSpec( const std::string & spec , char , char , char ) ;
void addSpec( const std::string & sort_key , char c , bool valued ) ;
void addSpec( const std::string & sort_key , char c , const std::string & name , const std::string & , bool valued , const std::string & ) ; void addSpec( const std::string & sort_key , char c , const std::string & name , const std::string & , bool valued , const std::string & ) ;
size_t parseArgs( const Arg & args_in ) ; size_t parseArgs( const Arg & args_in ) ;
bool isOldSwitch( const std::string & arg ) const ; bool isOldSwitch( const std::string & arg ) const ;

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -25,13 +25,16 @@
#include "glogoutput.h" #include "glogoutput.h"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <ctime>
G::LogOutput *G::LogOutput::m_this = NULL ; G::LogOutput *G::LogOutput::m_this = NULL ;
G::LogOutput::LogOutput( bool enabled , bool verbose ) : G::LogOutput::LogOutput( bool enabled , bool verbose ) :
m_enabled(enabled) , m_enabled(enabled) ,
m_verbose(verbose) , m_verbose(verbose) ,
m_syslog(false) m_syslog(false) ,
m_time(0) ,
m_timestamp(false)
{ {
if( m_this == NULL ) if( m_this == NULL )
m_this = this ; m_this = this ;
@ -76,16 +79,41 @@ void G::LogOutput::itoa( char *out , unsigned int n )
} }
} }
void G::LogOutput::timestamp()
{
m_timestamp = true ;
}
const char * G::LogOutput::timestampString()
{
std::time_t now = std::time(NULL) ;
if( m_time == 0 || m_time != now )
{
m_time = now ;
struct std::tm * tm_p = std::localtime( &m_time ) ;
m_time_buffer[0] = '\0' ;
std::strftime( m_time_buffer , sizeof(m_time_buffer)-1U , "%Y" "%m" "%d." "%H" "%M" "%S: " , tm_p ) ;
m_time_buffer[sizeof(m_time_buffer)-1U] = '\0' ;
}
return m_time_buffer ;
}
//static //static
void G::LogOutput::output( G::Log::Severity severity , const char *text ) void G::LogOutput::output( G::Log::Severity severity , const char *text )
{ {
if( m_this != NULL ) if( m_this != NULL )
m_this->doOutput( severity , text ) ;
}
void G::LogOutput::doOutput( G::Log::Severity severity , const char *text )
{
if( m_enabled )
{ {
if( severity != G::Log::s_Debug || m_this->m_verbose ) if( severity != G::Log::s_Debug || m_verbose )
{ {
m_this->rawOutput( severity , text ? text : "" ) ; rawOutput( severity , text ? text : "" ) ;
if( text && text[0U] && text[std::strlen(text)-1U] != '\n' ) if( text && text[0U] && text[std::strlen(text)-1U] != '\n' )
m_this->rawOutput( severity , "\n" ) ; rawOutput( severity , "\n" ) ;
} }
} }
} }
@ -93,19 +121,26 @@ void G::LogOutput::output( G::Log::Severity severity , const char *text )
//static //static
void G::LogOutput::output( G::Log::Severity severity , const char *file, unsigned line, const char *text ) void G::LogOutput::output( G::Log::Severity severity , const char *file, unsigned line, const char *text )
{ {
file = file ? file : "" ; if( m_this != NULL )
text = text ? text : "" ; m_this->doOutput( severity , file , line , text ) ;
}
// no-op if disabled void G::LogOutput::doOutput( G::Log::Severity severity , const char *file, unsigned line, const char *text )
if( m_this == NULL || !m_this->m_enabled ) {
return ; if( m_enabled )
{
file = file ? file : "" ;
text = text ? text : "" ;
char buffer[500U] ; char buffer[500U] ;
buffer[0U] = '\0' ; buffer[0U] = '\0' ;
if( severity == G::Log::s_Debug ) if( severity == G::Log::s_Debug )
fileAndLine( buffer , sizeof(buffer) , file , line ) ; addFileAndLine( buffer , sizeof(buffer) , file , line ) ;
std::strncat( buffer + std::strlen(buffer) , text , sizeof(buffer) - 1U - std::strlen(buffer) ) ; else if( m_timestamp )
output( severity , buffer ) ; addTimestamp( buffer , sizeof(buffer) , timestampString() ) ;
std::strncat( buffer + std::strlen(buffer) , text , sizeof(buffer) - 1U - std::strlen(buffer) ) ;
output( severity , buffer ) ;
}
} }
G::LogOutput *G::LogOutput::instance() G::LogOutput *G::LogOutput::instance()
@ -119,7 +154,7 @@ void G::LogOutput::onAssert()
} }
//static //static
void G::LogOutput::fileAndLine( char *buffer , size_t size , const char *file , int line ) void G::LogOutput::addFileAndLine( char *buffer , size_t size , const char *file , int line )
{ {
const char *forward = std::strrchr( file , '/' ) ; const char *forward = std::strrchr( file , '/' ) ;
const char *back = std::strrchr( file , '\\' ) ; const char *back = std::strrchr( file , '\\' ) ;
@ -134,6 +169,12 @@ void G::LogOutput::fileAndLine( char *buffer , size_t size , const char *file ,
std::strncat( buffer+std::strlen(buffer) , "): " , size-std::strlen(buffer)-1U ) ; std::strncat( buffer+std::strlen(buffer) , "): " , size-std::strlen(buffer)-1U ) ;
} }
//static
void G::LogOutput::addTimestamp( char *buffer , size_t size , const char * ts )
{
std::strncat( buffer+std::strlen(buffer) , ts , size-std::strlen(buffer)-1U ) ;
}
void G::LogOutput::assertion( const char *file , unsigned line , bool test , const char *test_string ) void G::LogOutput::assertion( const char *file , unsigned line , bool test , const char *test_string )
{ {
if( !test ) if( !test )
@ -143,7 +184,7 @@ void G::LogOutput::assertion( const char *file , unsigned line , bool test , con
size_t size = sizeof(buffer) - 10U ; // -10 for luck size_t size = sizeof(buffer) - 10U ; // -10 for luck
if( file ) if( file )
{ {
fileAndLine( buffer , size , file , line ) ; addFileAndLine( buffer , size , file , line ) ;
} }
if( test_string ) if( test_string )
{ {

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -72,6 +72,9 @@ public:
void syslog() ; void syslog() ;
// Enables logging to the syslog system under Unix. // Enables logging to the syslog system under Unix.
void timestamp() ;
// Enables timestamping.
void syslog( SyslogFacility facility ) ; void syslog( SyslogFacility facility ) ;
// Enables logging to the syslog system under Unix, // Enables logging to the syslog system under Unix,
// using the specified facility. // using the specified facility.
@ -99,15 +102,22 @@ private:
LogOutput( const LogOutput & ) ; LogOutput( const LogOutput & ) ;
void operator=( const LogOutput & ) ; void operator=( const LogOutput & ) ;
static void itoa( char *out , unsigned int ) ; static void itoa( char *out , unsigned int ) ;
static void fileAndLine( char * , size_t , const char * , int ) ; static void addFileAndLine( char * , size_t , const char * , int ) ;
static void addTimestamp( char * , size_t , const char * ) ;
const char * timestampString() ;
static void halt() ; static void halt() ;
void doOutput( G::Log::Severity , const char * ) ;
void doOutput( G::Log::Severity s , const char * , unsigned , const char * ) ;
private: private:
static LogOutput *m_this ; static LogOutput * m_this ;
bool m_enabled ; bool m_enabled ;
bool m_verbose ; bool m_verbose ;
bool m_syslog ; bool m_syslog ;
SyslogFacility m_facility ; SyslogFacility m_facility ;
time_t m_time ;
char m_time_buffer[40U] ;
bool m_timestamp ;
} ; } ;
#endif #endif

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -24,8 +24,6 @@
#include "gdef.h" #include "gdef.h"
#include "glogoutput.h" #include "glogoutput.h"
#include <cstdlib> // getenv #include <cstdlib> // getenv
#include <cstring> // strlen
void G::LogOutput::rawOutput( G::Log::Severity severity , const char *message ) void G::LogOutput::rawOutput( G::Log::Severity severity , const char *message )
{ {

194
src/glib/gmd5.cpp Normal file
View File

@ -0,0 +1,194 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// gmd5.cpp
//
#include "gdef.h"
#include "gmd5.h"
#include "gstr.h"
#include "gstrings.h"
#include "gassert.h"
typedef g_uint32_t UINT4 ;
typedef unsigned char * POINTER ;
#include "md5.h"
namespace
{
void init( MD5_CTX & context )
{
::MD5Init( &context ) ;
}
void update( MD5_CTX & context , const std::string & input )
{
char * p = const_cast<char*>(input.c_str()) ;
unsigned int size = static_cast<int>( input.size() ) ;
::MD5Update( &context , reinterpret_cast<unsigned char*>(p) , size ) ;
}
std::string final( MD5_CTX & context )
{
const size_t L = 16U ; // output size
unsigned char buffer[L] ;
::MD5Final( buffer , &context ) ;
const char * buffer_p = reinterpret_cast<char *>(buffer) ;
return std::string( buffer_p , L ) ;
}
std::string writeOut( const MD5_CTX & context )
{
G_ASSERT( sizeof context.state[0] <= sizeof(unsigned long) ) ;
return
G::Str::fromULong( context.state[0] ) + "." +
G::Str::fromULong( context.state[1] ) + "." +
G::Str::fromULong( context.state[2] ) + "." +
G::Str::fromULong( context.state[3] ) ;
}
void readIn( MD5_CTX & context , G::Strings & s )
{
static MD5_CTX zero_context ;
context = zero_context ;
context.count[0] = 0x200 ; // magic number -- see cyrus sasl lib/md5.c
G_ASSERT( context.count[1] == 0 ) ;
context.state[0] = G::Str::toULong(s.front()) ; s.pop_front() ;
context.state[1] = G::Str::toULong(s.front()) ; s.pop_front() ;
context.state[2] = G::Str::toULong(s.front()) ; s.pop_front() ;
context.state[3] = G::Str::toULong(s.front()) ; s.pop_front() ;
G_ASSERT( context.buffer[0] == 0 ) ;
}
}
std::string G::Md5::xor_( const std::string & s1 , const std::string & s2 )
{
G_ASSERT( s1.length() == s2.length() ) ;
std::string::const_iterator p1 = s1.begin() ;
std::string::const_iterator p2 = s2.begin() ;
std::string result ;
for( ; p1 != s1.end() ; ++p1 , ++p2 )
{
unsigned char c1 = static_cast<unsigned char>(*p1) ;
unsigned char c2 = static_cast<unsigned char>(*p2) ;
unsigned char c = c1 ^ c2 ;
result.append( 1U , static_cast<char>(c) ) ;
}
return result ;
}
std::string G::Md5::key64( std::string k )
{
const size_t B = 64U ;
if( k.length() > B )
k = digest(k) ;
if( k.length() < B )
k.append( std::string(B-k.length(),'\0') ) ;
G_ASSERT( k.length() == B ) ;
return k ;
}
std::string G::Md5::ipad()
{
const size_t B = 64U ;
return std::string( B , '\066' ) ; // 00110110 = 00,110,110
}
std::string G::Md5::opad()
{
const size_t B = 64U ;
return std::string( B , '\134' ) ; // 01011100 = 01,011,100
}
std::string G::Md5::mask( const std::string & k )
{
std::string k64 = key64( k ) ;
return mask( k64 , ipad() ) + "." + mask( k64 , opad() ) ;
}
std::string G::Md5::mask( const std::string & k64 , const std::string & pad )
{
MD5_CTX context ;
init( context ) ;
update( context , xor_(k64,pad) ) ;
return writeOut( context ) ;
}
std::string G::Md5::hmac( const std::string & masked_key , const std::string & input , Masked )
{
G::Strings part_list ;
G::Str::splitIntoTokens( masked_key , part_list , "." ) ;
if( part_list.size() != 8U )
throw InvalidMaskedKey( masked_key ) ;
MD5_CTX inner_context ;
MD5_CTX outer_context ;
readIn( inner_context , part_list ) ;
readIn( outer_context , part_list ) ;
update( inner_context , input ) ;
update( outer_context , final(inner_context) ) ;
return final( outer_context ) ;
}
std::string G::Md5::hmac( const std::string & k , const std::string & input )
{
std::string k64 = key64( k ) ;
return digest( xor_(k64,opad()) , digest(xor_(k64,ipad()),input) ) ;
}
std::string G::Md5::digest( const std::string & input )
{
return digest( input , NULL ) ;
}
std::string G::Md5::digest( const std::string & input_1 , const std::string & input_2 )
{
return digest( input_1 , &input_2 ) ;
}
std::string G::Md5::digest( const std::string & input_1 , const std::string * input_2 )
{
MD5_CTX context ;
init( context ) ;
update( context , input_1 ) ;
if( input_2 != NULL )
update( context , *input_2 ) ;
return final( context ) ;
}
std::string G::Md5::printable( const std::string & input )
{
G_ASSERT( input.length() == 16U ) ;
std::string result ;
const char * hex = "0123456789abcdef" ;
const size_t n = input.length() ;
for( size_t i = 0U ; i < n ; i++ )
{
unsigned char c = static_cast<unsigned char>(input.at(i)) ;
result.append( 1U , hex[(c>>4U)&0x0F] ) ;
result.append( 1U , hex[(c>>0U)&0x0F] ) ;
}
return result ;
}
// Source-file inclusion is not nice, but it means that the md5c.c
// file can be left in its pristine state, inheriting the UINT4/POINTER
// definitions from above.
//
#include "md5c.c"

80
src/glib/gmd5.h Normal file
View File

@ -0,0 +1,80 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// gmd5.h
//
#ifndef G_MD5_H
#define G_MD5_H
#include "gdef.h"
#include "gexception.h"
#include <string>
namespace G
{
class Md5 ;
} ;
// Class: G::Md5
// Description: MD5 class.
//
class G::Md5
{
public:
G_EXCEPTION( InvalidMaskedKey , "invalid md5 key" ) ;
struct Masked // An overload discriminator for G::Md5::hmac()
{} ;
static std::string digest( const std::string & input ) ;
// Creates an MD5 digest. The resulting
// string is not generally printable and
// may have embedded NULs.
static std::string digest( const std::string & input_1 , const std::string & input_2 ) ;
// An overload which processes two input strings.
static std::string printable( const std::string & input ) ;
// Converts a binary string into a printable
// form, using a lowercase hexadecimal encoding.
// See also RFC2095.
static std::string hmac( const std::string & key , const std::string & input ) ;
// Computes a Hashed Message Authentication Code
// using MD5 as the hash function.
// See also RFC2104 [HMAC-MD5].
static std::string hmac( const std::string & masked_key , const std::string & input , Masked ) ;
// An hmac() overload using a masked key.
static std::string mask( const std::string & key ) ;
// Masks an HMAC key so that it can be stored more safely.
private:
static std::string digest( const std::string & input_1 , const std::string * input_2 ) ;
static std::string mask( const std::string & k64 , const std::string & pad ) ;
static std::string xor_( const std::string & , const std::string & ) ;
static std::string key64( std::string ) ;
static std::string ipad() ;
static std::string opad() ;
Md5() ;
} ;
#endif

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -27,26 +27,10 @@
#include "gdef.h" #include "gdef.h"
#include <memory> #include <memory>
// define HAVE_NONCONST_AUTOPTR
//
#if HAVE_CONFIG_H
// autoconf's config.h
#include <config.h>
#else
#ifdef G_WINDOWS
#define HAVE_NONCONST_AUTOPTR 0
#else
#define HAVE_NONCONST_AUTOPTR 1
#endif
#endif
// Template function: operator<<= // Template function: operator<<=
// Description: A fix for the problem of resetting an auto_ptr<> // Description: A fix for the problem of resetting an auto_ptr<>
// portably. MSVC6.0 & GCC 2.91 do not have a reset() method, // portably. MSVC6.0 & GCC 2.91 do not have a reset() method,
// and GCC 2.95 has a non-const assignment operators. This means // and GCC 2.95 has a non-const assignment operators.
// that the MSVC code and the GCC 2.95 code for resetting
// auto_ptr<>s has to be quite different. This operator hides
// those differences.
// //
// Usage: // Usage:
/// #include <memory> /// #include <memory>
@ -64,11 +48,8 @@
template <class T> template <class T>
void operator<<=( std::auto_ptr<T> & ap , T * p ) void operator<<=( std::auto_ptr<T> & ap , T * p )
{ {
#if HAVE_NONCONST_AUTOPTR std::auto_ptr<T> temp( p ) ;
ap.reset( p ) ; ap = temp ;
#else
ap = std::auto_ptr<T>( p ) ;
#endif
} }
// Template function: operator<<= // Template function: operator<<=

47
src/glib/gnoncopyable.h Normal file
View File

@ -0,0 +1,47 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// gnoncopyable.h
//
#ifndef G_NONCOPYABLE_H
#define G_NONCOPYABLE_H
#include "gdef.h"
namespace G
{
class noncopyable ;
} ;
// Class: G::noncopyable
// Description: A noncopyable base class (a la boost).
//
class G::noncopyable
{
private:
noncopyable( const noncopyable & ) ;
void operator=( const noncopyable & ) ;
public:
noncopyable() {}
} ;
#endif

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -48,6 +48,10 @@ public:
G_EXCEPTION( WaitError , "cannot wait()" ) ; G_EXCEPTION( WaitError , "cannot wait()" ) ;
G_EXCEPTION( ChildError , "child process terminated abnormally or stopped" ) ; G_EXCEPTION( ChildError , "child process terminated abnormally or stopped" ) ;
G_EXCEPTION( InvalidPath , "invalid executable path -- must be absolute" ) ; G_EXCEPTION( InvalidPath , "invalid executable path -- must be absolute" ) ;
G_EXCEPTION( NoSuchUser , "no such user" ) ;
G_EXCEPTION( UidError , "cannot set uid" ) ;
G_EXCEPTION( GidError , "cannot set gid" ) ;
G_EXCEPTION( Insecure , "refusing to exec() while the user-id is zero" ) ;
enum Who { Parent , Child } ; enum Who { Parent , Child } ;
class IdImp ; class IdImp ;
@ -62,6 +66,14 @@ public:
private: IdImp * m_imp ; private: IdImp * m_imp ;
friend class Process ; friend class Process ;
} ; } ;
struct Identity // Used by G::Process::beSpecial().
{
uid_t uid ;
gid_t gid ;
Identity() ;
explicit Identity( const std::string & login_name ) ;
std::string str() const ;
} ;
class NoThrow // An overload discriminator for Process. class NoThrow // An overload discriminator for Process.
{} ; {} ;
@ -113,6 +125,21 @@ public:
static int errno_() ; static int errno_() ;
// Returns the process's current 'errno' value. // Returns the process's current 'errno' value.
static void beSpecial( Identity special ) ;
// Aquires special privileges (either root
// or suid). The parameter must have come from
// a previous call to beOrdinary().
static Identity beOrdinary( Identity nobody ) ;
// Revokes special privileges (root or suid).
// If really root (as opposed to suid root)
// then the effective id is changed to that
// passed in. If suid, then the effective
// id is changed to the real id, and the
// parameter is ignored. Returns the old
// identity, which can be passed to
// beSpecial().
private: private:
Process() ; Process() ;
static void execCore( const Path & , const std::string & ) ; static void execCore( const Path & , const std::string & ) ;
@ -125,6 +152,12 @@ namespace G
{ {
return stream << id.str() ; return stream << id.str() ;
} }
inline
std::ostream & operator<<( std::ostream & stream , const G::Process::Identity & identity )
{
return stream << identity.str() ;
}
} ; } ;
#endif #endif

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -30,6 +30,8 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> // open() #include <fcntl.h> // open()
#include <pwd.h> // getpwnam()
#include <unistd.h> // setuid() etc
// Class: G::Process::IdImp // Class: G::Process::IdImp
// Description: A private implementation class used by G::Process. // Description: A private implementation class used by G::Process.
@ -168,7 +170,6 @@ int G::Process::wait( const Id & child_pid , int error_return )
return error_return ; return error_return ;
} }
//static //static
int G::Process::errno_() int G::Process::errno_()
{ {
@ -180,9 +181,10 @@ void G::Process::exec( const G::Path & exe , const std::string & arg )
if( exe.isRelative() ) if( exe.isRelative() )
throw InvalidPath( exe.str() ) ; throw InvalidPath( exe.str() ) ;
closeFiles() ; if( privileged() )
throw Insecure() ;
// TODO: more security stuff required here -- setuid() etc. closeFiles() ;
execCore( exe , arg ) ; execCore( exe , arg ) ;
} }
@ -194,7 +196,6 @@ void G::Process::execCore( const G::Path & exe , const std::string & arg )
argv[1U] = arg.empty() ? static_cast<char*>(NULL) : const_cast<char*>(arg.c_str()) ; argv[1U] = arg.empty() ? static_cast<char*>(NULL) : const_cast<char*>(arg.c_str()) ;
argv[2U] = NULL ; argv[2U] = NULL ;
// TODO: review the set of environment variables
char * env[3U] ; char * env[3U] ;
std::string path( "PATH=/usr/bin:/bin" ) ; // no "." std::string path( "PATH=/usr/bin:/bin" ) ; // no "."
std::string ifr( "IFR= \t\n" ) ; std::string ifr( "IFR= \t\n" ) ;
@ -210,6 +211,12 @@ void G::Process::execCore( const G::Path & exe , const std::string & arg )
int G::Process::spawn( const G::Path & exe , const std::string & arg , int error_return ) int G::Process::spawn( const G::Path & exe , const std::string & arg , int error_return )
{ {
if( exe.isRelative() )
throw InvalidPath( exe.str() ) ;
if( privileged() )
throw Insecure() ;
Id child_pid ; Id child_pid ;
if( fork(child_pid) == Child ) if( fork(child_pid) == Child )
{ {
@ -227,6 +234,42 @@ bool G::Process::privileged()
return ::getuid() == 0U || ::geteuid() == 0U ; return ::getuid() == 0U || ::geteuid() == 0U ;
} }
void G::Process::beSpecial( Identity identity )
{
// try to change our effective id -- this
// will only work if our real uid is root, or if
// the executable is suid (assuming the
// o/s supports the saved-suid feature)
//
// gcc requires -D_BSD_SOURCE for seteuid()
//
Identity old_identity ;
(void) ::seteuid( identity.uid ) ;
(void) ::setegid( identity.gid ) ;
(void) old_identity.str() ; // pacify the compiler
G_DEBUG( "G::Process::beSpecial: " << old_identity << " -> " << Identity() ) ;
}
G::Process::Identity G::Process::beOrdinary( Identity nobody )
{
Identity special_identity ;
if( ::getuid() == 0 )
{
if( ::seteuid(0) ) throw UidError("0") ; // first
if( ::setegid(nobody.gid) ) throw GidError(nobody.str()) ; // second
if( ::seteuid(nobody.uid) ) throw UidError(nobody.str()) ; // third
}
else
{
// switch our effective id back to our real id --
// ie. turn off the effects of a suid executable
if( ::seteuid( ::getuid() ) ) throw UidError() ;
if( ::setegid( ::getgid() ) ) throw GidError() ;
}
G_DEBUG( "G::Process::beOrdinary: " << special_identity << " -> " << Identity() ) ;
return special_identity ;
}
// === // ===
G::Process::Id::Id() : m_imp(NULL) G::Process::Id::Id() : m_imp(NULL)
@ -265,3 +308,33 @@ bool G::Process::Id::operator==( const Id & rhs ) const
return m_imp->m_pid == rhs.m_imp->m_pid ; return m_imp->m_pid == rhs.m_imp->m_pid ;
} }
// ===
G::Process::Identity::Identity() :
uid(::geteuid()) ,
gid(::getegid())
{
}
G::Process::Identity::Identity( const std::string & name ) :
uid(static_cast<uid_t>(-1)) ,
gid(static_cast<gid_t>(-1))
{
if( ::getuid() == 0 )
{
::passwd * pw = ::getpwnam( name.c_str() ) ;
if( pw == NULL )
throw Process::NoSuchUser(name) ;
G_DEBUG( "G::Process::Identity: " << name << "=" << pw->pw_uid << "/" << pw->pw_gid ) ;
uid = pw->pw_uid ;
gid = pw->pw_gid ;
}
}
std::string G::Process::Identity::str() const
{
std::stringstream ss ;
ss << uid << "/" << gid ;
return ss.str() ;
}

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -140,6 +140,17 @@ bool G::Process::privileged()
return false ; return false ;
} }
G::Process::Identity G::Process::beOrdinary( Identity identity )
{
// not implemented
return identity ;
}
void G::Process::beSpecial( Identity )
{
// not implemented
}
// not implemented... // not implemented...
// int G::Process::errno_() // int G::Process::errno_()
// Who G::Process::fork() {} // Who G::Process::fork() {}
@ -148,3 +159,22 @@ bool G::Process::privileged()
// int G::Process::wait( const Id & child ) {} // int G::Process::wait( const Id & child ) {}
// int G::Process::wait( const Id & child , int error_return ) {} // int G::Process::wait( const Id & child , int error_return ) {}
// ===
G::Process::Identity::Identity() :
uid(0) ,
gid(0)
{
}
G::Process::Identity::Identity( const std::string & ) :
uid(0) ,
gid(0)
{
}
std::string G::Process::Identity::str() const
{
return "0/0" ;
}

67
src/glib/groot.cpp Normal file
View File

@ -0,0 +1,67 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// groot.cpp
//
#include "gdef.h"
#include "groot.h"
#include "gprocess.h"
#include "gdebug.h"
G::Root * G::Root::m_this = NULL ;
G::Process::Identity G::Root::m_special ;
G::Process::Identity G::Root::m_nobody ;
G::Root::Root()
{
if( m_this == NULL )
{
Process::beSpecial( m_special ) ;
m_this = this ;
}
}
G::Root::~Root()
{
try
{
if( m_this == this )
{
m_this = NULL ;
m_special = Process::beOrdinary( m_nobody ) ;
}
}
catch( std::exception & e )
{
G_ERROR( "G::Root: cannot release root privileges: " << e.what() ) ;
}
catch(...)
{
G_ERROR( "G::Root: cannot release root privileges" ) ;
}
}
void G::Root::init( const std::string & nobody )
{
m_nobody = G::Process::Identity( nobody ) ;
m_special = Process::beOrdinary( m_nobody ) ;
}

67
src/glib/groot.h Normal file
View File

@ -0,0 +1,67 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// groot.h
//
#ifndef G_ROOT_H
#define G_ROOT_H
#include "gdef.h"
#include "gprocess.h"
#include "gnoncopyable.h"
namespace G
{
class Root ;
} ;
// Class: G::Root
// Description: A class which aquires special privileges.
// The implementation uses G::Process.
//
class G::Root : private noncopyable
{
public:
Root() ;
// Default constructor. Aquires special
// privileges if possible.
~Root() ;
// Desctructor. Releases special privileges
// if this instance aquired them.
static void init( const std::string & nobody ) ;
// Releases root or suid privileges. Used
// at process start-up. The parameter
// gives a non-privileged username which
// is used if the real user-id is root.
private:
void * operator new( size_t ) ;
private:
static Root * m_this ;
static Process::Identity m_special ;
static Process::Identity m_nobody ;
} ;
#endif

255
src/glib/gstatemachine.h Normal file
View File

@ -0,0 +1,255 @@
//
// Copyright (C) 2001-2002 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.
//
// ===
//
// gstatemachine.h
//
#ifndef G_STATE_MACHINE_H
#define G_STATE_MACHINE_H
#include "gdef.h"
#include "gexception.h"
#include <map>
namespace G
{
G_EXCEPTION( StateMachine_Error , "invalid state machine transition" ) ;
// Class: StateMachine
// Description: A finite state machine class template.
//
// The finite state machine has a persistant 'state'. When an 'event' is
// apply()d to the state machine, it undergoes a state 'transition'
// and then calls the associated 'action' method.
//
// Predicates are supported. Any action method can return a boolean
// predicate value which is used to select between two transitions --
// the 'normal' transition if the predicate is true, and an 'alternative'
// transition if false.
//
// Transition states can be implemented by having the relevant action
// method call apply() on the state-machine. The state machine's state
// is always changed before any action method is called -- although only
// using the 'normal' transition, not the 'alternative' -- so this sort
// of reentrancy is valid, as long as the action method going into
// the transition state returns a predicate value of 'true'.
//
// Default transitions for a given state are not supported directly. But
// note that protocol errors do not invalidate the state machine and
// do not result in a change of state. This means that client code can
// achieve the effect of default transitions by handling protocol errors
// for that state in a special manner.
//
// Special states 'same' and 'any' can be defined to simplify the
// definition of state transitions. A transition with a 'source'
// state of 'any' will match any state. This is typically used
// for error events or timeouts. A transition with a 'destination'
// state of 'same' will not result in a state change. This is
// sometimes used when handling predicates -- the predicate can
// be used to control whether the state changes, or stays the
// same. The 'any' state is also used as a return value from
// apply() to signal a protocol error.
//
// The 'end' state is special in that predicates are ignored for
// transitions which have 'end' as their 'normal' destintation
// state. This is because of a special implementation feature
// which allows the state machine object to be deleted within the
// action method which causes a transition to the 'end' state.
// (This feature also means that transitions with an 'alternative'
// state of 'end' are not valid.)
//
// Usage:
/// class Protocol
/// {
/// struct ProtocolError {} ;
/// enum State { s_Any , s_Same , sFoo , sBar , sEnd } ;
/// enum Event { eFoo , eBar , eError } ;
/// typedef StateMachine<Protocol,State,Event> Fsm ;
/// Fsm m_fsm ;
/// void doFoo( const std::string & , bool & ) {}
/// void doBar( const std::string & , bool & ) { delete this ; }
/// Event decode( const std::string & ) const ;
/// public:
/// Protocol() : m_fsm(sFoo,sBar,s_Same,s_Any)
/// {
/// m_fsm.addTransition(eFoo,sFoo,sBar,&Protocol::doFoo) ;
/// m_fsm.addTransition(eBar,sBar,sEnd,&Protocol::doBar) ;
/// }
/// void apply( const std::string & event_string )
/// {
/// State s = m_fsm.apply( *this , decode(event_string) , event_string ) ;
/// if( s == sEnd ) return ; // this already deleted by doBar()
/// if( s == sAny ) throw ProtocolError() ;
/// }
/// } ;
//
template <class T, class State, class Event, class Arg = std::string>
class StateMachine
{
public:
typedef void (T::*Action)(const Arg &, bool &) ;
typedef StateMachine_Error Error ;
StateMachine( State s_start , State s_end , State s_same , State s_any ) ;
// Constructor.
void addTransition( Event event , State from , State to , Action action ) ;
// Adds a transition. Special semantics apply if 'from' is
// 's_any', or if 'to' is 's_same'.
void addTransition( Event event , State from , State to , Action action , State alt ) ;
// An overload which adds a transition with predicate support.
// The 'alt' state is taken as an alternative 'to' state
// if the action's predicate is returned as false.
State apply( T & t , Event event , const Arg & arg ) ;
// Applies an event. Calls the appropriate action method
// on object "t" and changes state. The state change
// takes into account the predicate returned by the
// action method.
//
// If the event is valid then the new state is returned.
// If the event results in a protocol error the StateMachine's
// state is unchanged, no action method is called, and
// this method returns 's_any' (see ctor).
//
// As a special implementation feature the StateMachine
// object may be deleted during the last action method
// call (ie. the one which takes the state to the
// 's_end' state).
State state() const ;
// Returns the current state.
State reset( State new_state ) ;
// Sets the current state. Returns the old state.
private:
struct Transition
{
State from ;
State to ;
State alt ; // alternate "to" state if predicate false
Action action ;
Transition(State s1,State s2,Action a,State s3) :
from(s1) , to(s2) , alt(s3) , action(a) {}
} ;
typedef std::multimap<Event,Transition GLessAllocator(Event,Transition) > Map ;
Map m_map ;
State m_state ;
State m_end ;
State m_same ;
State m_any ;
} ;
template <class T, class State, class Event, class Arg>
StateMachine<T,State,Event,Arg>::StateMachine( State s_start , State s_end , State s_same , State s_any ) :
m_state(s_start) ,
m_end(s_end) ,
m_same(s_same) ,
m_any(s_any)
{
}
template <class T, class State, class Event, class Arg>
inline
void StateMachine<T,State,Event,Arg>::addTransition( Event event , State from , State to , Action action )
{
addTransition( event , from , to , action , to ) ;
}
template <class T, class State, class Event, class Arg>
void StateMachine<T,State,Event,Arg>::addTransition( Event event , State from , State to , Action action , State alt )
{
if( to == m_any || alt == m_any )
throw Error( "\"to any\" is invalid" ) ;
if( from == m_same )
throw Error( "\"from same\" is invalid" ) ;
if( to == m_end && alt != to )
throw Error( "predicates on end-state transitions are invalid" ) ;
if( alt == m_end && to != m_end )
throw Error( "false predicates cannot take you to the end state" ) ;
m_map.insert( Map::value_type( event , Transition(from,to,action,alt) ) ) ;
}
template <class T, class State, class Event, class Arg>
inline
State StateMachine<T,State,Event,Arg>::reset( State new_state )
{
State old_state = m_state ;
m_state = new_state ;
return old_state ;
}
template <class T, class State, class Event, class Arg>
inline
State StateMachine<T,State,Event,Arg>::state() const
{
return m_state ;
}
template <class T, class State, class Event, class Arg>
State StateMachine<T,State,Event,Arg>::apply( T & t , Event event , const Arg & arg )
{
// look up in the multimap keyed on current-state + event
//
State state = m_state ;
bool done = false ;
Map::iterator p = m_map.find(event) ;
for( ; !done && p != m_map.end() && (*p).first == event ; ++p )
{
if( (*p).second.from == m_any || (*p).second.from == m_state )
{
// change state
//
State old_state = m_state ;
if( (*p).second.to != m_same )
state = m_state = (*p).second.to ;
// (avoid using members after the action method call)
State end = m_end ;
// perform action
//
bool predicate = true ;
(t.*((*p).second.action))( arg , predicate ) ;
// respond to predicate
//
if( state != end && !predicate )
{
State alt_state = (*p).second.alt ;
state = m_state = alt_state == m_same ? old_state : alt_state ;
}
done = true ;
}
}
return done ? state : m_any ;
}
} ; // namespace
#endif

View File

@ -1,5 +1,5 @@
// //
// Copyright (C) 2001 Graeme Walker <graeme_walker@users.sourceforge.net> // Copyright (C) 2001-2002 Graeme Walker <graeme_walker@users.sourceforge.net>
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -221,6 +221,13 @@ std::string G::Str::fromUInt( unsigned int n )
return ss.str() ; return ss.str() ;
} }
std::string G::Str::fromULong( unsigned long ul )
{
std::stringstream ss ;
ss << ul ;
return ss.str() ;
}
void G::Str::toLower( std::string &s ) void G::Str::toLower( std::string &s )
{ {
for( std::string::iterator p = s.begin() ; p != s.end() ; ++p ) for( std::string::iterator p = s.begin() ; p != s.end() ; ++p )
@ -482,4 +489,27 @@ void G::Str::splitIntoFields( const std::string & in_in , void * out ,
} }
} }
std::string G::Str::join( const G::Strings & strings , const std::string & sep )
{
std::string result ;
bool first = true ;
for( G::Strings::const_iterator p = strings.begin() ; p != strings.end() ; ++p , first = false )
{
if( !first ) result.append( sep ) ;
result.append( *p ) ;
}
return result ;
}
std::string G::Str::join( const StringArray & strings , const std::string & sep )
{
std::string result ;
bool first = true ;
for( StringArray::const_iterator p = strings.begin() ; p != strings.end() ; ++p , first = false )
{
if( !first ) result.append( sep ) ;
result.append( *p ) ;
}
return result ;
}

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