v0.9.7
This commit is contained in:
parent
2911440f23
commit
4905d3db56
7
AUTHORS
7
AUTHORS
@ -2,3 +2,10 @@
|
||||
AUTHORS
|
||||
=======
|
||||
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".
|
||||
|
||||
|
16
ChangeLog
16
ChangeLog
@ -1,6 +1,22 @@
|
||||
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
|
||||
--------------
|
||||
* SMTP AUTHentication extension -- LOGIN mechanism only.
|
||||
|
7
NEWS
7
NEWS
@ -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
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
noinst_SCRIPTS = emailrelay-doxygen-filter.sh emailrelay-test.sh emailrelay-soak.sh
|
||||
libexec_SCRIPTS = emailrelay.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)
|
||||
TESTS = emailrelay-test.sh
|
||||
SUFFIXES = .sh_ .sh
|
||||
|
@ -72,7 +72,7 @@ VERSION = @VERSION@
|
||||
noinst_SCRIPTS = emailrelay-doxygen-filter.sh emailrelay-test.sh emailrelay-soak.sh
|
||||
libexec_SCRIPTS = emailrelay.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)
|
||||
TESTS = emailrelay-test.sh
|
||||
SUFFIXES = .sh_ .sh
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@ -110,7 +110,7 @@ RunPoke()
|
||||
|
||||
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 "From: sender"
|
||||
echo " "
|
||||
@ -123,8 +123,8 @@ Envelope()
|
||||
echo "X-MailRelay-Content: 8bit"
|
||||
echo "X-MailRelay-From: sender"
|
||||
echo "X-MailRelay-ToCount: 2"
|
||||
echo "X-MailRelay-To-Remote: recipient-1@localhost"
|
||||
echo "X-MailRelay-To-Remote: recipient-2@localhost"
|
||||
echo "X-MailRelay-To-Remote: recipient-1@f.q.d.n"
|
||||
echo "X-MailRelay-To-Remote: recipient-2@f.q.d.n"
|
||||
echo "X-MailRelay-Authentication: "
|
||||
echo "X-MailRelay-Client: 127.0.0.1"
|
||||
echo "X-MailRelay-End: 1"
|
||||
@ -162,18 +162,22 @@ CreateAuth()
|
||||
{
|
||||
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"
|
||||
echo "# server.auth" > ${file}
|
||||
echo "login server fred freds_password" >> ${file}
|
||||
echo "login server joe joe+00s_password" >> ${file}
|
||||
echo "login client dummy pwd" >> ${file}
|
||||
echo "cram-md5 client dummy digest" >> ${file}
|
||||
echo "LOGIN server fred freds_password" >> ${file}
|
||||
echo "CRAM-MD5 server joe ${key}" >> ${file}
|
||||
echo "CRAM-MD5 server brian 1.1.1.1.2.2.2.2" >> ${file}
|
||||
|
||||
file="${base_dir}/client.auth"
|
||||
echo "# client.auth" > ${file}
|
||||
echo "cram-md5 client foo bar" >> ${file}
|
||||
echo "login client joe joe+00s_password" >> ${file}
|
||||
echo "login server abc def" >> ${file}
|
||||
file="${base_dir}/client-fred.auth"
|
||||
echo "# client-fred.auth" > ${file}
|
||||
echo "LOGIN client fred freds_password" >> ${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
|
||||
@ -182,8 +186,8 @@ trap "Trap 0 ; exit" 0
|
||||
StartTimer
|
||||
CreateAuth
|
||||
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}3 store-3 log-3 pid-3 "--immediate --forward-to localhost:${pp}4 --filter ${null_filter} --client-auth ${base_dir}/client.auth"
|
||||
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-fred.auth --server-auth ${base_dir}/server.auth"
|
||||
RunServer ${pp}4 store-4 log-4 pid-4 "--server-auth ${base_dir}/server.auth"
|
||||
CreateMessages
|
||||
RunClient localhost:${pp}1 store-1 log-c pid-5
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
89
bin/expand.sh_
Normal file
89
bin/expand.sh_
Normal 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
279
bin/mu2html.sh_
Normal 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( "&" , "\\&" , line )
|
||||
gsub( "<" , "\\<" , line )
|
||||
gsub( ">" , "\\>" , 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
|
||||
|
471
bin/txt2html.sh_
471
bin/txt2html.sh_
@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@ -21,459 +21,76 @@
|
||||
#
|
||||
# txt2html.sh
|
||||
#
|
||||
# Converts plain-text to html. The plain-text has to use special
|
||||
# formating conventions (see "function process()", Anchorise_1() etc).
|
||||
# Converts specially-formatted plain-text to html.
|
||||
# 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"
|
||||
# to create a document index.
|
||||
# The "-t" (text-mode) switch can be used for
|
||||
# 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>]
|
||||
#
|
||||
# The -x switch excludes header and footer stuff.
|
||||
# usage: txt2html.sh [-a <awk-binary>] [-v] [-x] [-t] [<input-file> [<stylesheet> [<graphics-dir> [<title>]]]]
|
||||
#
|
||||
|
||||
awk="gawk"
|
||||
if test "${1}" = "-a"
|
||||
then
|
||||
shift
|
||||
if test "${1}" != ""
|
||||
then
|
||||
awk="${1}"
|
||||
fi
|
||||
if test "${1}" != "" ; then awk="${1}" ; fi
|
||||
shift
|
||||
fi
|
||||
|
||||
full="1"
|
||||
if test "${1}" = "-x"
|
||||
v=""
|
||||
if test "${1}" = "-v"
|
||||
then
|
||||
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
|
||||
|
||||
file="${1}"
|
||||
if test "${file}" = ""
|
||||
stylesheet="${2}"
|
||||
graphics_dir="${3}"
|
||||
title="${4}"
|
||||
|
||||
if test "${v}" != "" -a "${file}" != ""
|
||||
then
|
||||
echo usage: `basename $0` '<txt-file>' >&2
|
||||
exit 2
|
||||
echo `basename $0`: processing ${file} >&2
|
||||
fi
|
||||
|
||||
if test \! -f "${file}"
|
||||
if test "${file}" != "" -a \! -f "${file}"
|
||||
then
|
||||
echo `basename $0`: no such file: ${file} >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
title="`grep -v '^[[:space:]]*$' ${file} | head -1`"
|
||||
if test "${2}" != ""
|
||||
if test "${stylesheet}" != "" -a \! -f "${stylesheet}"
|
||||
then
|
||||
title="${2}"
|
||||
echo `basename $0`: warning: missing stylesheet: "${stylesheet}" >&2
|
||||
fi
|
||||
|
||||
# ===
|
||||
# Include()
|
||||
#
|
||||
# Expands #include# directives. Included text is then processed
|
||||
# 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
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
if test "${graphics_dir}" = ""
|
||||
then
|
||||
graphics_dir="graphics"
|
||||
fi
|
||||
|
||||
# ===
|
||||
# Main()
|
||||
#
|
||||
# Does the bulk of the conversion.
|
||||
#
|
||||
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( "&" , "\\&" , line )
|
||||
gsub( "<" , "\\<" , line )
|
||||
gsub( ">" , "\\>" , 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\">\\\ " | \
|
||||
Decorate dd "<p>" "<p>" | \
|
||||
Anchorise_1 | \
|
||||
MoveIndex
|
||||
txt2mu="`dirname $0`/txt2mu.sh"
|
||||
mu2html="`dirname $0`/mu2html.sh"
|
||||
expand="`dirname $0`/expand.sh"
|
||||
cat ${file} | ${expand} -a "${awk}" ${t} | ${txt2mu} -a "${awk}" ${t} | ${mu2html} -a "${awk}" ${x} "${title}" "${stylesheet}" | ${expand} -a "${awk}"
|
||||
|
||||
|
338
bin/txt2mu.sh_
Normal file
338
bin/txt2mu.sh_
Normal 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"
|
||||
|
||||
|
@ -15,9 +15,6 @@
|
||||
/* Define if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#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'. */
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
|
93
configure
vendored
93
configure
vendored
@ -1124,7 +1124,7 @@ fi
|
||||
|
||||
PACKAGE=emailrelay
|
||||
|
||||
VERSION=0.9.6
|
||||
VERSION=0.9.7
|
||||
|
||||
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
|
||||
@ -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_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_cpp='$CXXCPP $CPPFLAGS'
|
||||
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_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
|
||||
if test -z "$CXXCPP"; 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,
|
||||
# not just through cpp. "Syntax error" is here to catch this case.
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line 3513 "configure"
|
||||
#line 3478 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax error
|
||||
_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
|
||||
ac_status=$?
|
||||
egrep -v '^ *\+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:3524: \$? = $ac_status" >&5
|
||||
echo "$as_me:3489: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null; then
|
||||
if test -s conftest.err; then
|
||||
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
|
||||
# can be detected and how.
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line 3547 "configure"
|
||||
#line 3512 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <ac_nonexistent.h>
|
||||
_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
|
||||
ac_status=$?
|
||||
egrep -v '^ *\+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:3557: \$? = $ac_status" >&5
|
||||
echo "$as_me:3522: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null; then
|
||||
if test -s conftest.err; then
|
||||
ac_cpp_err=$ac_cxx_preproc_warn_flag
|
||||
@ -3591,7 +3556,7 @@ fi
|
||||
else
|
||||
ac_cv_prog_CXXCPP=$CXXCPP
|
||||
fi
|
||||
echo "$as_me:3594: result: $CXXCPP" >&5
|
||||
echo "$as_me:3559: result: $CXXCPP" >&5
|
||||
echo "${ECHO_T}$CXXCPP" >&6
|
||||
ac_preproc_ok=false
|
||||
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,
|
||||
# not just through cpp. "Syntax error" is here to catch this case.
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line 3604 "configure"
|
||||
#line 3569 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax error
|
||||
_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
|
||||
ac_status=$?
|
||||
egrep -v '^ *\+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:3615: \$? = $ac_status" >&5
|
||||
echo "$as_me:3580: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null; then
|
||||
if test -s conftest.err; then
|
||||
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
|
||||
# can be detected and how.
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line 3638 "configure"
|
||||
#line 3603 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <ac_nonexistent.h>
|
||||
_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
|
||||
ac_status=$?
|
||||
egrep -v '^ *\+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:3648: \$? = $ac_status" >&5
|
||||
echo "$as_me:3613: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } >/dev/null; then
|
||||
if test -s conftest.err; then
|
||||
ac_cpp_err=$ac_cxx_preproc_warn_flag
|
||||
@ -3673,7 +3638,7 @@ rm -f conftest.err conftest.$ac_ext
|
||||
if $ac_preproc_ok; then
|
||||
:
|
||||
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;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
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
|
||||
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line 3688 "configure"
|
||||
#line 3653 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <time.h>
|
||||
|
||||
@ -3701,7 +3666,7 @@ fi
|
||||
rm -f conftest*
|
||||
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
#line 3704 "configure"
|
||||
#line 3669 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <time.h>
|
||||
|
||||
@ -3798,7 +3763,7 @@ DEFS=-DHAVE_CONFIG_H
|
||||
: ${CONFIG_STATUS=./config.status}
|
||||
ac_clean_files_save=$ac_clean_files
|
||||
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;}
|
||||
cat >$CONFIG_STATUS <<_ACEOF
|
||||
#! $SHELL
|
||||
@ -3974,7 +3939,7 @@ cat >>$CONFIG_STATUS <<\EOF
|
||||
echo "$ac_cs_version"; exit 0 ;;
|
||||
--he | --h)
|
||||
# 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
|
||||
echo "$as_me: error: ambiguous option: $1
|
||||
Try \`$0 --help' for more information." >&2;}
|
||||
@ -3993,7 +3958,7 @@ Try \`$0 --help' for more information." >&2;}
|
||||
ac_need_defaults=false;;
|
||||
|
||||
# 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
|
||||
echo "$as_me: error: unrecognized option: $1
|
||||
Try \`$0 --help' for more information." >&2;}
|
||||
@ -4048,7 +4013,7 @@ do
|
||||
"doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
|
||||
"default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
|
||||
"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;}
|
||||
{ (exit 1); exit 1; }; };;
|
||||
esac
|
||||
@ -4274,7 +4239,7 @@ done; }
|
||||
esac
|
||||
|
||||
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;}
|
||||
rm -f "$ac_file"
|
||||
fi
|
||||
@ -4292,7 +4257,7 @@ echo "$as_me: creating $ac_file" >&6;}
|
||||
-) echo $tmp/stdin ;;
|
||||
[\\/$]*)
|
||||
# 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;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
echo $f;;
|
||||
@ -4305,7 +4270,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;}
|
||||
echo $srcdir/$f
|
||||
else
|
||||
# /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;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi;;
|
||||
@ -4366,7 +4331,7 @@ for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
|
||||
* ) ac_file_in=$ac_file.in ;;
|
||||
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;}
|
||||
|
||||
# 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 ;;
|
||||
[\\/$]*)
|
||||
# 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;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
echo $f;;
|
||||
@ -4390,7 +4355,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;}
|
||||
echo $srcdir/$f
|
||||
else
|
||||
# /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;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi;;
|
||||
@ -4507,7 +4472,7 @@ cat >>$CONFIG_STATUS <<\EOF
|
||||
rm -f $tmp/in
|
||||
if test x"$ac_file" != x-; 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;}
|
||||
else
|
||||
ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 This program is free software; you can redistribute it and/or
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
dnl ===
|
||||
@ -72,7 +72,6 @@ AC_CHECK_HEADERS(unistd.h)
|
||||
AC_CHECK_HEADERS(sys/time.h)
|
||||
AC_CHECK_FUNCS(glob)
|
||||
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 is no good here since they may be in the library but
|
||||
dnl not the header (depending on preprocessor switches)
|
||||
|
@ -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
|
||||
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
|
||||
|
||||
stylesheet=emailrelay.css
|
||||
filter=$(top_builddir)/bin/emailrelay-doxygen-filter.sh
|
||||
filter_src=$(top_srcdir)/bin/emailrelay-doxygen-filter.sh_
|
||||
converter=$(top_builddir)/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:
|
||||
$(converter) -a "$(AWK)" $< > $*.html
|
||||
$(converter) -a "$(AWK)" $< $(stylesheet) > $*.html
|
||||
|
||||
.txt.ht:
|
||||
$(converter) -a "$(AWK)" -x $< > $*.ht
|
||||
$(converter) -a "$(AWK)" -x $< $(stylesheet) > $*.ht
|
||||
|
||||
$(filter): $(filter_src)
|
||||
cp $(filter_src) $(filter)
|
||||
chmod ugo+x $(filter)
|
||||
|
||||
$(converter): $(converter_src)
|
||||
$(converter): $(converter_src) $(converter_helper1) $(converter_helper2) $(converter_helper3)
|
||||
cp $(converter_src) $(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)
|
||||
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)
|
||||
|
||||
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)
|
||||
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog > changelog.html
|
||||
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog $(stylesheet) > changelog.html
|
||||
|
||||
install-data-local:
|
||||
$(mkinstalldirs) $(destdir)$(mandir)/man1
|
||||
$(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
|
||||
$(mkinstalldirs) $(destdir)$(pkgdatadir)/graphics
|
||||
$(INSTALL) $(top_srcdir)/doc/graphics/bullet.gif $(destdir)$(pkgdatadir)/graphics/bullet.gif
|
||||
$(mkinstalldirs) $(destdir)$(pkgdatadir)/html
|
||||
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
|
||||
|
||||
|
@ -69,7 +69,7 @@ PACKAGE = @PACKAGE@
|
||||
RANLIB = @RANLIB@
|
||||
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
|
||||
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
|
||||
|
||||
stylesheet = emailrelay.css
|
||||
filter = $(top_builddir)/bin/emailrelay-doxygen-filter.sh
|
||||
filter_src = $(top_srcdir)/bin/emailrelay-doxygen-filter.sh_
|
||||
converter = $(top_builddir)/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
|
||||
CONFIG_HEADER = ../config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
@ -165,7 +172,7 @@ install-data: install-data-am
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
install: install-am
|
||||
uninstall-am: uninstall-pkgdataDATA
|
||||
uninstall-am: uninstall-pkgdataDATA uninstall-local
|
||||
uninstall: uninstall-am
|
||||
all-am: Makefile $(SCRIPTS) $(DATA)
|
||||
all-redirect: all-am
|
||||
@ -206,26 +213,38 @@ maintainer-clean: maintainer-clean-am
|
||||
.PHONY: uninstall-pkgdataDATA install-pkgdataDATA tags distdir info-am \
|
||||
info dvi-am dvi check check-am installcheck-am installcheck \
|
||||
install-exec-am install-exec install-data-local install-data-am \
|
||||
install-data install-am install uninstall-am uninstall all-redirect \
|
||||
all-am all installdirs mostlyclean-generic distclean-generic \
|
||||
clean-generic maintainer-clean-generic clean mostlyclean distclean \
|
||||
maintainer-clean
|
||||
install-data install-am install uninstall-local uninstall-am uninstall \
|
||||
all-redirect all-am all installdirs mostlyclean-generic \
|
||||
distclean-generic clean-generic maintainer-clean-generic clean \
|
||||
mostlyclean distclean maintainer-clean
|
||||
|
||||
|
||||
.txt.html:
|
||||
$(converter) -a "$(AWK)" $< > $*.html
|
||||
$(converter) -a "$(AWK)" $< $(stylesheet) > $*.html
|
||||
|
||||
.txt.ht:
|
||||
$(converter) -a "$(AWK)" -x $< > $*.ht
|
||||
$(converter) -a "$(AWK)" -x $< $(stylesheet) > $*.ht
|
||||
|
||||
$(filter): $(filter_src)
|
||||
cp $(filter_src) $(filter)
|
||||
chmod ugo+x $(filter)
|
||||
|
||||
$(converter): $(converter_src)
|
||||
$(converter): $(converter_src) $(converter_helper1) $(converter_helper2) $(converter_helper3)
|
||||
cp $(converter_src) $(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)
|
||||
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)
|
||||
|
||||
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)
|
||||
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog > changelog.html
|
||||
$(converter) -a "$(AWK)" $(top_srcdir)/ChangeLog $(stylesheet) > changelog.html
|
||||
|
||||
install-data-local:
|
||||
$(mkinstalldirs) $(destdir)$(mandir)/man1
|
||||
$(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
|
||||
$(mkinstalldirs) $(destdir)$(pkgdatadir)/graphics
|
||||
$(INSTALL) $(top_srcdir)/doc/graphics/bullet.gif $(destdir)$(pkgdatadir)/graphics/bullet.gif
|
||||
$(mkinstalldirs) $(destdir)$(pkgdatadir)/html
|
||||
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.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
|
@ -105,9 +105,7 @@ language/library features:
|
||||
* static_cast<> & const_cast<>
|
||||
|
||||
but not:
|
||||
* defaulted template parameters
|
||||
* templated member functions
|
||||
* covariant return
|
||||
* "mutable"
|
||||
|
||||
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
|
||||
"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",
|
||||
"src/glib/gmemory.h".
|
||||
review the following header files "src/glib/gdef.h" and "src/gnet/gnet.h".
|
||||
|
||||
Compile-time features
|
||||
---------------------
|
||||
@ -162,9 +159,10 @@ The following features are available to source-code hackers:
|
||||
|
||||
# Multiple listening ports
|
||||
|
||||
Refer to the Server constructor in "src/main/gsmtpserver.cpp". Set "normal"
|
||||
to false and edit the hard-coded address strings. If the addresses
|
||||
need different port numbers then pass them to bind() in the third
|
||||
The server can be made to listen on several different addresses. Look at the
|
||||
"Server" constructor in "src/main/gsmtpserver.cpp", set the boolean variable
|
||||
"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.
|
||||
|
||||
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.
|
||||
|
@ -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">
|
||||
<title>E-MailRelay: $title</title>
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
|
39
doc/emailrelay-passwd.1
Normal file
39
doc/emailrelay-passwd.1
Normal 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
|
@ -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
|
||||
.\" 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
|
||||
.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
.\"
|
||||
.TH EMAILRELAY 1 local
|
||||
.TH EMAILRELAY-POKE 1 local
|
||||
.SH NAME
|
||||
emailrelay-poke \- e-mail transfer agent poke utility
|
||||
emailrelay-poke \- forces an E-MailRelay server to deliver spooled mail
|
||||
.SH SYNOPSIS
|
||||
.B emailrelay-poke
|
||||
[ admin-port [ admin-command ] ]
|
||||
|
36
doc/emailrelay-submit.1
Normal file
36
doc/emailrelay-submit.1
Normal 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
|
@ -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
|
||||
.\" modify it under the terms of the GNU General Public License
|
||||
@ -35,8 +35,8 @@ emailrelay \- e-mail transfer agent
|
||||
.I server-address
|
||||
.SH DESCRIPTION
|
||||
.I emailrelay
|
||||
is an simple e-mail message transfer agent. It is intended to be used
|
||||
on stand-alone machines which have a dial-up connection to an ISP.
|
||||
is an simple e-mail message transfer agent. It does store-and-forward
|
||||
mail relay to a fixed downstream server, without any routing.
|
||||
.LP
|
||||
It runs in two main modes: a storage deamon
|
||||
.RI ( --as-server )
|
||||
@ -45,8 +45,8 @@ agent
|
||||
.RI ( --as-client ).
|
||||
The storage daemon is an SMTP server which stores e-mail
|
||||
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
|
||||
server.
|
||||
SMTP client, which passes the spooled e-mail messages on to a downstrema
|
||||
SMTP server.
|
||||
.LP
|
||||
It can also run in a third mode, as a proxy server
|
||||
.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.
|
||||
.TP
|
||||
.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
|
||||
.B \-x,--dont-serve
|
||||
Stops the process acting as a server (usually used with \fI--forward\fR).
|
||||
.TP
|
||||
.B \-z,--filter \fIprogram\fR
|
||||
Defines a mail pre-processor (disallowed if running as root).
|
||||
Defines a mail pre-processor.
|
||||
.TP
|
||||
.B \-f,--forward
|
||||
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
|
||||
Writes log information on standard error (if open) and syslog (if not disabled).
|
||||
.TP
|
||||
.B \-L,--log-time
|
||||
Adds a timestamp to the logging output.
|
||||
.TP
|
||||
.B \-t,--no-daemon
|
||||
Does not detach from the terminal.
|
||||
.TP
|
||||
@ -112,7 +118,7 @@ Specifies the smtp listening port number.
|
||||
Allows remote clients to connect.
|
||||
.TP
|
||||
.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
|
||||
.B \-S,--server-auth \fIfile\fR
|
||||
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
|
||||
Specifies the spool directory (default is \fI/usr/local/var/spool/emailrelay\fR).
|
||||
.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
|
||||
Generates more verbose logging (if compiled-in and logging enabled and stderr open).
|
||||
.TP
|
||||
|
183
doc/emailrelay.css
Normal file
183
doc/emailrelay.css
Normal 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 */
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>E-MailRelay index</title>
|
||||
<link rel="stylesheet" href="emailrelay.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="div-main">
|
||||
<h1>E-MailRelay Documentation</h1>
|
||||
<ul>
|
||||
<li><a href="readme.html">Readme</a></li>
|
||||
@ -15,5 +18,6 @@
|
||||
<li><a href="man.html">Man page</a> (generated by man2html, if available)</li>
|
||||
<li><a href="http://emailrelay.sourceforge.net">Web site</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -33,13 +33,16 @@ where <switch> is:
|
||||
Closes the standard error stream after start-up.
|
||||
|
||||
# --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)
|
||||
Stops the process acting as a server (usually used with --forward).
|
||||
|
||||
# --filter (-z)
|
||||
Defines a mail pre-processor (disallowed if running as root).
|
||||
Defines a mail pre-processor.
|
||||
|
||||
# --forward (-f)
|
||||
Forwards stored mail on startup (requires --forward-to).
|
||||
@ -56,6 +59,9 @@ where <switch> is:
|
||||
# --log (-l)
|
||||
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)
|
||||
Does not detach from the terminal.
|
||||
|
||||
@ -72,7 +78,7 @@ where <switch> is:
|
||||
Allows remote clients to connect.
|
||||
|
||||
# --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)
|
||||
Enables authentication of remote clients, using the given secrets file.
|
||||
@ -80,6 +86,9 @@ where <switch> is:
|
||||
# --spool-dir (-s)
|
||||
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)
|
||||
Generates more verbose logging (if compiled-in and logging enabled and stderr open).
|
||||
|
||||
@ -95,6 +104,9 @@ behaviour is:
|
||||
* disable the administration interface
|
||||
* 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"
|
||||
is provided to run the program...
|
||||
* 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
|
||||
* 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
|
||||
-------------
|
||||
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
|
||||
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
|
||||
ignored by the SMTP protocol.
|
||||
contains the RFC822 headers and body text.
|
||||
|
||||
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
|
||||
@ -141,24 +144,22 @@ SMTP issues
|
||||
-----------
|
||||
# Authentication:
|
||||
|
||||
The AUTH extension is supported in V0.9.6, but only with the unofficial LOGIN
|
||||
mechanism.
|
||||
The AUTH extension is supported, providing the CRAM-MD5 and LOGIN mechanisms.
|
||||
|
||||
# Local delivery:
|
||||
|
||||
E-MailRelay will reject all local recipients, with the exception of
|
||||
"postmaster". This is in line with its intended purpose as a simple mail
|
||||
relay, rather than a fully-fledged routing MTA. Any addressee (except
|
||||
"postmaster") without an "at" sign (@) will be rejected at the time the
|
||||
message is submitted by the e-mail front-end.
|
||||
Recipient addresses like "postmaster", "postmaster@localhost" and "postmaster@fqdn"
|
||||
(where "fqdn" is the host's fully qualified domain name) are treated as the local
|
||||
postmaster, resulting in local delivery rather than mail forwarding.
|
||||
|
||||
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
|
||||
provided for completeness and for comformance to the SMTP specification. It is
|
||||
only relevant if you are in the habit of sending mail to yourself as
|
||||
"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
|
||||
provided for completeness and for comformance to the SMTP specification.
|
||||
Note that the 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
|
||||
directory with a ".local" suffix. Some external system, such as a shell
|
||||
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
|
||||
compatible with "telnet".
|
||||
|
||||
Currently the only supported command is "flush", which tries to forward spooled
|
||||
mail to the configured dowstream SMTP server. The downstream server address
|
||||
must have been defined on the "emailrelay" command line at start-up using the
|
||||
"--forward-to" switch; it cannot be specified through the administration
|
||||
interface.
|
||||
Currently the only supported commands are "flush" and "info". The "flush" command
|
||||
is used to forward spooled mail to the configured dowstream SMTP server. The
|
||||
downstream server address must have been defined on the "emailrelay" command
|
||||
line at start-up using the "--forward-to" switch; it cannot be specified through
|
||||
the administration interface.
|
||||
|
||||
The "flush" command allows you to run a single process which combines the
|
||||
functionality of storage daemon and forwarding client. This might be useful
|
||||
@ -246,13 +247,24 @@ system.
|
||||
Security issues
|
||||
---------------
|
||||
A major security concern is the use of an external mail pre-processor (using the
|
||||
"--filter" switch). In this release this feature is simply disabled if the
|
||||
process 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
|
||||
of environment variables, and no open file descriptors other than
|
||||
"stdin"/"stdout"/"stderr" open onto "/dev/null". The pre-processor filename has
|
||||
to be configured using a full path, so there is no dependence on the current
|
||||
working directory or the PATH variable.
|
||||
"--filter" switch), and so the following precautions are taken:
|
||||
|
||||
# effective userid
|
||||
|
||||
Root or suid privileges are revoked at start-up, switching to the real userid
|
||||
or "daemon" if the real userid is root. Special privileges are only reclaimed
|
||||
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
|
||||
this document, but RFC2821 makes the following observation: "SMTP mail is
|
||||
@ -272,26 +284,28 @@ Some other points are:
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
E-MailRelay has some support for the ESMTP "AUTH" extension, as defined in
|
||||
RFC2554, on both the server-side and client-side. The only authentication
|
||||
mechanism currently provided is the non-standard (but widely used) "LOGIN"
|
||||
mechanism, using plaintext passwords. A future release may add "CRAM-MD5"
|
||||
(RFC2195).
|
||||
E-MailRelay supports the ESMTP "AUTH" extension, as defined in RFC2554, on both
|
||||
the server-side and client-side. The only authentication mechanisms currently
|
||||
provided are the non-standard but widely used "LOGIN" mechanism, which uses
|
||||
plaintext passwords, and the "CRAM-MD5" mechanism, as defined in RFC2195.
|
||||
|
||||
Authentication is enabled with the "--auth-client" and "--auth-server"
|
||||
command-line switches. The switch parameter is the name of a "secrets" file,
|
||||
containing (in the current release) plaintext passwords.
|
||||
containing usernames and passwords.
|
||||
|
||||
The secrets file has a line-based format: blank lines are ignored and the hash
|
||||
character (#) is used for comments. Lines have four white-space delimited
|
||||
fields: "mechanism", "client-or-server", "userid", and "secret". The "mechanism"
|
||||
field must be "login" (case-insensitive); the "client-or-server" field must be
|
||||
"client" or "server"; the "userid" field is xtext-encoded user identifier; and
|
||||
the "secret" field is the xtext-encoded plaintext password. (The "xtext"
|
||||
encoding scheme is defined in RFC1891.) A client-side secrets file should
|
||||
contain at least one "login client" entry, and a server-side secrets file should
|
||||
contains zero or more "login server" entries. The same secrets file may be
|
||||
specified for both "--auth-client" and "--auth-server" switches.
|
||||
field must be "LOGIN" or "CRAM-MD5" (case-insensitive); the "client-or-server"
|
||||
field must be "client" or "server"; the "userid" field is xtext-encoded user
|
||||
identifier; and the "secret" field is the xtext-encoded "LOGIN" password or
|
||||
"CRAM-MD5" key. The "xtext" encoding scheme is defined in RFC1891. The
|
||||
"CRAM-MD5" keys can be generated using the "emailrelay-passwd" utility.
|
||||
|
||||
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
|
||||
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
|
||||
#
|
||||
login client jsmith my+20password
|
||||
login server user1 secret
|
||||
login server user2 ignorance+3Ddeath
|
||||
LOGIN client jsmith my+20password
|
||||
LOGIN server user1 secret
|
||||
LOGIN server user2 e+3Dmc2
|
||||
|
||||
Clearly storing plaintext passwords in a file and then sending them unencypted
|
||||
over a network is a bad thing. You should at least make sure that the secrets
|
||||
file has tight permissions, and that the passwords in it are not also used for
|
||||
anything important (such as root access).
|
||||
A "CRAM-MD5" version would look like this:
|
||||
|
||||
#
|
||||
# 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
|
||||
"EHLO" command, but authentication by the client is optional. If the client does
|
||||
authenticate then the authenticated user-id is stored with the message and
|
||||
then passed on to a downstream server using an "AUTH=userid" parameter on the
|
||||
SMTP "MAIL FROM" command. If the client chooses not to authenticate then the
|
||||
submitted messages will be forwarded using "AUTH=<>" on the "MAIL FROM"
|
||||
command. Note that any "AUTH=userid" information on incoming submitted messages
|
||||
is ignored and discarded: it is the authorised userid from the AUTH command
|
||||
which is propogated, not the userid from the incoming "MAIL FROM" command's
|
||||
"AUTH=" parameter.
|
||||
"EHLO" command if the "--auth-server" command line switch is used, but
|
||||
authentication by the client is optional. If the client does authenticate then
|
||||
the authenticated user-id is stored with the message and then passed on to a
|
||||
downstream server using an "AUTH=userid" parameter on the SMTP "MAIL FROM"
|
||||
command. If the client chooses not to authenticate then the submitted messages
|
||||
will be forwarded using "AUTH=<>" on the "MAIL FROM" command. Note that any
|
||||
"AUTH=userid" information on incoming submitted messages is ignored and
|
||||
discarded: it is the authorised userid from the AUTH command which is
|
||||
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
|
||||
a server which supports the AUTH extension with the LOGIN mechanism. If client
|
||||
authentication is enabled (with the "--auth-client" switch) but the server does not
|
||||
support the AUTH extension, or does not support the LOGIN mechanism, then the
|
||||
client will fail the first message and terminate with an error message.
|
||||
a server which supports the AUTH extension with the LOGIN or CRAM-MD5 mechanism.
|
||||
If client authentication is enabled (with the "--auth-client" switch) but the
|
||||
server does not support the AUTH extension, or does not support the LOGIN or
|
||||
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
|
||||
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:
|
||||
* /usr/local/libexec/emailrelay-poke
|
||||
* /usr/local/libexec/emailrelay-passwd
|
||||
* /usr/local/libexec/emailrelay.sh
|
||||
* /usr/local/sbin/emailrelay
|
||||
* /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.
|
||||
|
@ -27,15 +27,20 @@ E-MailRelay runs on GNU/Linux, FreeBSD, Solaris and Windows.
|
||||
|
||||
What it's not
|
||||
-------------
|
||||
E-MailRelay does not get involved in processing incoming e-mail messages; it
|
||||
only operates on outgoing messages. Incoming e-mail messages will probably be
|
||||
retrieved from your ISP by your e-mail front-end program, using the POP3 or
|
||||
IMAP protocols.
|
||||
With a dial-up connection E-MailRelay does not get involved in processing
|
||||
incoming e-mail messages; it only operates on outgoing messages. Incoming e-mail
|
||||
messages will probably be retrieved from your ISP by your e-mail front-end
|
||||
program, using the POP3 or IMAP protocols.
|
||||
|
||||
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
|
||||
choice if you send e-mail to other people who use the same machine or to people
|
||||
who are on the same local area network.
|
||||
all outgoing e-mail message go out over the dial-up connection, so it is not an
|
||||
appropriate choice if you send e-mail to other people who use the same machine
|
||||
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?
|
||||
-----------
|
||||
@ -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
|
||||
your ISP's mail server.
|
||||
|
||||
Even with the move away from dial-up Internet connections a simple
|
||||
store-and-forward MTA like E-MailRelay may still be useful for mobile computers
|
||||
and PDAs which need to store mail while away from the network.
|
||||
Because E-MailRelay can act as a proxy server, it may be useful handling
|
||||
incoming mail from a permanent Internet connection. In this configuration the
|
||||
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
|
||||
could be used to compensate for features, such as encryption, which are not
|
||||
available in your e-mail client program, or it could be used to enforce
|
||||
formatting or legal requirements for all outgoing mail.
|
||||
For outgoing mail pre-processing could be used to compensate for features, such
|
||||
as encryption, which are not available in your e-mail client program. Or it
|
||||
could be used to enforce formatting or legal requirements for all outgoing mail.
|
||||
|
||||
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
|
||||
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
|
||||
---------------
|
||||
@ -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.
|
||||
|
@ -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
|
||||
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
|
||||
name of the SMTP server for outgoing mail you should tell it to use
|
||||
"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.
|
||||
|
@ -1,10 +1,10 @@
|
||||
Summary: Simple e-mail message transfer agent using SMTP
|
||||
Name: emailrelay
|
||||
Version: 0.9.6
|
||||
Version: 0.9.7
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
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
|
||||
|
||||
%description
|
||||
|
@ -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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -11,7 +11,7 @@
|
||||
# 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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -11,7 +11,7 @@
|
||||
# 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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -34,6 +34,7 @@ namespace std
|
||||
using ::gmtime ;
|
||||
using ::mktime ;
|
||||
using ::_tzset ;
|
||||
using ::strftime ;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@ -24,7 +24,9 @@ EXTRA_DIST=garg_win32.cpp \
|
||||
gfs_win32.cpp \
|
||||
glogoutput_win32.cpp \
|
||||
gprocess_win32.cpp \
|
||||
gfile_win32.cpp
|
||||
gfile_win32.cpp \
|
||||
md5c.c \
|
||||
md5.h
|
||||
INCLUDES = -I$(top_srcdir)/lib/gcc2.95
|
||||
noinst_LIBRARIES = libglib.a
|
||||
libglib_a_SOURCES = \
|
||||
@ -33,6 +35,7 @@ libglib_a_SOURCES = \
|
||||
garg_unix.cpp \
|
||||
gassert.h \
|
||||
gconvert.h \
|
||||
gcredentials.h \
|
||||
gdaemon.h \
|
||||
gdaemon.cpp \
|
||||
gdaemon_unix.cpp \
|
||||
@ -60,13 +63,20 @@ libglib_a_SOURCES = \
|
||||
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
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
# 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
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@ -89,11 +89,11 @@ PACKAGE = @PACKAGE@
|
||||
RANLIB = @RANLIB@
|
||||
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
|
||||
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
|
||||
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 \
|
||||
gdatetime.o gdatetime_unix.o gdirectory.o gdirectory_unix.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@
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
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 \
|
||||
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
|
||||
../../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 \
|
||||
../../lib/gcc2.95/iostream ../../lib/gcc2.95/sstream \
|
||||
../../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/xlocale ../../lib/gcc2.95/limits glogoutput.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 \
|
||||
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
|
||||
../../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/xlocale ../../lib/gcc2.95/limits gprocess.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 \
|
||||
../../lib/gcc2.95/sstream ../../lib/gcc2.95/xlocale \
|
||||
../../lib/gcc2.95/limits gstr.h gexception.h gstrings.h \
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -27,22 +27,28 @@
|
||||
#include "gdef.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
|
||||
// overflow checking.
|
||||
// See also: boost::numeric_cast<>()
|
||||
//
|
||||
template <class Tout, class Tin>
|
||||
inline
|
||||
Tout GConvert( const Tin & in )
|
||||
Tout Convert( const Tin & in )
|
||||
{
|
||||
Tout out = in ;
|
||||
Tin copy = out ;
|
||||
if( in != copy )
|
||||
throw GConvertOverflow( std::stringstream() << in ) ;
|
||||
throw ConvertOverflow( std::stringstream() << in ) ;
|
||||
return out ;
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
|
79
src/glib/gcredentials.h
Normal file
79
src/glib/gcredentials.h
Normal 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
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
#include "gdef.h"
|
||||
#include "gdaemon.h"
|
||||
#include "groot.h"
|
||||
#include "gprocess.h"
|
||||
|
||||
//static
|
||||
@ -72,4 +73,3 @@ void G::Daemon::PidFile::commit()
|
||||
create( m_path ) ;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -114,6 +114,7 @@
|
||||
// Include commonly-used system headers (good for
|
||||
// pre-compilation)
|
||||
//
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@ -138,9 +139,11 @@
|
||||
//
|
||||
#if defined( G_WINDOWS )
|
||||
typedef int ssize_t ;
|
||||
typedef int uid_t ;
|
||||
typedef int gid_t ;
|
||||
#endif
|
||||
|
||||
// STL portability macros
|
||||
// STL portability macros (no longer necessary)
|
||||
//
|
||||
#if 1
|
||||
#define GAllocator(T)
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// 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 )
|
||||
{
|
||||
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 ;
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
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' )
|
||||
throw InvalidSpecification() ;
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -50,12 +50,9 @@ public:
|
||||
GetOpt( const Arg & arg , const std::string & spec ,
|
||||
char sep_major = '|' , char sep_minor = '/' , char escape = '\\' ) ;
|
||||
// Constructor taking a Arg reference and a
|
||||
// specification string. Supports old-fashioned
|
||||
// getopt specification strings such as "p:dv", and
|
||||
// also new-stye specifications like
|
||||
// "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...
|
||||
// specification string. Uses specifications like
|
||||
// "p/port/defines the port number/1/port|v/verbose/shows more logging/0/".
|
||||
// made up of the following parts:
|
||||
// <single-character-switch-letter>
|
||||
// <multi-character-switch-name>
|
||||
// <switch-description>
|
||||
@ -107,7 +104,7 @@ public:
|
||||
// prefix(es). The two prefixes are simply concatenated.
|
||||
|
||||
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 ;
|
||||
// For debugging.
|
||||
@ -150,9 +147,6 @@ private:
|
||||
void operator=( const GetOpt & ) ;
|
||||
GetOpt( const GetOpt & ) ;
|
||||
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 & ) ;
|
||||
size_t parseArgs( const Arg & args_in ) ;
|
||||
bool isOldSwitch( const std::string & arg ) const ;
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -25,13 +25,16 @@
|
||||
#include "glogoutput.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
G::LogOutput *G::LogOutput::m_this = NULL ;
|
||||
|
||||
G::LogOutput::LogOutput( bool enabled , bool verbose ) :
|
||||
m_enabled(enabled) ,
|
||||
m_verbose(verbose) ,
|
||||
m_syslog(false)
|
||||
m_syslog(false) ,
|
||||
m_time(0) ,
|
||||
m_timestamp(false)
|
||||
{
|
||||
if( m_this == NULL )
|
||||
m_this = this ;
|
||||
@ -76,37 +79,69 @@ 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
|
||||
void G::LogOutput::output( G::Log::Severity severity , const char *text )
|
||||
{
|
||||
if( m_this != NULL )
|
||||
m_this->doOutput( severity , text ) ;
|
||||
}
|
||||
|
||||
void G::LogOutput::doOutput( G::Log::Severity severity , const char *text )
|
||||
{
|
||||
if( severity != G::Log::s_Debug || m_this->m_verbose )
|
||||
if( m_enabled )
|
||||
{
|
||||
m_this->rawOutput( severity , text ? text : "" ) ;
|
||||
if( severity != G::Log::s_Debug || m_verbose )
|
||||
{
|
||||
rawOutput( severity , text ? text : "" ) ;
|
||||
if( text && text[0U] && text[std::strlen(text)-1U] != '\n' )
|
||||
m_this->rawOutput( severity , "\n" ) ;
|
||||
rawOutput( severity , "\n" ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void G::LogOutput::output( G::Log::Severity severity , const char *file, unsigned line, const char *text )
|
||||
{
|
||||
if( m_this != NULL )
|
||||
m_this->doOutput( severity , file , line , text ) ;
|
||||
}
|
||||
|
||||
void G::LogOutput::doOutput( G::Log::Severity severity , const char *file, unsigned line, const char *text )
|
||||
{
|
||||
if( m_enabled )
|
||||
{
|
||||
file = file ? file : "" ;
|
||||
text = text ? text : "" ;
|
||||
|
||||
// no-op if disabled
|
||||
if( m_this == NULL || !m_this->m_enabled )
|
||||
return ;
|
||||
|
||||
char buffer[500U] ;
|
||||
buffer[0U] = '\0' ;
|
||||
if( severity == G::Log::s_Debug )
|
||||
fileAndLine( buffer , sizeof(buffer) , file , line ) ;
|
||||
addFileAndLine( buffer , sizeof(buffer) , file , line ) ;
|
||||
else if( m_timestamp )
|
||||
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()
|
||||
{
|
||||
@ -119,7 +154,7 @@ void G::LogOutput::onAssert()
|
||||
}
|
||||
|
||||
//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 *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 ) ;
|
||||
}
|
||||
|
||||
//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 )
|
||||
{
|
||||
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
|
||||
if( file )
|
||||
{
|
||||
fileAndLine( buffer , size , file , line ) ;
|
||||
addFileAndLine( buffer , size , file , line ) ;
|
||||
}
|
||||
if( test_string )
|
||||
{
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -72,6 +72,9 @@ public:
|
||||
void syslog() ;
|
||||
// Enables logging to the syslog system under Unix.
|
||||
|
||||
void timestamp() ;
|
||||
// Enables timestamping.
|
||||
|
||||
void syslog( SyslogFacility facility ) ;
|
||||
// Enables logging to the syslog system under Unix,
|
||||
// using the specified facility.
|
||||
@ -99,8 +102,12 @@ private:
|
||||
LogOutput( const LogOutput & ) ;
|
||||
void operator=( const LogOutput & ) ;
|
||||
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() ;
|
||||
void doOutput( G::Log::Severity , const char * ) ;
|
||||
void doOutput( G::Log::Severity s , const char * , unsigned , const char * ) ;
|
||||
|
||||
private:
|
||||
static LogOutput * m_this ;
|
||||
@ -108,6 +115,9 @@ private:
|
||||
bool m_verbose ;
|
||||
bool m_syslog ;
|
||||
SyslogFacility m_facility ;
|
||||
time_t m_time ;
|
||||
char m_time_buffer[40U] ;
|
||||
bool m_timestamp ;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -24,8 +24,6 @@
|
||||
#include "gdef.h"
|
||||
#include "glogoutput.h"
|
||||
#include <cstdlib> // getenv
|
||||
#include <cstring> // strlen
|
||||
|
||||
|
||||
void G::LogOutput::rawOutput( G::Log::Severity severity , const char *message )
|
||||
{
|
||||
|
194
src/glib/gmd5.cpp
Normal file
194
src/glib/gmd5.cpp
Normal 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
80
src/glib/gmd5.h
Normal 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
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -27,26 +27,10 @@
|
||||
#include "gdef.h"
|
||||
#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<<=
|
||||
// Description: A fix for the problem of resetting an auto_ptr<>
|
||||
// portably. MSVC6.0 & GCC 2.91 do not have a reset() method,
|
||||
// and GCC 2.95 has a non-const assignment operators. This means
|
||||
// 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.
|
||||
// and GCC 2.95 has a non-const assignment operators.
|
||||
//
|
||||
// Usage:
|
||||
/// #include <memory>
|
||||
@ -64,11 +48,8 @@
|
||||
template <class T>
|
||||
void operator<<=( std::auto_ptr<T> & ap , T * p )
|
||||
{
|
||||
#if HAVE_NONCONST_AUTOPTR
|
||||
ap.reset( p ) ;
|
||||
#else
|
||||
ap = std::auto_ptr<T>( p ) ;
|
||||
#endif
|
||||
std::auto_ptr<T> temp( p ) ;
|
||||
ap = temp ;
|
||||
}
|
||||
|
||||
// Template function: operator<<=
|
||||
|
47
src/glib/gnoncopyable.h
Normal file
47
src/glib/gnoncopyable.h
Normal 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
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -48,6 +48,10 @@ public:
|
||||
G_EXCEPTION( WaitError , "cannot wait()" ) ;
|
||||
G_EXCEPTION( ChildError , "child process terminated abnormally or stopped" ) ;
|
||||
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 } ;
|
||||
class IdImp ;
|
||||
@ -62,6 +66,14 @@ public:
|
||||
private: IdImp * m_imp ;
|
||||
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.
|
||||
{} ;
|
||||
|
||||
@ -113,6 +125,21 @@ public:
|
||||
static int errno_() ;
|
||||
// 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:
|
||||
Process() ;
|
||||
static void execCore( const Path & , const std::string & ) ;
|
||||
@ -125,6 +152,12 @@ namespace G
|
||||
{
|
||||
return stream << id.str() ;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream & operator<<( std::ostream & stream , const G::Process::Identity & identity )
|
||||
{
|
||||
return stream << identity.str() ;
|
||||
}
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -30,6 +30,8 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h> // open()
|
||||
#include <pwd.h> // getpwnam()
|
||||
#include <unistd.h> // setuid() etc
|
||||
|
||||
// Class: G::Process::IdImp
|
||||
// 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 ;
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
int G::Process::errno_()
|
||||
{
|
||||
@ -180,9 +181,10 @@ void G::Process::exec( const G::Path & exe , const std::string & arg )
|
||||
if( exe.isRelative() )
|
||||
throw InvalidPath( exe.str() ) ;
|
||||
|
||||
closeFiles() ;
|
||||
if( privileged() )
|
||||
throw Insecure() ;
|
||||
|
||||
// TODO: more security stuff required here -- setuid() etc.
|
||||
closeFiles() ;
|
||||
|
||||
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[2U] = NULL ;
|
||||
|
||||
// TODO: review the set of environment variables
|
||||
char * env[3U] ;
|
||||
std::string path( "PATH=/usr/bin:/bin" ) ; // no "."
|
||||
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 )
|
||||
{
|
||||
if( exe.isRelative() )
|
||||
throw InvalidPath( exe.str() ) ;
|
||||
|
||||
if( privileged() )
|
||||
throw Insecure() ;
|
||||
|
||||
Id child_pid ;
|
||||
if( fork(child_pid) == Child )
|
||||
{
|
||||
@ -227,6 +234,42 @@ bool G::Process::privileged()
|
||||
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)
|
||||
@ -265,3 +308,33 @@ bool G::Process::Id::operator==( const Id & rhs ) const
|
||||
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() ;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -140,6 +140,17 @@ bool G::Process::privileged()
|
||||
return false ;
|
||||
}
|
||||
|
||||
G::Process::Identity G::Process::beOrdinary( Identity identity )
|
||||
{
|
||||
// not implemented
|
||||
return identity ;
|
||||
}
|
||||
|
||||
void G::Process::beSpecial( Identity )
|
||||
{
|
||||
// not implemented
|
||||
}
|
||||
|
||||
// not implemented...
|
||||
// int G::Process::errno_()
|
||||
// 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 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
67
src/glib/groot.cpp
Normal 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
67
src/glib/groot.h
Normal 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
255
src/glib/gstatemachine.h
Normal 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
|
||||
|
@ -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
|
||||
// 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() ;
|
||||
}
|
||||
|
||||
std::string G::Str::fromULong( unsigned long ul )
|
||||
{
|
||||
std::stringstream ss ;
|
||||
ss << ul ;
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
void G::Str::toLower( std::string &s )
|
||||
{
|
||||
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
Loading…
x
Reference in New Issue
Block a user