├── THANKS ├── doc ├── version.sgml.in ├── gloss.de.sgml ├── manual.de.sgml ├── Makefile.am ├── geamd.sgml ├── geamd-options.sgml └── localstyle.dsl.in ├── TODO ├── lib ├── stringhelp.c ├── Makefile.am ├── xmalloc.h ├── mischelp.h ├── xmalloc.c ├── logging.h ├── libutil-config.h ├── stringhelp.h ├── argparse.h └── logging.c ├── Makefile.am ├── AUTHORS ├── acconfig.h ├── tests ├── Makefile.am ├── test-plain-1 ├── common ├── pubring.asc ├── secring.asc └── basic ├── src ├── geamd.conf ├── decrypt ├── Makefile.am ├── encrypt ├── types.h ├── geamd.h ├── smtpproxy.h ├── aliases ├── nethelp.h ├── rwbuf.h ├── options.h ├── rfc822.h ├── rfc821.h ├── nethelp.c ├── rwbuf.c ├── simple-mta.c ├── geamd.c └── rfc822.c ├── NEWS ├── README ├── configure.in ├── db2html.in ├── ChangeLog ├── INSTALL └── acinclude.m4 /THANKS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/version.sgml.in: -------------------------------------------------------------------------------- 1 | @VERSION@ 2 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/geam/master/TODO -------------------------------------------------------------------------------- /lib/stringhelp.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/geam/master/lib/stringhelp.c -------------------------------------------------------------------------------- /doc/gloss.de.sgml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/geam/master/doc/gloss.de.sgml -------------------------------------------------------------------------------- /doc/manual.de.sgml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/geam/master/doc/manual.de.sgml -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = lib src tests doc 3 | EXTRA_DIST = TODO db2html.in 4 | 5 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Original author: Werner Koch 2 | Current maintainer: g10 Code GmbH 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /acconfig.h: -------------------------------------------------------------------------------- 1 | /* acconfig.h - used by autoheader to make config.h.in 2 | */ 3 | #ifndef GEAM_CONFIG_H 4 | #define GEAM_CONFIG_H 5 | 6 | /* Need this, because some autoconf tests rely on this (e.g. stpcpy) 7 | * and it should be used for new programs anyway. 8 | */ 9 | #define _GNU_SOURCE 1 10 | 11 | @TOP@ 12 | 13 | #undef HAVE_BYTE_TYPEDEF 14 | 15 | 16 | @BOTTOM@ 17 | 18 | 19 | #endif /*GEAM_CONFIG_H*/ 20 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to create Makefile.in 2 | 3 | TESTS = basic 4 | 5 | EXTRA_DIST = $(TESTS) common pubring.asc secring.asc \ 6 | test-plain-1 7 | 8 | DISTCLEANFILES = random_seed 9 | 10 | CLEANFILES = geamd.log geamd.conf encrypt decrypt aliases \ 11 | pubring.gpg secring.gpg trustdb.gpg \ 12 | inner-host.out inner-host.log \ 13 | outer-host.out outer-host.log \ 14 | out err x x1 x2 y y1 y2 15 | 16 | -------------------------------------------------------------------------------- /src/geamd.conf: -------------------------------------------------------------------------------- 1 | # Test configuration file for the geamd 2 | 3 | port 8025 4 | inner-host-name localhost 5 | inner-host-port 9025 6 | outer-host-name localhost 7 | outer-host-port 9026 8 | 9 | # To avoid mailloops, messages with more that this number 10 | # of "Received" headers are not delivered to the smarthost. 11 | #received_headers_max 30 12 | 13 | gpg-program /negev/gcrypt/build/g10/gpg 14 | gpg-homedir . 15 | 16 | # The default log file is /var/log/geam/geamd to specify another, 17 | # use this option. "-" denotes to use stderr for logging 18 | # which will also disable the timestamps. 19 | log-file ./geamd.log 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | # Please note that most files are maintained with another project - 4 | # please make the updates there and not here. 5 | # TODO: Make a target to get those file out of the CVS from the other 6 | # project. Should we put them into the local RCS? 7 | # Make an M4 file for autoconf for those functions. 8 | 9 | noinst_LIBRARIES = libutil.a 10 | 11 | libutil_a_SOURCES = libutil-config.h \ 12 | mischelp.h \ 13 | xmalloc.h xmalloc.c \ 14 | stringhelp.h stringhelp.c \ 15 | logging.h logging.c \ 16 | argparse.h argparse.c 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/test-plain-1: -------------------------------------------------------------------------------- 1 | Date: Mon, 13 Dec 1999 12:29:57 +0100 2 | From: Richard 3 | To: William 4 | Subject: test mime 5 | Message-ID: <19991213122957.X31784@hal9000.fbi.gov> 6 | Mime-Version: 1.0 7 | Content-Type: multipart/encrypted; protocol="application/foobar"; 8 | boundary="yEPQxsgoJgBvi8ip" 9 | Content-Foo: plain nonsense 10 | Sender: Hoover 11 | 12 | 13 | --yEPQxsgoJgBvi8ip 14 | Content-Type: application/foobar 15 | 16 | Tape=1 17 | Track=17 18 | Erased=sure 19 | 20 | --yEPQxsgoJgBvi8ip 21 | Content-Type: text/plain; charset=us-ascii 22 | 23 | "May I recommend some friends of mine with a lot of experience in 24 | in solving problems?" 25 | 26 | --yEPQxsgoJgBvi8ip-- 27 | 28 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | EXTRA_DIST = geamd.sgml geamd-options.sgml manual.de.sgml gloss.de.sgml \ 3 | version.sgml.in \ 4 | geamd.8 manual.de.ps manual.de.html 5 | 6 | man_MANS = geamd.8 7 | pkgdata_DATA = manual.de.html manual.de.ps 8 | 9 | BUILT_SOURCES = manual.de.html manual.de.ps 10 | 11 | CLEANFILES = manual.de.aux manual.de.log manual.de.tex manual.de.dvi 12 | 13 | manual.de.sgml : version.sgml gloss.de.sgml geamd-options.sgml 14 | 15 | 16 | if HAVE_DB2MAN 17 | %.8 : %.sgml 18 | $(DB2MAN) $< >$@ 19 | endif 20 | 21 | if HAVE_DB2TEX 22 | %.ps : %.dvi 23 | dvips -o $@ $< 24 | 25 | %.tex : %.sgml 26 | $(DB2TEX) -d localstyle.dsl $< > $@ 27 | 28 | %.dvi : %.tex 29 | $(JADETEX) $< 30 | endif 31 | 32 | if HAVE_DB2HTML 33 | %.html : %.sgml 34 | $(DB2HTML) --nosplit $< 35 | endif 36 | 37 | -------------------------------------------------------------------------------- /tests/common: -------------------------------------------------------------------------------- 1 | # common definitions for all test scripts 2 | 3 | # reset some environment variables becuase we do not want to test locals 4 | export LANG=C 5 | export LANGUAGE=C 6 | export LC_ALL=C 7 | 8 | if [ "$VERBOSE" = yes ]; then 9 | set -x 10 | fi 11 | 12 | fail=0 13 | framework_failure=0 14 | 15 | if [ -n "$GPG_PROGRAM" ]; then 16 | GPG="$GPG_PROGRAM" 17 | else 18 | GPG=`which gpg` 19 | if [ ! -x $GPG ]; then 20 | echo 'Sorry, gpg has not been found in the search path.' 21 | echo 'To run these checks anyway, please set GPG_PROGRAM' 22 | echo 'to the full path of gpg' 23 | exit 1 24 | fi 25 | fi 26 | 27 | if ! $GPG --version >/dev/null; then 28 | echo 'Sorry, there is a problem running GnuPG.' 29 | echo "Please check why $GPG does not run." 30 | exit 1 31 | fi 32 | 33 | -------------------------------------------------------------------------------- /src/decrypt: -------------------------------------------------------------------------------- 1 | # Geam - list of secret keys which should be used to decrypt messages. 2 | # 3 | # We need this list to relay a decrypted message to a fixed address. 4 | # This way we have better control over the recipient of a _decrypted_ 5 | # message. 6 | # 7 | # Format is: mail address, encryption system, keyid. 8 | # 9 | # The mail address here may be used to decrypt messages which do not 10 | # have an allowed decrypt recipients (as determined by the aliases table). 11 | # You may want to use the owner of the corresponding key or the postmaster 12 | # for this address. 13 | # 14 | # In contrast to the "encrypt" table, we only use the keyid here, as this 15 | # is the information stored in the OpenPGP message header. 16 | 17 | postmaster@localhost gpg 5381EA4EE29BA37F 18 | yankee@localhost gpg 5ADFD255F7B080AD 19 | 20 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | EXTRA_DIST = geamd.conf aliases encrypt decrypt 3 | 4 | sbin_PROGRAMS = geamd 5 | noinst_PROGRAMS = simple-mta 6 | 7 | geamd_SOURCES = geamd.c geamd.h \ 8 | smtpproxy.c smtpproxy.h \ 9 | options.h \ 10 | types.h \ 11 | rwbuf.h rwbuf.c \ 12 | nethelp.h nethelp.c \ 13 | rfc821.h rfc821.c \ 14 | rfc822.h rfc822.c 15 | 16 | simple_mta_SOURCES = simple-mta.c \ 17 | types.h \ 18 | rwbuf.h rwbuf.c \ 19 | rfc821.h rfc821.c \ 20 | rfc822.h rfc822.c 21 | 22 | 23 | INCLUDES = -I$(top_srcdir)/lib $(PTH_CFLAGS) 24 | LDADD = ../lib/libutil.a $(PTH_LIBS) 25 | simple_mta_LDADD = ../lib/libutil.a $(PTH_LIBS) 26 | 27 | if MAINTAINER_MODE 28 | 29 | rfc822: $(srcdir)/rfc822.c 30 | $(COMPILE) -DTESTING -o rfc822 $(srcdir)/rfc822.c ../lib/libutil.a 31 | 32 | misc: $(srcdir)/misc.c 33 | $(COMPILE) -DTESTING -o misc $(srcdir)/misc.c ../lib/libutil.a 34 | 35 | endif 36 | 37 | -------------------------------------------------------------------------------- /src/encrypt: -------------------------------------------------------------------------------- 1 | # Geam - list of recipients which should receive their mail encrypted. 2 | # 3 | # Format is: mail address, encryption system, keyid. 4 | # Leading and trailing white spaces are ignored, lines starting with a 5 | # hash sign and blank lines are ignored. 6 | # An example for OpenPGP is: 7 | # joe@foobar.net gpg 016C7F5C72E26B8DE642D49A5ADFD255F7B080AD 8 | # We have to use the fingerprint of the encryption key here. 9 | # The mail address is not directly used but subject to alias expansion. 10 | # You may use any string without blanks in it here. 11 | # You may also use the short or long keyID instead of the fingerprint. 12 | 13 | joe@foobar.net gpg 016C7F5C72E26B8DE642D49A5ADFD255F7B080AD 14 | 15 | wk@gnupg.de gpg ADF6A6E1 16 | 17 | g10code.de gpg 016C7F5C72E26B8DE642D49A5ADFD255F7B080AD 18 | joe.undercover gpg 016C7F5C72E26B8DE642D49A5ADFD255F7B080AD 19 | foo.bar gpg 016C7F5C72E26B8DE642D49A5ADFD255F7B080AD 20 | 21 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Noteworthy changes in version 0.8.4 (2004-05-07) 2 | ------------------------------------------------ 3 | 4 | * Allow more simultaneous connections and fail only temporary if we 5 | can't allocate a buffer anymore. 6 | 7 | 8 | Noteworthy changes in version 0.8.3 (2004-03-31) 9 | ------------------------------------------------ 10 | 11 | * Fail gracefully on transient errors from MTAs. This is especially 12 | required if the MTA is temporary under a high load and won't accept 13 | new data. 14 | 15 | 16 | Noteworthy changes in version 0.8.0 17 | ----------------------------------- 18 | 19 | * Add a manual in HTML and PS. 20 | * Add option --inner-net 21 | 22 | 23 | Noteworthy changes in version 0.5.3 24 | ----------------------------------- 25 | 26 | * Fixed a race condition. 27 | 28 | 29 | Noteworthy changes in version 0.5.3 30 | ----------------------------------- 31 | 32 | * Add a few other checks to the make check target. 33 | 34 | * Add a few X-Geam-Comment: header 35 | 36 | -------------------------------------------------------------------------------- /lib/xmalloc.h: -------------------------------------------------------------------------------- 1 | /* xmalloc.h 2 | * Copyright (C) 1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef LIBUTIL_XMALLOC_H 22 | #define LIBUTIL_XMALLOC_H 23 | 24 | void *xmalloc( size_t n ); 25 | void *xrealloc( void *a, size_t n ); 26 | void *xcalloc( size_t n, size_t m ); 27 | char *xstrdup( const char *string ); 28 | 29 | 30 | #endif /*LIBUTIL_XMALLOC_H*/ 31 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | /* types.h - Some type defintions for GEAM 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef TYPES_H 22 | #define TYPES_H 23 | 24 | #include 25 | 26 | #ifndef HAVE_BYTE_TYPEDEF 27 | #undef byte /* maybe there is a macro with this name */ 28 | typedef unsigned char byte; 29 | #define HAVE_BYTE_TYPEDEF 30 | #endif 31 | 32 | #endif/*TYPES_H*/ 33 | -------------------------------------------------------------------------------- /src/geamd.h: -------------------------------------------------------------------------------- 1 | /* geamd.h - GEAM daemon main header 2 | * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef GEAMD_H 22 | #define GEAMD_H 23 | 24 | #include "types.h" 25 | 26 | #include "mischelp.h" 27 | #include "xmalloc.h" 28 | #include "logging.h" 29 | #include "stringhelp.h" 30 | 31 | #include "options.h" 32 | #include "rwbuf.h" 33 | 34 | #define _(a) (a) 35 | #define N_(a) (a) 36 | 37 | 38 | #endif/*GEAMD_H*/ 39 | -------------------------------------------------------------------------------- /src/smtpproxy.h: -------------------------------------------------------------------------------- 1 | /* smtpproxy.h 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef SMTPPROXY_H 22 | #define SMTPPROXY_H 23 | 24 | #include 25 | 26 | int smtpproxy_read_configs(void); 27 | int smtpproxy_set_smarthost( const char *inbound_name, int inbound_port, 28 | const char *outbound_name, int outbound_port ); 29 | void *smtpproxy_handler( int fd, const char *sessid, 30 | struct sockaddr *peer_addr, 31 | const char *peer_addr_str, int peer_port ); 32 | 33 | 34 | #endif/*SMTPPROXY_H*/ 35 | -------------------------------------------------------------------------------- /src/aliases: -------------------------------------------------------------------------------- 1 | # Aliases for geam 2 | # 3 | # This file is a mapping of mail addresses to the mail-adressses as used 4 | # in other tables of geam. Only n-to-1 mapping is supported. The first 5 | # entry is used, an asterisk may be used as a wildcard at the beginning of 6 | # a mail address, an address without the at-sign aliases the entire domain. 7 | # wildcards are not yet implemented 8 | # 9 | # Note: When we talk about addresses here we mean the envelope addresses 10 | # and not those found in the rfc822 headers. 11 | # 12 | # Special names on the right side: 13 | # DECRYPT - Allow decryption for these recipients 14 | # 15 | 16 | 17 | # Encrypt all mail to g10code.de using the key "@g10code.de". This 18 | # means that everything for the domain with all mailboxes and all 19 | # subdomains will be encrypted. 20 | 21 | g10code.de : g10code.de 22 | 23 | # Encrypt everything for joe's address at the NSA using his undercover key. 24 | # this is neededed because of the next rule 25 | joe@nsa.gov : joe.undercover 26 | 27 | # Why bother to encrypt something for the NSA at all. 28 | nsa.gov : 29 | 30 | # Do not encrypt the list addresses, but everthing else 31 | announce-list@foo.bar : 32 | announce-list-request@foo.bar : 33 | foo.bar : foo.bar 34 | 35 | gnupg.de: wk@gnupg.de 36 | 37 | wk@gnupg.de: DECRYPT 38 | 39 | foo.net: DECRYPT 40 | 41 | -------------------------------------------------------------------------------- /src/nethelp.h: -------------------------------------------------------------------------------- 1 | /* nethelp.h - network helpers 2 | * Copyright (C) 2000 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef NETHELP_H 22 | #define NETHELP_H 23 | 24 | struct network_address_s; 25 | typedef struct network_address_s *NETWORK_ADDRESS; 26 | 27 | NETWORK_ADDRESS parse_network_address( const char *string ); 28 | void append_network_address( NETWORK_ADDRESS a, NETWORK_ADDRESS b ); 29 | void release_network_address( NETWORK_ADDRESS a ); 30 | int match_network_address( NETWORK_ADDRESS a, struct sockaddr *saddr ); 31 | 32 | 33 | #endif/*NETHELP_H*/ 34 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | GEAM Encrypts Automagically Mail 2 | Version 0.8.3 3 | 4 | 5 | BEWARE: GEAM has not been maintained for many years. IT should 6 | still build fine and work with recent gpg versions. However we have 7 | not done any tests. The source has been pout into a GIT repo for 8 | convenience. 9 | 10 | 11 | Installation: 12 | 13 | ./configure 14 | make 15 | make install 16 | 17 | You need at least GnuPG version 1.0.6 and pth-1.2.1. We have tested 18 | this software only on a GNU/Linux system and we know that the glibc is 19 | required due to the use of "%m" in the printf format strings. 20 | 21 | To test the daemon, you shoud do a "make checks". If this 22 | fails, please make sure that there are no daemons from previous 23 | test hanging around. 24 | 25 | The man page is geamd(8). 26 | 27 | A German manual is available as doc/manual.de.html or in 28 | Postscript as doc/manual.de.ps . 29 | 30 | We appreciate any bug report or feature suggestion but please 31 | understand that we won't help with general installation problems 32 | unless we have agreed on the terms to compensate us. 33 | 34 | WARNING: To use this software you should first acquire a thorough 35 | understanding of it's working and read the manual. The software is in 36 | use for quite sometime now, but be prepared to find a lot of bugs and 37 | strange behavior. 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/rwbuf.h: -------------------------------------------------------------------------------- 1 | /* rwbuf.h - read write buffering 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef RWBUF_H 22 | #define RWBUF_H 23 | 24 | #include "mischelp.h" 25 | 26 | int rw_init( int fd ); 27 | void rw_timeout( int fd, int read_seconds, int write_seconds ); 28 | char *rw_readline( int fd, size_t maxlen, size_t *nbytes, int *truncated ); 29 | int rw_writen( int fd, const char *buffer, size_t length ); 30 | int rw_writestr( int fd, const char *string ); 31 | int rw_printf( int fd, const char *format, ... ) LIBUTIL_GCC_A_PRINTF(2,3); 32 | 33 | 34 | #endif/*RWBUF_H*/ 35 | -------------------------------------------------------------------------------- /src/options.h: -------------------------------------------------------------------------------- 1 | /* options.h - GEAM options 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef OPTIONS_H 22 | #define OPTIONS_H 23 | 24 | #include "nethelp.h" 25 | 26 | struct { 27 | int shutdown_pending; 28 | int quiet; 29 | int verbose; 30 | unsigned int debug; 31 | char *alias_file; 32 | char *encrypt_file; 33 | char *decrypt_file; 34 | char *gpg_binary; 35 | char *gpg_homedir; 36 | NETWORK_ADDRESS inner_nets; 37 | 38 | int received_headers_max; 39 | 40 | } opt; 41 | 42 | #define DBG_VERBOSE (opt.debug & 1) 43 | #define DBG_GPG (opt.debug & 2) 44 | #define DBG_SMTP (opt.debug & 4) 45 | 46 | 47 | #endif/*OPTIONS_H*/ 48 | -------------------------------------------------------------------------------- /lib/mischelp.h: -------------------------------------------------------------------------------- 1 | /* mischelp.h 2 | * Copyright (C) 1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef LIBUTIL_MISCHELP_H 22 | #define LIBUTIL_MISCHHELP_H 23 | 24 | 25 | #define DIM(v) (sizeof(v)/sizeof((v)[0])) 26 | #define DIMof(type,member) DIM(((type *)0)->member) 27 | 28 | 29 | #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) 30 | # define LIBUTIL_GCC_A_NR __attribute__ ((noreturn)) 31 | # define LIBUTIL_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a))) 32 | # define LIBUTIL_GCC_A_NR_PRINTF( f, a ) \ 33 | __attribute__ ((noreturn, format (printf,f,a))) 34 | #else 35 | # define LIBUTIL_GCC_A_NR 36 | # define LIBUTIL_GCC_A_PRINTF( f, a ) 37 | # define LIBUTIL_GCC_A_NR_PRINTF( f, a ) 38 | #endif 39 | 40 | 41 | 42 | #endif /*LIBUTIL_MISCHELP_H*/ 43 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl Configure script source for GEAM 3 | dnl 4 | dnl (Process this file with autoconf to produce a configure script.) 5 | AC_REVISION($Revision$)dnl 6 | AC_PREREQ(2.13) 7 | 8 | AC_INIT(src/geamd.c) 9 | AM_CONFIG_HEADER(config.h) 10 | 11 | dnl 12 | dnl The version number goes here 13 | dnl 14 | AM_INIT_AUTOMAKE(geam,0.8.4) 15 | 16 | 17 | AM_MAINTAINER_MODE 18 | 19 | dnl 20 | dnl Checks for programs 21 | dnl 22 | AC_PROG_CC 23 | AC_STDC_HEADERS 24 | AC_ARG_PROGRAM 25 | AC_PROG_RANLIB 26 | GPH_PROG_DOCBOOK 27 | 28 | dnl 29 | dnl Checks for libraries 30 | dnl 31 | 32 | dnl These are needed by libutil: 33 | AC_CHECK_FUNCS(memicmp stpcpy strlwr strtoul memmove stricmp) 34 | 35 | 36 | AM_PATH_PTH(1.2.1,, 37 | AC_MSG_ERROR([[ 38 | *** 39 | *** Portable Threads Library (pth) found. Please install it first. 40 | *** Download it from ftp://ftp.gnu.org/gnu/pth/ 41 | *** On a Debian GNU/Linux system you might want to try 42 | *** apt-get install libpth-dev 43 | *** 44 | ]])) 45 | 46 | dnl 47 | dnl Checks for header files 48 | dnl 49 | 50 | 51 | dnl 52 | dnl Checks for typedefs and structures 53 | dnl 54 | 55 | GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF) 56 | 57 | 58 | dnl 59 | dnl Checks for compiler features 60 | dnl 61 | 62 | dnl 63 | dnl Checks for library functions 64 | dnl 65 | 66 | 67 | dnl 68 | dnl Checks for system services 69 | dnl 70 | 71 | 72 | if test "$GCC" = yes; then 73 | CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes" 74 | fi 75 | 76 | 77 | AC_OUTPUT_COMMANDS([chmod +x db2html]) 78 | AC_OUTPUT([ 79 | Makefile 80 | db2html 81 | lib/Makefile 82 | src/Makefile 83 | doc/Makefile 84 | doc/version.sgml 85 | doc/localstyle.dsl 86 | tests/Makefile 87 | ]) 88 | -------------------------------------------------------------------------------- /lib/xmalloc.c: -------------------------------------------------------------------------------- 1 | /* xmalloc.c - standard malloc wrappers 2 | * Copyright (C) 1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "libutil-config.h" 26 | #include "xmalloc.h" 27 | 28 | static void 29 | out_of_core(void) 30 | { 31 | fputs("\nfatal: out of memory\n", stderr ); 32 | exit(2); 33 | } 34 | 35 | 36 | void * 37 | xmalloc( size_t n ) 38 | { 39 | void *p = malloc( n ); 40 | if( !p ) 41 | out_of_core(); 42 | return p; 43 | } 44 | 45 | void * 46 | xrealloc( void *a, size_t n ) 47 | { 48 | void *p = realloc( a, n ); 49 | if( !p ) 50 | out_of_core(); 51 | return p; 52 | } 53 | 54 | void * 55 | xcalloc( size_t n, size_t m ) 56 | { 57 | void *p = calloc( n, m ); 58 | if( !p ) 59 | out_of_core(); 60 | return p; 61 | } 62 | 63 | char * 64 | xstrdup( const char *string ) 65 | { 66 | void *p = xmalloc( strlen(string)+1 ); 67 | strcpy( p, string ); 68 | return p; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /lib/logging.h: -------------------------------------------------------------------------------- 1 | /* logging.h 2 | * Copyright (C) 1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef LIBUTIL_LOGGING_H 22 | #define LIBUTIL_LOGGING_H 23 | 24 | #include 25 | #include "mischelp.h" 26 | 27 | void log_set_file( const char *name ); 28 | int log_get_fd(void); 29 | 30 | #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) 31 | void bug_at( const char *file, int line, const char *func ) LIBUTIL_GCC_A_NR; 32 | # define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__ ) 33 | #else 34 | void bug_at( const char *file, int line ); 35 | # define BUG() bug_at( __FILE__ , __LINE__ ) 36 | #endif 37 | 38 | void log_bug( const char *fmt, ... ) LIBUTIL_GCC_A_NR_PRINTF(1,2); 39 | void log_fatal( const char *fmt, ... ) LIBUTIL_GCC_A_NR_PRINTF(1,2); 40 | void log_error( const char *fmt, ... ) LIBUTIL_GCC_A_PRINTF(1,2); 41 | void log_info( const char *fmt, ... ) LIBUTIL_GCC_A_PRINTF(1,2); 42 | void log_debug( const char *fmt, ... ) LIBUTIL_GCC_A_PRINTF(1,2); 43 | void log_printf( const char *fmt, ... ) LIBUTIL_GCC_A_PRINTF(1,2); 44 | 45 | 46 | #endif /*LIBUTIL_LOGGING_H*/ 47 | -------------------------------------------------------------------------------- /lib/libutil-config.h: -------------------------------------------------------------------------------- 1 | /* libutil-config.h - libutil configuration for GAEMibutil functions 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | /**************** 22 | * This header is to be included only by the files in this directory 23 | * it should not be used by other modules. 24 | */ 25 | 26 | #ifndef LIBUTIL_CONFIG_H 27 | #define LIBUTIL_CONFIG_H 28 | 29 | #include 30 | 31 | #ifndef HAVE_BYTE_TYPEDEF 32 | #undef byte /* maybe there is a macro with this name */ 33 | typedef unsigned char byte; 34 | #define HAVE_BYTE_TYPEDEF 35 | #endif 36 | 37 | #include "xmalloc.h" 38 | 39 | /* We don't need gettext for this project */ 40 | #define _(a) (a) 41 | #define N_(a) (a) 42 | 43 | 44 | #define libutil_xmalloc(a) xmalloc( (a) ) 45 | #define libutil_realloc(a,n) xrealloc( (a), (n) ) 46 | #define libutil_strdup(a) xstrdup( (a) ) 47 | #define libutil_free(a) free( (a) ) 48 | 49 | #define libutil_log_debug log_debug 50 | #define libutil_log_info log_info 51 | #define libutil_log_error log_error 52 | #define libutil_log_fatal log_fatal 53 | #define libutil_log_bug log_bug 54 | 55 | #endif /*LIBUTIL_CONFIG_H*/ 56 | -------------------------------------------------------------------------------- /lib/stringhelp.h: -------------------------------------------------------------------------------- 1 | /* stringhelp.h 2 | * Copyright (C) 1998,1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef LIBUTIL_STRINGHELP_H 22 | #define LIBUTIL_STRINGHELP_H 23 | 24 | 25 | const char *memistr( const char *buf, size_t buflen, const char *sub ); 26 | char *mem2str( char *, const void *, size_t); 27 | char *trim_spaces( char *string ); 28 | char *trim_trailing_spaces( char *string ); 29 | unsigned int trim_trailing_chars( unsigned char *line, unsigned len, 30 | const char *trimchars); 31 | unsigned int trim_trailing_ws( unsigned char *line, unsigned len ); 32 | 33 | 34 | #ifndef HAVE_MEMICMP 35 | int memicmp( const char *a, const char *b, size_t n ); 36 | #endif 37 | #ifndef HAVE_STPCPY 38 | char *stpcpy(char *a,const char *b); 39 | #endif 40 | #ifndef HAVE_STRLWR 41 | char *strlwr(char *a); 42 | #endif 43 | #ifndef HAVE_STRTOUL 44 | #define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c))) 45 | #endif 46 | #ifndef HAVE_MEMMOVE 47 | #define memmove(d, s, n) bcopy((s), (d), (n)) 48 | #endif 49 | #ifndef HAVE_STRICMP 50 | #define stricmp(a,b) strcasecmp( (a), (b) ) 51 | #endif 52 | 53 | 54 | #ifndef STR 55 | #define STR(v) #v 56 | #endif 57 | #define STR2(v) STR(v) 58 | 59 | 60 | #endif /*LIBUTIL_STRINGHELP_H*/ 61 | -------------------------------------------------------------------------------- /lib/argparse.h: -------------------------------------------------------------------------------- 1 | /* argparse.h 2 | * Copyright (C) 1998,1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef LIBUTIL_ARGPARSE_H 22 | #define LIBUTIL_ARGPARSE_H 23 | 24 | typedef struct { 25 | int *argc; /* pointer to argc (value subject to change) */ 26 | char ***argv; /* pointer to argv (value subject to change) */ 27 | unsigned flags; /* Global flags (DO NOT CHANGE) */ 28 | int err; /* print error about last option */ 29 | /* 1 = warning, 2 = abort */ 30 | int r_opt; /* return option */ 31 | int r_type; /* type of return value (0 = no argument found)*/ 32 | union { 33 | int ret_int; 34 | long ret_long; 35 | ulong ret_ulong; 36 | char *ret_str; 37 | } r; /* Return values */ 38 | struct { 39 | int idx; 40 | int inarg; 41 | int stopped; 42 | const char *last; 43 | void *aliases; 44 | const void *cur_alias; 45 | } internal; /* DO NOT CHANGE */ 46 | } ARGPARSE_ARGS; 47 | 48 | typedef struct { 49 | int short_opt; 50 | const char *long_opt; 51 | unsigned flags; 52 | const char *description; /* optional option description */ 53 | } ARGPARSE_OPTS; 54 | 55 | 56 | 57 | int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); 58 | int optfile_parse( FILE *fp, const char *filename, unsigned *lineno, 59 | ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); 60 | void usage( int level ); 61 | const char *strusage( int level ); 62 | void set_strusage( const char *(*f)( int ) ); 63 | 64 | #endif /*LIBUTIL_ARGPARSE_H*/ 65 | -------------------------------------------------------------------------------- /src/rfc822.h: -------------------------------------------------------------------------------- 1 | /* rfc822.h 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef RFC822_H 22 | #define RFC822_H 23 | 24 | #include "mischelp.h" 25 | 26 | struct rfc822_data; 27 | typedef struct rfc822_data *RFC822; 28 | 29 | enum rfc822_errors { 30 | RFC822ERR_NOMEM = 1 31 | }; 32 | 33 | enum rfc822_events { 34 | RFC822EVT_OPEN = 1, 35 | RFC822EVT_CLOSE, 36 | RFC822EVT_CANCEL, 37 | RFC822EVT_T2BODY, 38 | RFC822EVT_FINISH, 39 | RFC822EVT_RCVD_SEEN 40 | }; 41 | 42 | struct rfc822_parse_context; 43 | typedef struct rfc822_parse_context *RFC822_PARSE_CTX; 44 | 45 | 46 | char *rfc822_timestamp(char *buffer, size_t buflen ); 47 | 48 | RFC822 rfc822_open( int (*cb)( void *, enum rfc822_events, RFC822 ), 49 | void *cb_value ); 50 | void rfc822_cancel( RFC822 msg ); 51 | void rfc822_close( RFC822 msg ); 52 | 53 | int rfc822_insert( RFC822 msg, char *line, size_t length ); 54 | int rfc822_finish( RFC822 msg ); 55 | 56 | int rfc822_add_header( RFC822 msg, const char *line ); 57 | int rfc822_add_headerf( RFC822 msg, const char *fmt, ... ) 58 | LIBUTIL_GCC_A_PRINTF(2,3); 59 | int rfc822_rename_header( RFC822 msg, const char *oldname, 60 | const char *newname, int which ); 61 | int rfc822_remove_header( RFC822 msg, const char *name, int which ); 62 | 63 | char *rfc822_get_header( RFC822 msg, const char *name, int which ); 64 | const char *rfc822_enum_header_lines( RFC822 msg, void **context ); 65 | const char *rfc822_enum_body_lines( RFC822 msg, void **context, size_t *n ); 66 | 67 | RFC822_PARSE_CTX rfc822_parse_header( RFC822 msg, const char *name, int which ); 68 | void rfc822_release_parse_ctx( RFC822_PARSE_CTX ctx ); 69 | const char *rfc822_query_parameter( RFC822_PARSE_CTX ctx, const char *attr ); 70 | const char *rfc822_query_media_type( RFC822_PARSE_CTX ctx, const char **subtype ); 71 | 72 | 73 | #endif/*RFC822_H*/ 74 | -------------------------------------------------------------------------------- /tests/pubring.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP ARMORED FILE----- 2 | Version: GnuPG v1.0.1b (GNU/Linux) 3 | Comment: For info see http://www.gnupg.org 4 | Comment: Use "gpg --dearmor" for unpacking 5 | 6 | mQGiBDbjtVERBADdUAZzhP6+69VdyRrgRNotouUvXE6I8h0kxZFZZDrQJmpZcNWk 7 | UHDqgbYDJ9RmIeEuWZNmyzPxSFcvD9RGw9KmIZu2kZYqIuzg4KqOyU3SUfNycarE 8 | ZYJkmLEyBlrkNxZkmPCp1cRsMKGCbhQs//v6Iq8h6dNA2EWgJev0y12gcwCguk0K 9 | ZIqVO7UfkaVaZhMr0Cd1at8D/juKnRViDMi9SEjSJZwb3mw1+yECnM8vrM+AoGoA 10 | KiCz/n8N9Gf2DTsFy4yKEskPQ8s09Wc5epBFo3gNruMu4kDnde0uCmiDEbTwzpdS 11 | KZO5x9yi+7b39uCNkgoDlzwonaXNdIn2NnFKjL47TnV/vKFdtSZgLW902vwYGTr1 12 | ArL/BACIcx9TdxsJ9NMyaKD7MEcKQeOrOqv/Mq1HxFPkDBI4hTZpQiId1XTxqkJ6 13 | UHDw9sR/TvtO5YKrZjINkmaBZFiHlx1oyB0B3u6XUVLXIc9liyFyh9aOBdQkdHgj 14 | yI8Kzk6Z0ejYcre5TY4zfplAZKkUDlY3U0Sb0a0xIGhgo3YRELQrWWFua2VlIFRl 15 | c3QgKGRlbW8ga2V5KSA8eWFua2VlQGV4YW1wbGUubmV0PohVBBMRAgAVBQI247VR 16 | AwsKAwMVAwIDFgIBAheAAAoJEJ7vNM1LEbJfSQQAoJRRe9UHKHiX2iFczXq6nrvr 17 | 0NhLAJ99W/I5b2/2QQ01we8i1mcSYPWj47kBDQQ247VnEAQAmuK5RcS0zTyXp6Sj 18 | W2+WeQIpJnJDflL0+iBe//3SADv01qUmw3jWMAuxG+CcCApksl122V9npEHiLC4Q 19 | 2A69roLRsbxKBPebustfadLJoVYqPsvjnrBlafe5GcrFPnKbE0wV6ZXx/Tp/eSDi 20 | Qlid4lWz5J+z/mN7KhHANzoRAbsAAwYEAJO5fkCSdNwkisFXzeKslWxm9Yoe1TOo 21 | uiSV11hex0j94Hpz5wGWEXF7z+FbDq+4V0UqGkKxaERsl6HMWNkImj57N/9h1C1Y 22 | DfiKTimg5tZpKmehXtldpWGCNDZrE0RasrFCKENVhFMhpc4kAnx6rbA0+LhRvJkv 23 | kdxY7pKU//aZiEYEGBECAAYFAjbjtWcACgkQnu80zUsRsl/0XACfffuI4IS7cgh0 24 | PNghr/0v3L/NhncAoJNwutmN7kkv9n/oPqkByzLxvZt4mQGiBDbjtcsRBACBDJOG 25 | X9C/xxCVZNP6OHz6cL5vM3PimUAhV+9HAVVPQViTnFKrkYPSQyRfWzjOU8RO1Tp5 26 | CHz747oOb6j9P74yH1uy78yFg4UuhXBWinhuCKKq4IIWwJkCKBFr1U8fu8a6Y6Nc 27 | jqiDA0KmGRJrMPmXenXkJpFGHG78rUvNi9IMfwCgugzNILh/3XZCZU+BUPYeXL+n 28 | UAEEAIDXZhj1vFXHgi9lmijKDjJocEBoamN/taQy6Ox1RRD6HtfAPY5TER1n7xm9 29 | hMzE+Ov1IKpH/E872Rha1qu1v7eOa6eTuNWF0NvmSR955freRsNuR8JNIb6StI2E 30 | R9pzBUfjykC9pg2wPeC7wpQJIF9TF+Ja1BvG2I+ha2xJ786AA/sHEUvAOsc58YbP 31 | lbIPyp2JdEHvXTRT2NISVRuTMQsg8vV99nMYR2CUh270uPyy2xZaD/kYcJ9/1ngY 32 | 7C9pbbNWoV70PkEMO/qj67OIViWVPzUhIdURorbpGhuc3oBzUxOgial7IbISPRIt 33 | Dgg2oZoY4hqyQNx8Cj2ZZAzDpM2vCrQnWnVsdSBUZXN0IChkZW1vIGtleSkgPHp1 34 | bHVAZXhhbXBsZS5uZXQ+iFUEExECABUFAjbjtcsDCwoDAxUDAgMWAgECF4AACgkQ 35 | a8R3gFSs0kZA6wCeJUyRzuFbsZ0uQulvpgOIRTLTKscAoLd3InVEj20peTUQ5b2N 36 | OimSXnKxuQENBDbjtfIQBADMfPDBQoMzv52Mmjb8SdaYKKNzqDd9K1oY2hcMSi+L 37 | cHag+KJFOyKBf3SoHmcU/vCEN+LyTgljYSKDmEf4wZ2+eLfqFgSdBJp2xm55ih+9 38 | CHXg3dXx9SbHiGJCIxfJaIsnNz3VmJGPDDjBlaf/hjl/7SZvR+MJpVLFPGjj7uOh 39 | TwADBQP/Sgv0abeCXVdVXwGEmhdV0VDo833IQRdRu1yt+QLnWRMGTY1oQapsH6QL 40 | wYSZfDJlxbsBA3tfqKStpRSbdGNNTsK+RIehsGddi3sWGplRGm5Xt5KpkY/mc/tL 41 | FaYJNMqAgfWQcKlZHBp7EoWMgiRiDJUWq0TH1wRDoPaRc+H5GdqIRgQYEQIABgUC 42 | NuO18gAKCRBrxHeAVKzSRn1jAKC5Gp5sHM9sWdZeM6qfu54F2OwMQACfTjYXfpMA 43 | pAROPkjhhFNqH0d8x5E= 44 | =vjtZ 45 | -----END PGP ARMORED FILE----- 46 | -------------------------------------------------------------------------------- /src/rfc821.h: -------------------------------------------------------------------------------- 1 | /* rfc821.h 2 | * Copyright (C) 1999 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #ifndef RFC821_H 22 | #define RFC821_H 23 | 24 | #include "rfc822.h" 25 | 26 | struct rfc821_state; 27 | typedef struct rfc821_state *RFC821; 28 | 29 | enum rfc821_errors { 30 | RFC821ERR_NONE = 0, 31 | RFC821ERR_GENERAL, 32 | RFC821ERR_NOMEM, 33 | RFC821ERR_CONFLICT, 34 | RFC821ERR_NOSERVICE, 35 | RFC821ERR_SEND, 36 | RFC821ERR_RECV, 37 | RFC821ERR_CMDSEQ, 38 | RFC821ERR_PATH, 39 | RFC821ERR_TEMP 40 | }; 41 | 42 | enum rfc821_flags { 43 | RFC821FLG_VERBOSE = 1, 44 | RFC821FLG_DBGSMTP = 2 45 | }; 46 | 47 | enum rfc821_events { 48 | RFC821EVT_DATA, /* After basic checks of the data command */ 49 | RFC821EVT_DATA_END, /* After reading all data, before rfc822 close */ 50 | }; 51 | 52 | 53 | RFC821 rfc821_open( int (*cb)( void *, enum rfc821_events, RFC821 ), 54 | void *cb_value ); 55 | void rfc821_set_proto_comment( RFC821 state, const char *comment ); 56 | void rfc821_set_flag( RFC821 state, enum rfc821_flags flag, int value ); 57 | void rfc821_set_rfc822_cb( RFC821 hd, 58 | int (*cb)( void *, enum rfc822_events, RFC822 ), 59 | void *cb_value ); 60 | int rfc821_handler( RFC821 state, int fd, 61 | const char *peer_addr_str, int peer_port ); 62 | void rfc821_cancel( RFC821 hd ); 63 | void rfc821_close( RFC821 hd ); 64 | int rfc821_reply( int fd, int code, const char *desc ); 65 | 66 | int rfc821_start_session( RFC821 state, int fd ); 67 | int rfc821_send_sender( RFC821 state, const char *path ); 68 | int rfc821_send_recipient( RFC821 state, const char *path ); 69 | int rfc821_send_body_line( RFC821 state, const char *line, size_t length ); 70 | 71 | const char *rfc821_query_sender( RFC821 state ); 72 | const char *rfc821_enum_recipients( RFC821 state, void **context ); 73 | 74 | int rfc821_copy_header_lines( RFC821 smtp, RFC822 msg ); 75 | int rfc821_copy_body_lines( RFC821 smtp, RFC822 msg ); 76 | 77 | #endif/*RFC821_H*/ 78 | -------------------------------------------------------------------------------- /tests/secring.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP ARMORED FILE----- 2 | Version: GnuPG v1.0.1b (GNU/Linux) 3 | Comment: For info see http://www.gnupg.org 4 | Comment: Use "gpg --dearmor" for unpacking 5 | 6 | lQG7BDbjtVERBADdUAZzhP6+69VdyRrgRNotouUvXE6I8h0kxZFZZDrQJmpZcNWk 7 | UHDqgbYDJ9RmIeEuWZNmyzPxSFcvD9RGw9KmIZu2kZYqIuzg4KqOyU3SUfNycarE 8 | ZYJkmLEyBlrkNxZkmPCp1cRsMKGCbhQs//v6Iq8h6dNA2EWgJev0y12gcwCguk0K 9 | ZIqVO7UfkaVaZhMr0Cd1at8D/juKnRViDMi9SEjSJZwb3mw1+yECnM8vrM+AoGoA 10 | KiCz/n8N9Gf2DTsFy4yKEskPQ8s09Wc5epBFo3gNruMu4kDnde0uCmiDEbTwzpdS 11 | KZO5x9yi+7b39uCNkgoDlzwonaXNdIn2NnFKjL47TnV/vKFdtSZgLW902vwYGTr1 12 | ArL/BACIcx9TdxsJ9NMyaKD7MEcKQeOrOqv/Mq1HxFPkDBI4hTZpQiId1XTxqkJ6 13 | UHDw9sR/TvtO5YKrZjINkmaBZFiHlx1oyB0B3u6XUVLXIc9liyFyh9aOBdQkdHgj 14 | yI8Kzk6Z0ejYcre5TY4zfplAZKkUDlY3U0Sb0a0xIGhgo3YREAAAn1hOeokhtSHV 15 | KsEIIIClLY5iad7RCYH9JiM6RFNBX2ZhY3RvcjoAAK9cLaRT6JcG2kFGv+UJs6Nv 16 | 3tgAGTEl/SYjOkRTQV9mYWN0b3I6AACvUn79p77RGDELzTQ3dA75wTQaMZQEuf0m 17 | IzpEU0FfZmFjdG9yOgAAr2eYSfk5dBbbwwviV9LMKKEMzwxjQjm0K1lhbmtlZSBU 18 | ZXN0IChkZW1vIGtleSkgPHlhbmtlZUBleGFtcGxlLm5ldD6IVQQTEQIAFQUCNuO1 19 | UgMLCgMDFQMCAxYCAQIXgAAKCRCe7zTNSxGyX1exAKCQACs4HkR+NIPptcV+WXz+ 20 | kJwnKACgm02TEqNB+/YOmZ9sGW3RFRsJo/qdAZIENuO1ZxAEAJriuUXEtM08l6ek 21 | o1tvlnkCKSZyQ35S9PogXv/90gA79NalJsN41jALsRvgnAgKZLJddtlfZ6RB4iwu 22 | ENgOva6C0bG8SgT3m7rLX2nSyaFWKj7L456wZWn3uRnKxT5ymxNMFemV8f06f3kg 23 | 4kJYneJVs+Sfs/5jeyoRwDc6EQG7AAMGBACTuX5AknTcJIrBV83irJVsZvWKHtUz 24 | qLoklddYXsdI/eB6c+cBlhFxe8/hWw6vuFdFKhpCsWhEbJehzFjZCJo+ezf/YdQt 25 | WA34ik4poObWaSpnoV7ZXaVhgjQ2axNEWrKxQihDVYRTIaXOJAJ8eq2wNPi4UbyZ 26 | L5HcWO6SlP/2mQAD/2gWcysv/hclqsB8MA0WXGJdxKJQguHFguyLk2nVDn5a5rDM 27 | OIE2i4FCVrY6AZsvfQfTD7uCbv5nxuoH9sWn3TjIrGQJqfyW8TF9JhmXPHhNizJw 28 | 76PH4aheSCYLauNIe3AxIgsGfgkfG+w6WK8BcxWY4QF3lst9fYElKCJM7FiZOvWI 29 | RgQYEQIABgUCNuO1ZwAKCRCe7zTNSxGyX/RcAJ9X3N2PPlX0KeNxUHefqmpPYDF6 30 | GgCfZmyC/OlrmmSulJ6NAHxiQNT4D/aVAbsENuO1yxEEAIEMk4Zf0L/HEJVk0/o4 31 | fPpwvm8zc+KZQCFX70cBVU9BWJOcUquRg9JDJF9bOM5TxE7VOnkIfPvjug5vqP0/ 32 | vjIfW7LvzIWDhS6FcFaKeG4IoqrgghbAmQIoEWvVTx+7xrpjo1yOqIMDQqYZEmsw 33 | +Zd6deQmkUYcbvytS82L0gx/AKC6DM0guH/ddkJlT4FQ9h5cv6dQAQQAgNdmGPW8 34 | VceCL2WaKMoOMmhwQGhqY3+1pDLo7HVFEPoe18A9jlMRHWfvGb2EzMT46/Ugqkf8 35 | TzvZGFrWq7W/t45rp5O41YXQ2+ZJH3nl+t5Gw25Hwk0hvpK0jYRH2nMFR+PKQL2m 36 | DbA94LvClAkgX1MX4lrUG8bYj6FrbEnvzoAD+wcRS8A6xznxhs+Vsg/KnYl0Qe9d 37 | NFPY0hJVG5MxCyDy9X32cxhHYJSHbvS4/LLbFloP+Rhwn3/WeBjsL2lts1ahXvQ+ 38 | QQw7+qPrs4hWJZU/NSEh1RGitukaG5zegHNTE6CJqXshshI9Ei0OCDahmhjiGrJA 39 | 3HwKPZlkDMOkza8KAACgi7AlPWgokH0wXVOPBksrCRkogGEG8P0mIzpEU0FfZmFj 40 | dG9yOgAAr2d3aB0MZev5pLgf1E2jbVUvw6wokGP9JiM6RFNBX2ZhY3RvcjoAAK9d 41 | PtNQrKDy9rpfRFOgRaDj594MkUSf/SYjOkRTQV9mYWN0b3I6AACvSz8HFdENaOMK 42 | pk0jlUqYYPcRDYIJY7QnWnVsdSBUZXN0IChkZW1vIGtleSkgPHp1bHVAZXhhbXBs 43 | ZS5uZXQ+iFUEExECABUFAjbjtcsDCwoDAxUDAgMWAgECF4AACgkQa8R3gFSs0kZA 44 | 6wCeOBSNOP3/J4LLMGDC7YWzVnYcH1oAoJh1THc6xw3dCapVWt7enBljkaZInQGS 45 | BDbjtfIQBADMfPDBQoMzv52Mmjb8SdaYKKNzqDd9K1oY2hcMSi+LcHag+KJFOyKB 46 | f3SoHmcU/vCEN+LyTgljYSKDmEf4wZ2+eLfqFgSdBJp2xm55ih+9CHXg3dXx9SbH 47 | iGJCIxfJaIsnNz3VmJGPDDjBlaf/hjl/7SZvR+MJpVLFPGjj7uOhTwADBQP/Sgv0 48 | abeCXVdVXwGEmhdV0VDo833IQRdRu1yt+QLnWRMGTY1oQapsH6QLwYSZfDJlxbsB 49 | A3tfqKStpRSbdGNNTsK+RIehsGddi3sWGplRGm5Xt5KpkY/mc/tLFaYJNMqAgfWQ 50 | cKlZHBp7EoWMgiRiDJUWq0TH1wRDoPaRc+H5GdoAA/94kCcIF9j9MAyak0NzEDmx 51 | PfVYkJJnPIfkWfj0amC+3a8meScCY1K5BBitrgdx5kzX8Ldw/BLXMYFytCWZOuNs 52 | cUIWIcwXJmHmGprDavIIr9m1E4nkAS6HaJRUmi4rmr/5O5bQrF6oP7+l/5HJUOHL 53 | 4H9RzFzH1lM1WvO56Sq160G4iEYEGBECAAYFAjbjtfIACgkQa8R3gFSs0kZ9YwCb 54 | Bd87sGdPaO09MmTZuM1nERmb7XgAoK6C61XVLjcW3RJZR+AW3LxQdOsw 55 | =/4OQ 56 | -----END PGP ARMORED FILE----- 57 | -------------------------------------------------------------------------------- /db2html.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # db2html.in - Docbook to HTML rendering 3 | # 4 | # Copyright (C) 2000 Free Software Foundation 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | 20 | version=0.5 21 | nosplit=no 22 | copyfiles=no 23 | stylesheet=@DSL_FOR_HTML@ 24 | JADE=@JADE@ 25 | 26 | usage () { 27 | echo 'usage: db2html [--nosplit] [--copyfiles] filename' >&2 28 | exit 1 29 | } 30 | 31 | 32 | while test "`echo $1 | head -c1`" = "-"; do 33 | case $1 in 34 | --version) 35 | cat <&2 60 | exit 1 61 | ;; 62 | esac 63 | shift 64 | done 65 | 66 | if test $# = 1; then 67 | input="$1" 68 | else 69 | usage 70 | fi 71 | 72 | # grep the document type 73 | doctype=`grep -i '\&2 77 | else 78 | echo "DOCTYPE is '$doctype'" >&2 79 | fi 80 | 81 | output="`basename $input| sed 's/\.sgml$//'`.html" 82 | 83 | 84 | if test $nosplit = yes; then 85 | echo "running jade on '$input' ..." >&2 86 | $JADE -d $stylesheet -t sgml -i html -V nochunks $input > $output 87 | echo "$output created" 88 | exit 0 89 | fi 90 | 91 | if test -d html ; then 92 | : 93 | else 94 | if mkdir html; then 95 | echo "'html' directory created" >&2 96 | else 97 | echo "failed to create 'html' directory" >&2 98 | exit 1 99 | fi 100 | fi 101 | 102 | outputdir="html/`basename $input| sed 's/\.sgml$//'`" 103 | 104 | if test -d $outputdir ; then 105 | : 106 | else 107 | if mkdir $outputdir; then 108 | echo "'$outputdir' created" >&2 109 | else 110 | echo "failed to create '$outputdir'" >&2 111 | exit 1 112 | fi 113 | fi 114 | echo "creating html pages in '$outputdir' ..." >&2 115 | if test "$input" = "`basename $input`"; then 116 | inp="../../$input" 117 | else 118 | inp="$input" 119 | fi 120 | echo "running jade on '$inp' ..." >&2 121 | (cd $outputdir && $JADE -t sgml -i html -d $stylesheet $inp ) 122 | echo "html version in '$outputdir' created" >&2 123 | 124 | # break out all filerefs and copy them to the outputdirectory 125 | # fixme: handling of path components is wrong 126 | if test $copyfiles = yes; then 127 | echo "looking for filerefs ..." >&2 128 | for file in `nsgmls -i html $input \ 129 | | awk '/^AFILEREF[ \t]+CDATA/ {print $3}'`; do 130 | d=$outputdir/`basename $file` 131 | if cat $file > $outputdir/`basename $file` ; then 132 | echo " $file -> $d" >&2 133 | fi 134 | done 135 | fi 136 | 137 | mainfile=`ls $outputdir/${doctype}* | head -1` 138 | 139 | cat > $output <$output 141 | 142 | 143 | $mainfile 144 | 145 | 146 | 147 | EOF 148 | 149 | echo "$output created with link to '$mainfile'" >&2 150 | 151 | exit 0 152 | 153 | -------------------------------------------------------------------------------- /doc/geamd.sgml: -------------------------------------------------------------------------------- 1 | 20 | 21 | 23 | 24 | geamd"> 25 | directory"> 26 | file"> 27 | &ParmFile;"> 28 | files"> 29 | &ParmFiles;"> 30 | names"> 31 | &ParmNames;"> 32 | name"> 33 | &ParmName;"> 34 | key IDs"> 35 | n"> 36 | flags"> 37 | string"> 38 | value"> 39 | name=value"> 40 | ]> 41 | 42 | 43 | 44 |
45 | wk@gnupg.org 46 |
47 | 48 | Werner 49 | Koch 50 | 51 | 1999-12-28 52 |
53 | 54 | geamd 55 | 8 56 | GNU Tools 57 | 58 | 59 | geamd 60 | An SMTP encryption daemon 61 | 62 | 63 | 64 | geamd 65 | options 66 | 67 | 68 | 69 | 70 | DESCRIPTION 71 | 72 | The &geamd; is a SMTP proxy which is able to encrypt 73 | or decrypt mail on the fly. It is not a full MTA as it depends 74 | on smarthosts for routing. 75 | 76 | 77 | 78 | 79 | &geamdoptions; 80 | 81 | 82 | SEE ALSO 83 | 84 | gpg(1) 85 | 86 | 87 | 88 | 89 | WARNINGS 90 | This software is intended to encrypt all mail at a site. It 91 | is highly recommended to install and use it only after learning how 92 | to configure it and to know what it can do and what it cannot do. 93 | 94 | This software is only as secure as the machine it is running on 95 | is. Never install valuable secure keys on that machine. It seems to be 96 | a good way to use only an encryption subkey with a limited lifetime and 97 | make the primary key unusable; this way a stolen key can easily be replaced 98 | without loosing the certificates. Newer version of GnuPG support this; 99 | see the GnuPG FAQ on how to do it 100 | 101 | 102 | 103 | 104 | BUGS 105 | No serious bugs are known; your mileage may vary. 106 | Please report them to geam@g10code.com and 107 | do not forget to include the version of the program and all 108 | the information to reproduce the problem. Do dot send secret keys! 109 | A bug report may be forwarded to a public mailing list. 110 | 111 | 112 | 113 |
114 | 115 | -------------------------------------------------------------------------------- /src/nethelp.c: -------------------------------------------------------------------------------- 1 | /* nethelp.c - network helper functions 2 | * Copyright (C) 2000 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "types.h" 31 | #include "xmalloc.h" 32 | #include "nethelp.h" 33 | 34 | struct network_address_s { 35 | struct network_address_s *next; 36 | ulong addr; /* (in host byte order) */ 37 | ulong mask; 38 | }; 39 | 40 | 41 | /**************** 42 | * input string should be syntactically correct. 43 | * Returns pointer to next character + 1 44 | */ 45 | static const char * 46 | get_dotted_quad( const char *s, ulong *retval ) 47 | { 48 | ulong value = 0; 49 | int i; 50 | 51 | for(i=24; *s && i >= 0; s++, i -= 8 ) { 52 | int n = atoi(s); 53 | if( n < 0 || n > 255 ) 54 | return NULL; 55 | value |= (n&0xff) << i; 56 | while( isdigit(*s) ) 57 | s++; 58 | } 59 | *retval = value; 60 | return s; 61 | } 62 | 63 | /**************** 64 | * Parse a network address and return an object describing 65 | * address and the mask. Returns NULL on error. Caller must 66 | * free the returned object using release_network_address. 67 | * 68 | * Valid address formats are: 69 | * 70 | * a.a.a.a - mask will either be one for a A,B or C class nentwork 71 | * a.a.a.a/m - mask is m hight bits set, rest of the nbits are low 72 | * a.a.a.a/m.m.m.m - mask exactly specified 73 | * 74 | * IPv6 is not yet supported but can be done entirely inside this modules 75 | * because the return data type is only know here. A user should always 76 | * use one of the functions here. 77 | */ 78 | NETWORK_ADDRESS 79 | parse_network_address( const char *string ) 80 | { 81 | int a_dots, m_dots, digs, m_digs, slashes; 82 | const char *s; 83 | ulong addr, mask; 84 | NETWORK_ADDRESS na; 85 | 86 | 87 | /* count dots and slashes and check for invalid characters */ 88 | a_dots = m_dots = digs = m_digs = slashes = 0; 89 | for( s = string; *s; s++ ) { 90 | if( isdigit( *s ) ) { 91 | digs++; 92 | } 93 | else { 94 | if( !digs || digs > 3 ) 95 | return NULL; 96 | digs = 0; 97 | if( *s == '/' ) 98 | slashes++; 99 | else if( !slashes && *s == '.' ) 100 | a_dots++; 101 | else if( *s == '.' ) 102 | m_dots++; 103 | else 104 | return NULL; 105 | } 106 | } 107 | if( !digs || digs > 3 || slashes > 1 || a_dots != 3 108 | || ( !slashes && m_dots ) || ( slashes && m_dots != 0 && m_dots != 3)){ 109 | return NULL; 110 | } 111 | 112 | string = get_dotted_quad( string, &addr ); 113 | if( !string ) 114 | return NULL; 115 | if( slashes ) { 116 | if( !*string ) 117 | return NULL; 118 | if( m_dots ) { 119 | string = get_dotted_quad( string, &mask ); 120 | if( !string ) 121 | return NULL; 122 | } 123 | else { 124 | int i, n = atoi(string); 125 | if( n < 0 || n > 32 ) 126 | return NULL; 127 | for( mask=0, i=n-1; i >= 0; i-- ) { 128 | mask |= 0x80000000 >> i; 129 | } 130 | } 131 | 132 | } 133 | else { /* calculate mask from the address */ 134 | int i = (addr & 0xff000000) >> 24; 135 | if( i < 128 ) 136 | mask = 0xff000000; 137 | else if( i < 192 ) 138 | mask = 0xffff0000; 139 | else /* class C. we return this also for class D and E networks */ 140 | mask = 0xffffff00; 141 | } 142 | na = xcalloc(1, sizeof *na ); 143 | na->addr = addr; 144 | na->mask = mask; 145 | return na; 146 | } 147 | 148 | void 149 | release_network_address( NETWORK_ADDRESS a ) 150 | { 151 | NETWORK_ADDRESS a2; 152 | 153 | while( a ) { 154 | a2 = a->next; 155 | free( a ); 156 | a = a2; 157 | } 158 | } 159 | 160 | /**************** 161 | * Append address list b to the end of the list with addresses b 162 | * Do not use b later on. 163 | */ 164 | void 165 | append_network_address( NETWORK_ADDRESS a, NETWORK_ADDRESS b ) 166 | { 167 | while( a->next ) 168 | a = a->next; 169 | a->next = b; 170 | } 171 | 172 | /**************** 173 | * Tell whether saddr matches on of the network addresses. 174 | */ 175 | int 176 | match_network_address( NETWORK_ADDRESS a, struct sockaddr *saddr ) 177 | { 178 | if( saddr->sa_family == AF_INET ) { 179 | ulong addr = ntohl(((struct sockaddr_in *)saddr)->sin_addr.s_addr); 180 | for( ; a; a = a->next ) { 181 | if( (a->addr & a->mask) == (addr & a->mask) ) { 182 | return 1; /* match */ 183 | } 184 | } 185 | } 186 | return 0; 187 | } 188 | 189 | 190 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2005-06-27 Werner Koch 2 | 3 | * src/Makefile.am (simple_mta_LDADD): Add LIBPTH. 4 | 5 | 2004-05-07 Werner Koch 6 | 7 | Released 0.8.4. 8 | 9 | 2004-04-21 Werner Koch 10 | 11 | * src/smtpproxy.c (prepare_encryption): Don't bail out if a 12 | boundary is still set. 13 | 14 | 2004-04-20 Werner Koch 15 | 16 | * src/rfc821.c (rfc821_reply): Made global. 17 | 18 | * src/smtpproxy.c (open_smarthost): Fail only temporary if we 19 | can't allocate a buffer. Not really useful though. 20 | (smtpproxy_handler): Keep a connection counter and limit the 21 | number of connections to 200. 22 | * src/rwbuf.c (MAX_FDS): Bumped up from 40 to 1024. 23 | 24 | 2004-03-31 Werner Koch 25 | 26 | Released 0.8.3 27 | 28 | * src/simple-mta.c: New option --loaded. 29 | * tests/basic: Add 2 tests to check temporary failures. 30 | * src/smtpproxy.c (cb_from_rfc822): Set the new state variable 31 | FAIL_DATA_TEMP. 32 | (cb_from_rfc821): Return a different error if we have a temporary 33 | failure. 34 | (open_smarthost, copy_data): New arg TEMP_FAILURE. 35 | * src/rfc821.c (rfc821_proc_data): Return 451 depending on what 36 | the callback wants. 37 | (rfc821_start_session): Distinguish between temporary and 38 | permanent errors. 39 | (rfc821_send_sender, rfc821_send_recipient) 40 | (rfc821_copy_header_lines): Ditto. 41 | 42 | 2003-08-12 Werner Koch 43 | 44 | * src/rfc821.c (rfc821_send_body_line): Don't write the DATA END 45 | command if we did not send a DATA command. 46 | (rfc821_send_body_line): Return an error if we didn't send a DATA. 47 | 48 | 2001-06-19 Werner Koch 49 | 50 | Released 0.8.2 51 | 52 | * tests/basic: Don't reset the daemon's pid so that it will be 53 | killed by do_exit. 54 | 55 | * src/smtpproxy.c (run_check_decryption_command): Just ignore 56 | error to do the fact that gpg may return an error in --list-only 57 | decryption mode. 58 | 59 | * src/rfc822.c, src/geamd.c: Use time.h 60 | * src/geamd.c: Changed bug reporting address and copyright notice. 61 | 62 | 2001-03-22 Werner Koch 63 | 64 | * src/geamd.conf,src/encrypt,src/decrypt,src/aliases: Typo fixes. 65 | * doc/geamd.sgml: Typo fix. 66 | * doc/geamd-options.sgml: Fixed name of a default filename. 67 | 68 | 2000-07-26 15:50:57 Werner Koch (wk@gnupg.org) 69 | 70 | Version 0.8.1 released 71 | 72 | 2000-04-12 13:11:00 Werner Koch (wk@habibti.openit.de) 73 | 74 | * acinclude.m4 (GPH_PROG_DOCBOOK): export DSL_FOR_TEX 75 | * configure.in: Create a doc/localstyle.dsl 76 | * doc/localstyle.dsl.in: New 77 | 78 | 2000-03-02 17:23:39 Werner Koch (wk@habibti.gnupg.de) 79 | 80 | * doc/version.sgml.in: New. 81 | 82 | * Released version 0.8.0. 83 | 84 | 2000-03-02 15:09:27 Werner Koch (wk@habibti.gnupg.de) 85 | 86 | * src/nethelp.c: New. 87 | * src/nethelp.h: New. 88 | * src/options.h: New field inner_nets. 89 | * src/smtproxy.c (is_sender_local): Implemented. 90 | (smtpproxy_handler): Add new arg peer_addr. 91 | * src/geamd.c: Pass the sockaddr down to the handler. 92 | (main): New option --inner-net. 93 | * doc/geamd-options.c: Add new option. 94 | 95 | 2000-02-24 14:18:22 Werner Koch (wk@bilbo.gnupg.de) 96 | 97 | * doc/geamd.sgml: Moved parts to ... 98 | * doc/geamd-options.sgml: ... this new file. 99 | 100 | 2000-02-10 16:35:05 Werner Koch (wk@gnupg.org) 101 | 102 | * src/smtpproxy.c (read_encrypt_table): Allow to give keyIDs instead 103 | of fingerprints. 104 | 105 | 2000-02-09 14:59:53 Werner Koch (wk@gnupg.org) 106 | 107 | * Makefile.am: Add new subdirectory doc. 108 | * src/Makefile.am: Removed the documentaion parts. 109 | * doc/Makefile.am: New and readded the documenation parts 110 | * doc/manual.de.sgml: New. 111 | * src/geamd.sgml: Moved to ... 112 | * doc/geamd.sgml: .. here. 113 | 114 | 2000-01-26 09:23:06 Werner Koch (wk@bilbo.gnupg.de) 115 | 116 | * src/smtpprox.c (encryption_callback): Do a pth_join(). 117 | (check_decryption_callback): Ditto. 118 | (decryption_callback): Ditto. 119 | 120 | 2000-01-19 17:08:16 Werner Koch (wk@gnupg.org) 121 | 122 | * src/rfc822.c (rfc822_add_headerf): New. 123 | * src/smtpproxy.c (open_smarthost): Add some comment lines to 124 | the message. Add one argument to the function and adapted all callers. 125 | 126 | * src9rfc822.c (rfc822_timestamp: New. 127 | * src/rfc821.c (mk_timestamp): Removed and replaced all calls by 128 | rfc822_timestamp. 129 | * src/smtpprox.c (decrypt_eater): Add a comment with the timestamp. 130 | 131 | * Released version 0.5.3 132 | 133 | 2000-01-19 13:36:56 Werner Koch (wk@gnupg.org) 134 | 135 | * Released version 0.5.2 136 | 137 | 2000-01-19 10:37:53 Werner Koch (wk@bilbo.gnupg.de) 138 | 139 | * src/geamd.c (change_userid): New. 140 | (main): Add new options --user and --goup and use them. 141 | 142 | * src/geamd.c (become_daemon): Don't catch SIGCHLD here, this 143 | leads to problems with waitpid due to different semantics. 144 | 145 | * tests: Add the test directory and a basic test 146 | 147 | 2000-01-12 09:21:59 Werner Koch (wk@bilbo.gnupg.de) 148 | 149 | * src/rfc821.c (rfc821_parse_cmd): Made static. 150 | 151 | * src/rfc821.c (rfc821_set_flag): New and used the flags at 152 | some places to enable debugging output. 153 | * src/geamd.c (main): Set the rfc821 flag when requested. 154 | (handlesignals): set/clear the rfc821 smtp debug flag when 155 | verbosity is changed to/from level 3. 156 | * src/geamd.sgml: Documented these changes. 157 | 158 | * src/smtpproxy.c (dummy_eater): New. 159 | (check_decryption_callback): Pass output to the dummy eater and 160 | don't use signalling to kill gpg as this badly interferes with some 161 | problems in early glibc2. 162 | 163 | * Released version 0.5.1 164 | 165 | 2000-01-11 14:10:38 Werner Koch (wk@bilbo.gnupg.de) 166 | 167 | * acinclude.m4 (AM_PATH_PTH): Add --ldflags. 168 | 169 | * src/smtpproxy.c (open_smarthost): Use orignal recipients 170 | and not the ones from the alises table for encryption. 171 | 172 | 2000-01-06 15:54:04 Werner Koch (wk@gnupg.org) 173 | 174 | * Released version 0.5.0 175 | 176 | 1999-12-28 13:12:00 Werner Koch (wk@gnupg.org) 177 | 178 | * Released version 0.1.0 179 | 180 | -------------------------------------------------------------------------------- /lib/logging.c: -------------------------------------------------------------------------------- 1 | /* logging.c - useful logging functions 2 | * Copyright (C) 1998, 1999 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GnuPG. 5 | * 6 | * GnuPG is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GnuPG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | 22 | /* This file should replace logger.c in the future - for now it is not 23 | * used GnuPG. 24 | * It is a quite simple implemenation but sufficient for most purposes. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "libutil-config.h" 36 | #include "logging.h" 37 | 38 | enum my_log_levels { 39 | MY_LOG_BEGIN, /* only print the timestamp if configured */ 40 | MY_LOG_CONT, 41 | MY_LOG_INFO, 42 | MY_LOG_WARN, 43 | MY_LOG_ERROR, 44 | MY_LOG_FATAL, 45 | MY_LOG_BUG, 46 | MY_LOG_DEBUG 47 | }; 48 | 49 | static FILE *logstream; 50 | static int use_time; 51 | static int missing_lf; 52 | 53 | #if 0 54 | static void 55 | write2stderr( const char *s ) 56 | { 57 | write( 2, s, strlen(s) ); 58 | } 59 | 60 | 61 | static void 62 | do_die(int rc, const char *text ) 63 | { 64 | write2stderr("\nFatal error: "); 65 | write2stderr(text); 66 | write2stderr("\n"); 67 | abort(); 68 | } 69 | #endif 70 | 71 | void 72 | log_set_file( const char *name ) 73 | { 74 | FILE *fp = (name && strcmp(name,"-"))? fopen(name, "a") : stderr; 75 | if( !fp ) { 76 | fprintf(stderr, "failed to open log file `%s': %s\n", 77 | name, strerror(errno)); 78 | return; 79 | } 80 | setvbuf( fp, NULL, _IOLBF, 0 ); 81 | 82 | if( logstream && logstream != stderr ) 83 | fclose( logstream ); 84 | logstream = fp; 85 | use_time = fp != stderr; 86 | missing_lf = 0; 87 | } 88 | 89 | 90 | int 91 | log_get_fd() 92 | { 93 | return fileno(logstream?logstream:stderr); 94 | } 95 | 96 | static void 97 | do_logv( int level, const char *fmt, va_list arg_ptr ) 98 | { 99 | if( !logstream ) 100 | logstream = stderr; 101 | 102 | if( missing_lf && level != MY_LOG_CONT ) 103 | putc('\n', logstream ); 104 | missing_lf = 0; 105 | 106 | if( use_time && level != MY_LOG_CONT ) { 107 | /* Note this does not work for multiple line logging as we would 108 | * need to print to a buffer first */ 109 | struct tm *tp; 110 | time_t atime = time(NULL); 111 | 112 | tp = localtime( &atime ); 113 | fprintf( logstream, "%04d-%02d-%02d %02d:%02d:%02d ", 114 | 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, 115 | tp->tm_hour, tp->tm_min, tp->tm_sec ); 116 | } 117 | 118 | switch ( level ) { 119 | case MY_LOG_BEGIN: break; 120 | case MY_LOG_CONT: break; 121 | case MY_LOG_INFO: break; 122 | case MY_LOG_WARN: break; 123 | case MY_LOG_ERROR: break; 124 | case MY_LOG_FATAL: fputs("Fatal: ",logstream ); break; 125 | case MY_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break; 126 | case MY_LOG_DEBUG: fputs("DBG: ", logstream ); break; 127 | default: fprintf(logstream,"[Unknown log level %d]: ", level ); break; 128 | } 129 | 130 | if( fmt ) { 131 | vfprintf(logstream,fmt,arg_ptr) ; 132 | if( *fmt && fmt[strlen(fmt)-1] != '\n' ) 133 | missing_lf = 1; 134 | } 135 | 136 | if( level == MY_LOG_FATAL ) 137 | exit(2); 138 | if( level == MY_LOG_BUG ) 139 | abort(); 140 | } 141 | 142 | static void 143 | do_log( int level, const char *fmt, ... ) 144 | { 145 | va_list arg_ptr ; 146 | 147 | va_start( arg_ptr, fmt ) ; 148 | do_logv( level, fmt, arg_ptr ); 149 | va_end(arg_ptr); 150 | } 151 | 152 | 153 | 154 | void 155 | log_info( const char *fmt, ... ) 156 | { 157 | va_list arg_ptr ; 158 | 159 | va_start( arg_ptr, fmt ) ; 160 | do_logv( MY_LOG_INFO, fmt, arg_ptr ); 161 | va_end(arg_ptr); 162 | } 163 | 164 | void 165 | log_error( const char *fmt, ... ) 166 | { 167 | va_list arg_ptr ; 168 | 169 | va_start( arg_ptr, fmt ) ; 170 | do_logv( MY_LOG_ERROR, fmt, arg_ptr ); 171 | va_end(arg_ptr); 172 | } 173 | 174 | 175 | void 176 | log_fatal( const char *fmt, ... ) 177 | { 178 | va_list arg_ptr ; 179 | 180 | va_start( arg_ptr, fmt ) ; 181 | do_logv( MY_LOG_FATAL, fmt, arg_ptr ); 182 | va_end(arg_ptr); 183 | abort(); /* never called, bugs it makes the compiler happy */ 184 | } 185 | 186 | void 187 | log_bug( const char *fmt, ... ) 188 | { 189 | va_list arg_ptr ; 190 | 191 | va_start( arg_ptr, fmt ) ; 192 | do_logv( MY_LOG_BUG, fmt, arg_ptr ); 193 | va_end(arg_ptr); 194 | abort(); /* never called, but it makes the compiler happy */ 195 | } 196 | 197 | void 198 | log_debug( const char *fmt, ... ) 199 | { 200 | va_list arg_ptr ; 201 | 202 | va_start( arg_ptr, fmt ) ; 203 | do_logv( MY_LOG_DEBUG, fmt, arg_ptr ); 204 | va_end(arg_ptr); 205 | } 206 | 207 | 208 | void 209 | log_printf( const char *fmt, ... ) 210 | { 211 | va_list arg_ptr ; 212 | 213 | if( !fmt ) { 214 | do_logv( MY_LOG_BEGIN, NULL, NULL ); 215 | } 216 | else { 217 | va_start( arg_ptr, fmt ) ; 218 | do_logv( MY_LOG_CONT, fmt, arg_ptr ); 219 | va_end(arg_ptr); 220 | } 221 | } 222 | 223 | 224 | #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) 225 | void 226 | bug_at( const char *file, int line, const char *func ) 227 | { 228 | do_log( MY_LOG_BUG, 229 | ("... this is a bug (%s:%d:%s)\n"), file, line, func ); 230 | abort(); /* never called, but it makes the compiler happy */ 231 | } 232 | #else 233 | void 234 | bug_at( const char *file, int line ) 235 | { 236 | do_log( MY_LOG_BUG, 237 | _("you found a bug ... (%s:%d)\n"), file, line); 238 | abort(); /* never called, but it makes the compiler happy */ 239 | } 240 | #endif 241 | 242 | -------------------------------------------------------------------------------- /tests/basic: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . $srcdir/common || exit 2 4 | 5 | cat >geamd.conf <geamd.log 21 | 22 | cat >encrypt <decrypt <aliases <pubring.gpg 2>/dev/null 45 | $GPG --dearmor <$srcdir/secring.asc >secring.gpg 2>/dev/null 46 | 47 | echo 'starting daemon' 48 | if ! ../src/geamd -C `pwd`/geamd.conf ; then 49 | echo 'failed to start the daemon process' 50 | exit 1 51 | fi 52 | echo -n 'waiting for daemon to get ready ' 53 | i=5 54 | while geamd_pid=`sed -n 's/^.*(pid=\([0-9]*\).*$/\1/p' geamd.log`; \ 55 | test -z "$geamd_pid" ; do 56 | if ! ((i=$i-1)); then 57 | echo ' - failed' 58 | exit 1 59 | fi 60 | echo -n '.' 61 | sleep 1 62 | done 63 | echo 64 | 65 | inner_pid="" 66 | outer_pid="" 67 | 68 | do_exit () { 69 | echo 'stopping daemons' 70 | [ -n "$geamd_pid" ] && kill $geamd_pid 71 | [ -n "$inner_pid" ] && kill $inner_pid 72 | [ -n "$outer_pid" ] && kill $outer_pid 73 | exit $fail 74 | } 75 | 76 | do_fail () { 77 | fail=1 78 | do_exit 79 | } 80 | 81 | trap do_fail HUP INT QUIT PIPE TERM 82 | 83 | 84 | #------------------------------------------ 85 | # Test: 86 | #------------------------------------------ 87 | echo 'checking simple proxing ...' 88 | # starting outer MTA 89 | ../src/simple-mta -lp 9026 >outer-host.out 2>outer-host.log & 90 | outer_pid="$!" 91 | sleep 1 92 | ../src/simple-mta -p 8025 -f foo -t joe@i-cant-internet.com localhost $srcdir/test-plain-1 93 | wait $outer_pid 2>/dev/null 94 | if [ ! -s outer-host.out ]; then 95 | echo 'Error: no message sent' 96 | fail=1 97 | do_exit 98 | fi 99 | outer_pid="" 100 | 101 | # Compare but skip the Received header. We know that they come before Date. 102 | # because a regex as secnd address wil not be tested when the first address 103 | # matches, we have do the strange hack. 104 | echo | cat - $srcdir/test-plain-1 | sed '1,/^Date:/d' >x1 105 | sed '1,/^Date:/d' outer-host.out >x2 106 | if ! diff -q x1 x2 >/dev/null ; then 107 | echo 'ERROR: mismatch:' 108 | diff x1 x2 109 | fail=1 110 | fi 111 | 112 | 113 | #------------------------------------------ 114 | # Test: 115 | #------------------------------------------ 116 | echo 'checking encryption ...' 117 | # starting outer MTA 118 | ../src/simple-mta -lp 9026 >outer-host.out 2>outer-host.log & 119 | outer_pid="$!" 120 | sleep 1 121 | ../src/simple-mta -p 8025 -f foo -t bill@whitehouse.tmp localhost $srcdir/test-plain-1 122 | wait $outer_pid 2>/dev/null 123 | if [ ! -s outer-host.out ]; then 124 | echo 'ERROR: no message sent' 125 | fail=1 126 | do_exit 127 | fi 128 | outer_pid="" 129 | 130 | # fixme: check theat the message looks okay. Instead of doing this, 131 | # we simply decrypt the message. 132 | cat outer-host.out >x 133 | 134 | echo '... and decryption' 135 | ../src/simple-mta -lp 9025 >inner-host.out 2>inner-host.log & 136 | inner_pid="$!" 137 | sleep 1 138 | ../src/simple-mta -p 8025 -f someone -t joe@foo.bar localhost x 139 | wait $inner_pid 2>/dev/null 140 | if [ ! -s inner-host.out ]; then 141 | echo 'ERROR: no message received' 142 | fail=1 143 | do_exit 144 | fi 145 | inner_pid="" 146 | 147 | # now compare the body parts 148 | sed '1,/^$/d' $srcdir/test-plain-1 >x1 149 | sed '1,/^$/d' inner-host.out >x2 150 | if ! diff -q x1 x2 >/dev/null ; then 151 | echo 'ERROR: body mismatch:' 152 | diff x1 x2 153 | fail=1 154 | fi 155 | 156 | #------------------------------------------ 157 | # Test: 158 | #------------------------------------------ 159 | echo 'checking that we do not decrypt for unknown recipients ...' 160 | 161 | ../src/simple-mta -lp 9025 >inner-host.out 2>inner-host.log & 162 | inner_pid="$!" 163 | sleep 1 164 | ../src/simple-mta -p 8025 -f someone -t joe@i-cant-internet.com localhost x 165 | wait $inner_pid 2>/dev/null 166 | if [ ! -s inner-host.out ]; then 167 | echo 'ERROR: no message received' 168 | fail=1 169 | do_exit 170 | fi 171 | inner_pid="" 172 | 173 | if ! grep -qs '^X-Geam-Comment: using <.*> as fallback' inner-host.out; then 174 | echo 'ERROR: fallback recipient has not been used' 175 | fail=1 176 | fi 177 | 178 | sed '1,/^$/d' $srcdir/test-plain-1 >x1 179 | sed '1,/^$/d' inner-host.out >x2 180 | if ! diff -q x1 x2 >/dev/null ; then 181 | echo 'ERROR: body mismatch:' 182 | diff x1 x2 183 | fail=1 184 | fi 185 | 186 | 187 | #------------------------------------------ 188 | # Test: 189 | #------------------------------------------ 190 | echo 'checking encryption with multiple recipients ...' 191 | # starting outer MTA 192 | ../src/simple-mta -lp 9026 >outer-host.out 2>outer-host.log & 193 | outer_pid="$!" 194 | sleep 1 195 | ../src/simple-mta -p 8025 -f foo -t bill@whitehouse.tmp \ 196 | -t joe@i-cant-internet.com localhost $srcdir/test-plain-1 197 | wait $outer_pid 2>/dev/null 198 | if [ ! -s outer-host.out ]; then 199 | echo 'ERROR: no message sent' 200 | fail=1 201 | do_exit 202 | fi 203 | outer_pid="" 204 | 205 | 206 | #------------------------------------------ 207 | # Test: 208 | #------------------------------------------ 209 | echo 'checking decryption against a loaded forwarding host ...' 210 | 211 | ../src/simple-mta --loaded -lp 9025 >inner-host.out 2>inner-host.log & 212 | inner_pid="$!" 213 | sleep 1 214 | ../src/simple-mta -v -p 8025 -f someone -t joe@i-cant-internet.com localhost x 215 | wait $inner_pid 2>/dev/null 216 | if [ -s inner-host.out ]; then 217 | echo 'ERROR: message received' 218 | fail=1 219 | do_exit 220 | fi 221 | inner_pid="" 222 | 223 | # And again this time by closing the connection immediately. 224 | ../src/simple-mta --loaded --loaded -lp 9025 >inner-host.out 2>inner-host.log & 225 | inner_pid="$!" 226 | sleep 1 227 | ../src/simple-mta -p 8025 -f someone -t joe@i-cant-internet.com localhost x 228 | wait $inner_pid 2>/dev/null 229 | if [ -s inner-host.out ]; then 230 | echo 'ERROR: message received' 231 | fail=1 232 | do_exit 233 | fi 234 | inner_pid="" 235 | 236 | 237 | 238 | # Add more tests here. We should write a tool ala formail to 239 | # tweak the headers for compares. 240 | 241 | do_exit 242 | 243 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Basic Installation 2 | ================== 3 | 4 | These are generic installation instructions. 5 | 6 | The `configure' shell script attempts to guess correct values for 7 | various system-dependent variables used during compilation. It uses 8 | those values to create a `Makefile' in each directory of the package. 9 | It may also create one or more `.h' files containing system-dependent 10 | definitions. Finally, it creates a shell script `config.status' that 11 | you can run in the future to recreate the current configuration, a file 12 | `config.cache' that saves the results of its tests to speed up 13 | reconfiguring, and a file `config.log' containing compiler output 14 | (useful mainly for debugging `configure'). 15 | 16 | If you need to do unusual things to compile the package, please try 17 | to figure out how `configure' could check whether to do them, and mail 18 | diffs or instructions to the address given in the `README' so they can 19 | be considered for the next release. If at some point `config.cache' 20 | contains results you don't want to keep, you may remove or edit it. 21 | 22 | The file `configure.in' is used to create `configure' by a program 23 | called `autoconf'. You only need `configure.in' if you want to change 24 | it or regenerate `configure' using a newer version of `autoconf'. 25 | 26 | The simplest way to compile this package is: 27 | 28 | 1. `cd' to the directory containing the package's source code and type 29 | `./configure' to configure the package for your system. If you're 30 | using `csh' on an old version of System V, you might need to type 31 | `sh ./configure' instead to prevent `csh' from trying to execute 32 | `configure' itself. 33 | 34 | Running `configure' takes awhile. While running, it prints some 35 | messages telling which features it is checking for. 36 | 37 | 2. Type `make' to compile the package. 38 | 39 | 3. Optionally, type `make check' to run any self-tests that come with 40 | the package. 41 | 42 | 4. Type `make install' to install the programs and any data files and 43 | documentation. 44 | 45 | 5. You can remove the program binaries and object files from the 46 | source code directory by typing `make clean'. To also remove the 47 | files that `configure' created (so you can compile the package for 48 | a different kind of computer), type `make distclean'. There is 49 | also a `make maintainer-clean' target, but that is intended mainly 50 | for the package's developers. If you use it, you may have to get 51 | all sorts of other programs in order to regenerate files that came 52 | with the distribution. 53 | 54 | Compilers and Options 55 | ===================== 56 | 57 | Some systems require unusual options for compilation or linking that 58 | the `configure' script does not know about. You can give `configure' 59 | initial values for variables by setting them in the environment. Using 60 | a Bourne-compatible shell, you can do that on the command line like 61 | this: 62 | CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure 63 | 64 | Or on systems that have the `env' program, you can do it like this: 65 | env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure 66 | 67 | Compiling For Multiple Architectures 68 | ==================================== 69 | 70 | You can compile the package for more than one kind of computer at the 71 | same time, by placing the object files for each architecture in their 72 | own directory. To do this, you must use a version of `make' that 73 | supports the `VPATH' variable, such as GNU `make'. `cd' to the 74 | directory where you want the object files and executables to go and run 75 | the `configure' script. `configure' automatically checks for the 76 | source code in the directory that `configure' is in and in `..'. 77 | 78 | If you have to use a `make' that does not supports the `VPATH' 79 | variable, you have to compile the package for one architecture at a time 80 | in the source code directory. After you have installed the package for 81 | one architecture, use `make distclean' before reconfiguring for another 82 | architecture. 83 | 84 | Installation Names 85 | ================== 86 | 87 | By default, `make install' will install the package's files in 88 | `/usr/local/bin', `/usr/local/man', etc. You can specify an 89 | installation prefix other than `/usr/local' by giving `configure' the 90 | option `--prefix=PATH'. 91 | 92 | You can specify separate installation prefixes for 93 | architecture-specific files and architecture-independent files. If you 94 | give `configure' the option `--exec-prefix=PATH', the package will use 95 | PATH as the prefix for installing programs and libraries. 96 | Documentation and other data files will still use the regular prefix. 97 | 98 | In addition, if you use an unusual directory layout you can give 99 | options like `--bindir=PATH' to specify different values for particular 100 | kinds of files. Run `configure --help' for a list of the directories 101 | you can set and what kinds of files go in them. 102 | 103 | If the package supports it, you can cause programs to be installed 104 | with an extra prefix or suffix on their names by giving `configure' the 105 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 106 | 107 | Optional Features 108 | ================= 109 | 110 | Some packages pay attention to `--enable-FEATURE' options to 111 | `configure', where FEATURE indicates an optional part of the package. 112 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 113 | is something like `gnu-as' or `x' (for the X Window System). The 114 | `README' should mention any `--enable-' and `--with-' options that the 115 | package recognizes. 116 | 117 | For packages that use the X Window System, `configure' can usually 118 | find the X include and library files automatically, but if it doesn't, 119 | you can use the `configure' options `--x-includes=DIR' and 120 | `--x-libraries=DIR' to specify their locations. 121 | 122 | Specifying the System Type 123 | ========================== 124 | 125 | There may be some features `configure' can not figure out 126 | automatically, but needs to determine by the type of host the package 127 | will run on. Usually `configure' can figure that out, but if it prints 128 | a message saying it can not guess the host type, give it the 129 | `--host=TYPE' option. TYPE can either be a short name for the system 130 | type, such as `sun4', or a canonical name with three fields: 131 | CPU-COMPANY-SYSTEM 132 | 133 | See the file `config.sub' for the possible values of each field. If 134 | `config.sub' isn't included in this package, then this package doesn't 135 | need to know the host type. 136 | 137 | If you are building compiler tools for cross-compiling, you can also 138 | use the `--target=TYPE' option to select the type of system they will 139 | produce code for and the `--build=TYPE' option to select the type of 140 | system on which you are compiling the package. 141 | 142 | Sharing Defaults 143 | ================ 144 | 145 | If you want to set default values for `configure' scripts to share, 146 | you can create a site shell script called `config.site' that gives 147 | default values for variables like `CC', `cache_file', and `prefix'. 148 | `configure' looks for `PREFIX/share/config.site' if it exists, then 149 | `PREFIX/etc/config.site' if it exists. Or, you can set the 150 | `CONFIG_SITE' environment variable to the location of the site script. 151 | A warning: not all `configure' scripts look for a site script. 152 | 153 | Operation Controls 154 | ================== 155 | 156 | `configure' recognizes the following options to control how it 157 | operates. 158 | 159 | `--cache-file=FILE' 160 | Use and save the results of the tests in FILE instead of 161 | `./config.cache'. Set FILE to `/dev/null' to disable caching, for 162 | debugging `configure'. 163 | 164 | `--help' 165 | Print a summary of the options to `configure', and exit. 166 | 167 | `--quiet' 168 | `--silent' 169 | `-q' 170 | Do not print messages saying which checks are being made. To 171 | suppress all normal output, redirect it to `/dev/null' (any error 172 | messages will still be shown). 173 | 174 | `--srcdir=DIR' 175 | Look for the package's source code in directory DIR. Usually 176 | `configure' can determine that directory automatically. 177 | 178 | `--version' 179 | Print the version of Autoconf used to generate the `configure' 180 | script, and exit. 181 | 182 | `configure' also accepts some other, not widely useful, options. 183 | -------------------------------------------------------------------------------- /src/rwbuf.c: -------------------------------------------------------------------------------- 1 | /* rwbuf.c 2 | * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | #include "logging.h" 32 | #include "types.h" 33 | #include "rwbuf.h" 34 | 35 | #define MAX_FDS 1024 /* Note, taht this also limits the number of 36 | concurrent connections we can process. */ 37 | #define READ_BUFFER_SIZE 256 38 | #define WRITE_BUFFER_SIZE 128 39 | 40 | #define LF '\x0a' 41 | #define CR '\x0d' 42 | 43 | 44 | struct buf_desc { 45 | size_t size; /* allocated size */ 46 | size_t wpos; /* next write goes here */ 47 | size_t rpos; /* next read starts here */ 48 | char d[1]; 49 | }; 50 | 51 | struct rwbuf_data { 52 | int eof; 53 | int error; 54 | struct buf_desc *r; 55 | int rto, wto; /* read and write timeout in seconds */ 56 | }; 57 | typedef struct rwbuf_data *RWBUF; 58 | 59 | 60 | static struct rwbuf_data fd_table[MAX_FDS]; 61 | 62 | 63 | static struct buf_desc* 64 | create_buffer( size_t size ) 65 | { 66 | struct buf_desc *buf; 67 | 68 | buf = malloc( size + sizeof(*buf) - 1 ); 69 | if( buf ) { 70 | buf->size = size; 71 | buf->wpos = 0; 72 | buf->rpos = 0; 73 | } 74 | return buf; 75 | } 76 | 77 | 78 | static struct buf_desc* 79 | resize_buffer( struct buf_desc *old, size_t newsize ) 80 | { 81 | struct buf_desc *new; 82 | 83 | new = realloc( old, newsize + sizeof(*old) - 1 ); 84 | if( new ) 85 | new->size = newsize; 86 | return new; 87 | } 88 | 89 | 90 | /**************** 91 | * Initialize a buffer. This function may be used at any 92 | * time to assign a rw buffer to a file descriptor. 93 | */ 94 | int 95 | rw_init( int fd ) 96 | { 97 | RWBUF a; 98 | 99 | if( fd < 0 || fd >= MAX_FDS ) 100 | return -1; 101 | a = fd_table + fd; 102 | 103 | if( !a->r && !(a->r = create_buffer( READ_BUFFER_SIZE )) ) 104 | return -1; /* out of memory */ 105 | a->r->rpos = 0; 106 | a->r->wpos = 0; 107 | a->eof = 0; 108 | a->error = 0; 109 | a->rto = 0; 110 | a->wto = 0; 111 | return 0; 112 | } 113 | 114 | void 115 | rw_timeout( int fd, int read_seconds, int write_seconds ) 116 | { 117 | RWBUF rw; 118 | 119 | if( fd < 0 || fd >= MAX_FDS ) 120 | BUG(); 121 | rw = fd_table + fd; 122 | 123 | if( read_seconds != -1 ) 124 | rw->rto = read_seconds; 125 | if( write_seconds != -1 ) 126 | rw->wto = write_seconds; 127 | } 128 | 129 | /**************** 130 | * Read a line from fd and return a pointer to a buffer 131 | * which is allocated for the fd and valid until the next call 132 | * to a read function on this fd. 133 | * Reading stops on a LF which will be replaced by binary 0 134 | * nbytes will have the length of the line w/o this 0. 135 | * If the line has to be truncated a 0 will we set anyway. 136 | * 137 | * 138 | * Returns: A pointer to this buffer which valid length is 139 | * returned in nbytes. 140 | * EOF or error is indicated by returning NULL. 141 | * if truncated is not NULL, it wiill be set to 1 if 142 | * the line has been truncated or together with a return value. 143 | * of NULL it indicates a timeout 144 | * Note: This function uses the internal read buffer and probably 145 | * will extend it to maxlen if required. 146 | */ 147 | char * 148 | rw_readline( int fd, size_t maxlen, size_t *nbytes, int *truncated ) 149 | { 150 | RWBUF rw; 151 | struct buf_desc *buf; 152 | int nread, n; 153 | char *p; 154 | pth_event_t evt; 155 | 156 | if( truncated ) 157 | *truncated = 0; 158 | if( !maxlen ) /* we need a maxlen of at least 1 */ 159 | maxlen = READ_BUFFER_SIZE; 160 | 161 | if( fd < 0 || fd >= MAX_FDS ) 162 | BUG(); 163 | 164 | rw = fd_table + fd; 165 | /* make sure that the buffer has been initialized */ 166 | if( !(buf = rw->r) ) { 167 | buf = rw->r = create_buffer( maxlen < READ_BUFFER_SIZE ? 168 | READ_BUFFER_SIZE : maxlen ); 169 | if( !buf ) { 170 | return NULL; /* out of core */ 171 | } 172 | } 173 | 174 | if( rw->eof || rw->error ) { 175 | return NULL; 176 | } 177 | 178 | assert( buf->rpos <= buf->wpos ); 179 | 180 | if( buf->rpos ) { /* shift the buffer to the beginning */ 181 | /* Hmmm: We have to see whether it makes sense to 182 | * defer this until our buffer gets to short */ 183 | memmove( buf->d, buf->d + buf->rpos, buf->wpos - buf->rpos ); 184 | buf->wpos -= buf->rpos; 185 | buf->rpos = 0; 186 | } 187 | 188 | for(;;) { 189 | n = buf->wpos < maxlen? buf->wpos : maxlen; 190 | p = memchr( buf->d, LF, n ); 191 | if( p ) { 192 | *p = 0; 193 | n = p - buf->d; 194 | buf->rpos = n+1; 195 | if( nbytes ) 196 | *nbytes = n; 197 | return buf->d; /* The complete line has already been read in */ 198 | } 199 | if( buf->wpos >= maxlen ) { 200 | if( truncated ) 201 | *truncated = 1; 202 | buf->rpos = maxlen; 203 | buf->d[maxlen-1] = 0; /* make sure it is a C string */ 204 | if( nbytes ) 205 | *nbytes = maxlen; /* fixme: save this character for later restore */ 206 | return buf->d; 207 | } 208 | 209 | /* fill up the buffer */ 210 | n = buf->size - buf->wpos; 211 | if( n < 10 && buf->size < maxlen ) { 212 | /* our buffer seems to be too short. try to reallocate */ 213 | struct buf_desc *newbuf = resize_buffer( buf, maxlen ); 214 | if( newbuf ) { 215 | rw->r = buf = newbuf; 216 | n = buf->size - buf->wpos; 217 | } 218 | } 219 | if( n < 1 ) { 220 | /* no way to stuff more into our buffer */ 221 | if( truncated ) 222 | *truncated = 1; 223 | buf->rpos = buf->wpos; 224 | buf->d[buf->rpos-1] = 0; /* make sure it is a C string */ 225 | if( nbytes ) 226 | *nbytes = buf->rpos; /* fixme: save this character for later restore */ 227 | return buf->d; 228 | } 229 | 230 | evt = rw->rto ? pth_event( PTH_EVENT_TIME, pth_timeout( rw->rto, 0) ) 231 | : NULL; 232 | nread = pth_read_ev( fd, buf->d + buf->wpos, n, evt ); 233 | if( nread < 0 ) { 234 | if( evt && pth_event_occurred( evt ) ) { 235 | pth_event_free(evt, PTH_FREE_THIS); 236 | if( truncated ) 237 | *truncated = 1; /* indicate timeout */ 238 | } 239 | rw->error = 1; 240 | return NULL; 241 | } 242 | if( evt ) 243 | pth_event_free(evt, PTH_FREE_THIS); 244 | if( !nread ) { 245 | rw->eof = 1; 246 | if( !buf->wpos ) { 247 | return NULL; 248 | } 249 | if( truncated ) 250 | *truncated = 1; 251 | buf->rpos = buf->wpos; 252 | buf->d[buf->rpos-1] = 0; /* make sure it is a C string */ 253 | if( nbytes ) 254 | *nbytes = buf->rpos; /* fixme: save this character for later restore */ 255 | return buf->d; 256 | } 257 | buf->wpos += nread; 258 | /* Actually we should increase rpos and take this in account 259 | * while looking for the LF atthe top of the loop. 260 | * However, the current approach does work and can be 261 | * enhanced later. 262 | */ 263 | } 264 | 265 | } 266 | 267 | 268 | int 269 | rw_writen( int fd, const char *buffer, size_t length ) 270 | { 271 | while( length ) { 272 | int nwritten = pth_write( fd, buffer, length ); 273 | /* pth handles EINTR for us */ 274 | if( nwritten < 0 ) 275 | return -1; /* write error */ 276 | length -= nwritten; 277 | buffer += nwritten; 278 | } 279 | return 0; /* okay */ 280 | } 281 | 282 | int 283 | rw_writestr( int fd, const char *string ) 284 | { 285 | return rw_writen( fd, string, strlen(string) ); 286 | } 287 | 288 | int 289 | rw_printf( int fd, const char * format, ... ) 290 | { 291 | char buf[990]; /* should be below 1000 to help for SMTP */ 292 | size_t n, len; 293 | va_list arg_ptr; 294 | 295 | va_start( arg_ptr, format ); 296 | vsnprintf( buf, DIM(buf), format, arg_ptr ); 297 | va_end( arg_ptr ); 298 | 299 | len = strlen(buf); /* return value of vsnprint is not reliable */ 300 | 301 | /* make sure that we have at least the 302 | * line ending in the output */ 303 | n = strlen(format); 304 | if( n > 1 && len > 1 && format[n-2] == '\r' && format[n-1] == '\n' ) { 305 | if( buf[len-2] != '\r' || buf[len-1] != '\n' ) { 306 | buf[len-2] = '\r'; 307 | buf[len-1] = '\n'; 308 | } 309 | } 310 | else if( n && len && format[n-1] == '\n' ) { 311 | if( buf[len-1] != '\n' ) { 312 | buf[len-1] = '\n'; 313 | } 314 | } 315 | return rw_writen( fd, buf, len ); 316 | } 317 | 318 | -------------------------------------------------------------------------------- /doc/geamd-options.sgml: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | OPTIONS 23 | 24 | Long options can be put in the configuration file 25 | (default: /etc/geam/geamd.conf). Do not 26 | write the two dashes, but simply the name of the option and 27 | any required arguments. Lines with a hash as the first 28 | non-white-space character are ignored. Commands may be put in 29 | this file too, but that does not make sense. 30 | 31 | &geamd; recognizes these options: 32 | 33 | 34 | 35 | 36 | &ParmName; 37 | 38 | Use the host named &ParmName; as a smarthost to forward 39 | all messages which either get decrypted or were not generated locally. 40 | Default is localhost. 41 | 42 | 43 | 44 | 45 | &ParmName; 46 | 47 | Use the host named &ParmName; as a smarthost to forward 48 | all messages which are intended for the outside. 49 | Default is localhost. 50 | 51 | 52 | 53 | 54 | &ParmN; 55 | 56 | Connect to the inner host on port &ParmN;. Default is 25. 57 | 58 | 59 | 60 | 61 | &ParmN; 62 | 63 | Connect to the outer host on port &ParmN;. Default is 25. 64 | 65 | 66 | 67 | 68 | , 69 | 70 | Increase logging verbosity. This may be changed at runtime by 71 | using one of the signals. 72 | 73 | 74 | 75 | 76 | , 77 | 78 | Be more quiet. 79 | 80 | 81 | 82 | 83 | &ParmFlags; 84 | 85 | Set debugging flags. All flags are or-ed and &ParmFlags; may 86 | be given in C syntax (e.g. 0x0042). 87 | 88 | 89 | 90 | Enable general debugging info. 91 | 92 | 93 | 94 | Show status info of the encryption program. 95 | 96 | 97 | 98 | Show the SMTP commands. 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | Do not run as a daemon. 108 | 109 | 110 | 111 | 112 | &ParmFile;, &ParmFile; 113 | 114 | Read options from &ParmFile; and do not try to read 115 | them from the default config file which is 116 | This option is ignored if used inside the config file. 117 | 118 | 119 | 120 | 121 | &ParmFile; 122 | 123 | Use &ParmFile; as the alias file. If it is not an 124 | absolute filename, it is relative to the configuration directory. 125 | Default is aliases. 126 | 127 | 128 | 129 | 130 | &ParmFile; 131 | 132 | Use &ParmFile; as the encrypt file. If it is not an 133 | absolute filename, it is relative to the configuration directory. 134 | Default is encrypt. 135 | 136 | 137 | 138 | 139 | &ParmFile; 140 | 141 | Use &ParmFile; as the decrypt file. If it is not an 142 | absolute filename, it is relative to the configuration directory. 143 | Default is decrypt. 144 | 145 | 146 | 147 | 148 | &ParmFile; 149 | 150 | Use &ParmFile; as the log file. If you use a single dash, 151 | log output is written to stderr 152 | without timestamps. 153 | Default is /var/log/geam/geamd. 154 | 155 | 156 | 157 | 158 | &ParmFile; 159 | 160 | Use &ParmFile; as the gpg binary. 161 | The default is installation dependent. 162 | 163 | 164 | 165 | 166 | &ParmDir; 167 | 168 | Use &ParmDir; for the gpg 169 | option. If it is not an 170 | absolute path, it is relative to the configuration 171 | directory. Default is gpg. 172 | 173 | 174 | 175 | 176 | 177 | &ParmN; 178 | 179 | Listen on port &ParmN; instead of the default port 8025. 180 | 181 | 182 | 183 | 184 | &ParmName; 185 | 186 | After setting up some basic things, change the user ID 187 | of the process to &ParmName;. This will only be done when the 188 | process has been started under the effective user ID 0. 189 | If this option is not given, it is used implictly with 190 | &ParmName; set to mail. 191 | 192 | 193 | 194 | 195 | &ParmName; 196 | 197 | After setting up some basic things, change the group ID 198 | of the process to &ParmName;. This will only be done when the 199 | process has been started under the effective user ID 0. 200 | If this option is not given, it is used implictly with 201 | &ParmName; set to mail. 202 | 203 | 204 | 205 | 206 | &ParmN; 207 | 208 | Set the the number of Received: mail headers 209 | which are used to decide whether the mail is looping. 210 | Default is 30. 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | FILES 220 | 221 | 222 | 223 | /etc/geam/geamd.conf 224 | 225 | The default configuration file. 226 | 227 | 228 | 229 | 230 | /etc/geam/ 231 | 232 | The default configuration directory which is deducted from the 233 | configuration file and used as the base for all relative paths. 234 | 235 | 236 | 237 | 238 | /etc/geam/gpg/ 239 | 240 | The default GnuPG home directory. 241 | 242 | 243 | 244 | 245 | /var/log/geam/geamd 246 | 247 | The default log file. 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | SIGNALS 256 | 257 | 258 | 259 | SIGHUP 260 | 261 | Reread the configuration tables. Note that this does not 262 | include the configuration file which is only read on startup. 263 | 264 | 265 | 266 | 267 | SIGUSR1 268 | 269 | Increase the logging verbosity. Increasing this to level 3 270 | will also enable SMTP debugging. 271 | 272 | 273 | 274 | 275 | SIGUSR2 276 | 277 | Decrease the logging verbosity. Decreasing it from level 3 278 | will also disable SMTP debugging. 279 | 280 | 281 | 282 | 283 | SIGTERM 284 | 285 | The correct way to terminate this daemon. 286 | 287 | 288 | 289 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl autoconf macros for this project 3 | dnl 4 | 5 | 6 | dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME) 7 | dnl Check whether a typedef exists and create a #define $2 if it exists 8 | dnl 9 | AC_DEFUN(GNUPG_CHECK_TYPEDEF, 10 | [ AC_MSG_CHECKING(for $1 typedef) 11 | AC_CACHE_VAL(gnupg_cv_typedef_$1, 12 | [AC_TRY_COMPILE([#include 13 | #include ], [ 14 | #undef $1 15 | int a = sizeof($1); 16 | ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )]) 17 | AC_MSG_RESULT($gnupg_cv_typedef_$1) 18 | if test "$gnupg_cv_typedef_$1" = yes; then 19 | AC_DEFINE($2) 20 | fi 21 | ]) 22 | 23 | 24 | # Configure paths for PTH 25 | # Shamelessly stolen from the one of XDELTA by Owen Taylor 26 | # Werner Koch 99-12-08 27 | 28 | dnl AM_PATH_PTH([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) 29 | dnl Test for Pth, and define PTH_CFLAGS and PTH_LIBS 30 | dnl 31 | AC_DEFUN(AM_PATH_PTH, 32 | [dnl 33 | dnl Get the cflags and libraries from the pth-config script 34 | dnl 35 | AC_ARG_WITH(pth-prefix, 36 | [ --with-pth-prefix=PFX Prefix where Pth is installed (optional)], 37 | pth_config_prefix="$withval", pth_config_prefix="") 38 | AC_ARG_ENABLE(pthtest, 39 | [ --disable-pthtest Do not try to compile and run a test Pth program], 40 | , enable_pthtest=yes) 41 | 42 | if test x$pth_config_prefix != x ; then 43 | pth_config_args="$pth_config_args --prefix=$pth_config_prefix" 44 | if test x${PTH_CONFIG+set} != xset ; then 45 | PTH_CONFIG=$pth_config_prefix/bin/pth-config 46 | fi 47 | fi 48 | 49 | AC_PATH_PROG(PTH_CONFIG, pth-config, no) 50 | min_pth_version=ifelse([$1], ,1.2.1,$1) 51 | AC_MSG_CHECKING(for Pth - version >= $min_pth_version) 52 | no_pth="" 53 | if test "$PTH_CONFIG" = "no" ; then 54 | no_pth=yes 55 | else 56 | PTH_CFLAGS=`$PTH_CONFIG $pth_config_args --cflags` 57 | PTH_LIBS=`$PTH_CONFIG $pth_config_args --ldflags --libs` 58 | pth_config_major_version=`$PTH_CONFIG $pth_config_args --version | \ 59 | sed 's/.* \([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` 60 | pth_config_minor_version=`$PTH_CONFIG $pth_config_args --version | \ 61 | sed 's/.* \([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` 62 | pth_config_micro_version=`$PTH_CONFIG $pth_config_args --version | \ 63 | sed 's/.* \([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` 64 | if test "x$enable_pthtest" = "xyes" ; then 65 | ac_save_CFLAGS="$CFLAGS" 66 | ac_save_LIBS="$LIBS" 67 | CFLAGS="$CFLAGS $PTH_CFLAGS" 68 | LIBS="$LIBS $PTH_LIBS" 69 | dnl 70 | dnl Now check if the installed Pth is sufficiently new. Also sanity 71 | dnl checks the results of pth-config to some extent 72 | dnl 73 | rm -f conf.pthtest 74 | AC_TRY_RUN([ 75 | #include 76 | #include 77 | #include 78 | #include 79 | 80 | int 81 | main () 82 | { 83 | int major, minor, micro; 84 | unsigned int major_pth, minor_pth, micro_pth, patlvl_pth; 85 | char *tmp_version; 86 | char ver_string[20]; 87 | 88 | system ("touch conf.pthtest"); 89 | 90 | /* HP/UX 9 (%@#!) writes to sscanf strings */ 91 | tmp_version = strdup("$min_pth_version"); 92 | if( !tmp_version ) 93 | exit(1); 94 | if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { 95 | printf("%s, bad version string\n", "$min_pth_version"); 96 | exit(1); 97 | } 98 | 99 | sprintf( ver_string, "%lX", pth_version() ); 100 | if ( sscanf(ver_string, "%1x%2x%1x%2x", 101 | &major_pth, &minor_pth, &patlvl_pth, µ_pth) != 4) { 102 | printf("%s, pth returned bad version string\n", ver_string ); 103 | exit(1); 104 | } 105 | 106 | if ((major_pth != $pth_config_major_version) || 107 | (minor_pth != $pth_config_minor_version) || 108 | (micro_pth != $pth_config_micro_version)) 109 | { 110 | printf("\n*** 'pth-config --version' returned %d.%d.%d, but Pth (%u.%u.%u)\n", 111 | $pth_config_major_version, $pth_config_minor_version, $pth_config_micro_version, 112 | major_pth, minor_pth, micro_pth); 113 | printf("*** was found! If pth-config was correct, then it is best\n"); 114 | printf("*** to remove the old version of Pth. You may also be able to fix the error\n"); 115 | printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); 116 | printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); 117 | printf("*** required on your system.\n"); 118 | printf("*** If pth-config was wrong, set the environment variable PTH_CONFIG\n"); 119 | printf("*** to point to the correct copy of pth-config, and remove the file config.cache\n"); 120 | printf("*** before re-running configure\n"); 121 | } 122 | else if ( pth_version() != PTH_VERSION ) 123 | { 124 | printf("*** Pth header file (version %lx) does not match\n", PTH_VERSION); 125 | printf("*** library (version %lx)\n", pth_version() ); 126 | } 127 | else 128 | { 129 | if ((major_pth > major) || 130 | ((major_pth == major) && (minor_pth > minor)) || 131 | ((major_pth == major) && (minor_pth == minor) && (micro_pth >= micro))) 132 | { 133 | return 0; 134 | } 135 | else 136 | { 137 | printf("\n*** An old version of Pth (%u.%u.%u) was found.\n", 138 | major_pth, minor_pth, micro_pth); 139 | printf("*** You need a version of Pth newer than %d.%d.%d. The latest version of\n", 140 | major, minor, micro); 141 | printf("*** Pth is always available from ftp://ftp.gnu.org/gnu/pub/.\n"); 142 | printf("***\n"); 143 | printf("*** If you have already installed a sufficiently new version, this error\n"); 144 | printf("*** probably means that the wrong copy of the pth-config shell script is\n"); 145 | printf("*** being found. The easiest way to fix this is to remove the old version\n"); 146 | printf("*** of Pth, but you can also set the PTH_CONFIG environment to point to the\n"); 147 | printf("*** correct copy of pth-config. (In this case, you will have to\n"); 148 | printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); 149 | printf("*** so that the correct libraries are found at run-time))\n"); 150 | } 151 | } 152 | return 1; 153 | } 154 | ],, no_pth=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) 155 | CFLAGS="$ac_save_CFLAGS" 156 | LIBS="$ac_save_LIBS" 157 | fi 158 | fi 159 | if test "x$no_pth" = x ; then 160 | AC_MSG_RESULT(yes) 161 | ifelse([$2], , :, [$2]) 162 | else 163 | AC_MSG_RESULT(no) 164 | if test "$PTH_CONFIG" = "no" ; then 165 | echo "*** The pth-config script installed by Pth could not be found" 166 | echo "*** If Pth was installed in PREFIX, make sure PREFIX/bin is in" 167 | echo "*** your path, or set the PTH_CONFIG environment variable to the" 168 | echo "*** full path to pth-config." 169 | else 170 | if test -f conf.pthtest ; then 171 | : 172 | else 173 | echo "*** Could not run Pth test program, checking why..." 174 | CFLAGS="$CFLAGS $PTH_CFLAGS" 175 | LIBS="$LIBS $PTH_LIBS" 176 | AC_TRY_LINK([ 177 | #include 178 | #include 179 | ], [ return !!pth_version(); ], 180 | [ echo "*** The test program compiled, but did not run. This usually means" 181 | echo "*** that the run-time linker is not finding Pth or finding the wrong" 182 | echo "*** version of Pth. If it is not finding Pth, you'll need to set your" 183 | echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" 184 | echo "*** to the installed location Also, make sure you have run ldconfig if that" 185 | echo "*** is required on your system" 186 | echo "***" 187 | echo "*** If you have an old version installed, it is best to remove it, although" 188 | echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" 189 | echo "***" ], 190 | [ echo "*** The test program failed to compile or link. See the file config.log for the" 191 | echo "*** exact error that occured. This usually means Pth was incorrectly installed" 192 | echo "*** or that you have moved Pth since it was installed. In the latter case, you" 193 | echo "*** may want to edit the pth-config script: $PTH_CONFIG" ]) 194 | CFLAGS="$ac_save_CFLAGS" 195 | LIBS="$ac_save_LIBS" 196 | fi 197 | fi 198 | PTH_CFLAGS="" 199 | PTH_LIBS="" 200 | ifelse([$3], , :, [$3]) 201 | fi 202 | AC_SUBST(PTH_CFLAGS) 203 | AC_SUBST(PTH_LIBS) 204 | rm -f conf.pthtest 205 | ]) 206 | 207 | 208 | 209 | dnl GPH_PROG_DOCBOOK() 210 | dnl Check whether we have the needed Docbook environment 211 | dnl and issue a warning if this is not the case. 212 | dnl 213 | dnl This test defines these variables for substitution: 214 | dnl DB2HTML - command used to convert Docbook to HTML 215 | dnl DB2TEX - command used to convert Docbook to TeX 216 | dnl DB2MAN - command used to convert Docbook to man pages 217 | dnl JADE - command to invoke jade 218 | dnl JADETEX - command to invoke jadetex 219 | dnl DSL_FOR_HTML - the stylesheet used to for the Docbook->HTML conversion 220 | dnl DSL_FOR_TEX - the stylesheet used to for the Docbook->TeX conversion 221 | dnl The following make conditionals are defined 222 | dnl HAVE_DB2MAN - defined when db2man is available 223 | dnl HAVE_DB2TEX - defined when db2tex is available 224 | dnl HAVE_DB2HTML - defined when db2html is available 225 | dnl HAVE_DOCBOOK - defined when the entire Docbook environment is present 226 | dnl HAVE_JADE - defined when jade is installed 227 | dnl HAVE_JADETEX - defined when jadetex is installed 228 | dnl 229 | dnl (wk 2000-04-12) 230 | dnl 231 | AC_DEFUN(GPH_PROG_DOCBOOK, 232 | [ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl 233 | all=yes 234 | AC_PATH_PROG(DB2MAN, docbook-to-man, no) 235 | test "$DB2MAN" = no && all=no 236 | AM_CONDITIONAL(HAVE_DB2MAN, test "$DB2MAN" != no ) 237 | 238 | AC_PATH_PROG(JADE, jade, no) 239 | test "$JADE" = no && all=no 240 | AM_CONDITIONAL(HAVE_JADE, test "$JADE" != no ) 241 | 242 | AC_PATH_PROG(JADETEX, jadetex, no) 243 | test "$JADETEX" = no && all=no 244 | AM_CONDITIONAL(HAVE_JADETEX, test "$JADETEX" != no ) 245 | 246 | stylesheet_dirs=' 247 | /usr/local/lib/dsssl/stylesheets/docbook 248 | /usr/local/share/dsssl/stylesheets/docbook 249 | /usr/local/lib/sgml/stylesheet/dsssl/docbook/nwalsh 250 | /usr/local/share/sgml/stylesheet/dsssl/docbook/nwalsh 251 | /usr/lib/dsssl/stylesheets/docbook 252 | /usr/share/dsssl/stylesheets/docbook 253 | /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh 254 | /usr/share/sgml/stylesheet/dsssl/docbook/nwalsh 255 | /usr/lib/sgml/stylesheets/nwalsh-modular 256 | /usr/share/sgml/stylesheets/nwalsh-modular 257 | ' 258 | 259 | AC_MSG_CHECKING(for TeX stylesheet) 260 | DSL_FOR_TEX=none 261 | for d in ${stylesheet_dirs}; do 262 | file=${d}/print/docbook.dsl 263 | if test -f $file; then 264 | DSL_FOR_TEX=$file 265 | break 266 | fi 267 | done 268 | AC_MSG_RESULT([$DSL_FOR_TEX]) 269 | okay=no 270 | if test $DSL_FOR_TEX = none ; then 271 | DB2TEX="$missing_dir/missing db2tex" 272 | all=no 273 | else 274 | DB2TEX="$JADE -t tex" 275 | okay=yes 276 | fi 277 | AC_SUBST(DB2TEX) 278 | AC_SUBST(DSL_FOR_TEX) 279 | AM_CONDITIONAL(HAVE_DB2TEX, test $okay = yes ) 280 | 281 | if ( $ac_aux_dir/db2html.in --version) < /dev/null > /dev/null 2>&1; then 282 | : 283 | else 284 | AC_ERROR([needed $ac_aux_dir/db2html.in not found]) 285 | fi 286 | 287 | AC_MSG_CHECKING(for HTML stylesheet) 288 | DSL_FOR_HTML="none" 289 | for d in ${stylesheet_dirs}; do 290 | file=${d}/html/docbook.dsl 291 | if test -f $file; then 292 | DSL_FOR_HTML=$file 293 | break 294 | fi 295 | done 296 | AC_MSG_RESULT([$DSL_FOR_HTML]) 297 | okay=no 298 | if test $DSL_FOR_HTML = none ; then 299 | DB2HTML="$missing_dir/missing db2html" 300 | all=no 301 | else 302 | DB2HTML="`cd $ac_aux_dir && pwd`/db2html --copyfiles" 303 | okay=yes 304 | fi 305 | AC_SUBST(DB2HTML) 306 | AC_SUBST(DSL_FOR_HTML) 307 | AM_CONDITIONAL(HAVE_DB2HTML, test $okay = yes ) 308 | 309 | AM_CONDITIONAL(HAVE_DOCBOOK, test "$all" != yes ) 310 | if test $all = no ; then 311 | AC_MSG_WARN([[ 312 | *** 313 | *** It seems that the Docbook environment is not installed as required. 314 | *** We will try to build everything, but if you either touch some files 315 | *** or use a bogus make tool, you may run into problems. 316 | *** Docbook is normally only needed to build the documentation. 317 | ***]]) 318 | fi 319 | ]) 320 | 321 | 322 | dnl *-*wedit:notab*-* Please keep this as the last line. 323 | -------------------------------------------------------------------------------- /src/simple-mta.c: -------------------------------------------------------------------------------- 1 | /* simple-mta.c - A simple SMTP implemenation 2 | * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #ifndef __GLIBC__ 38 | #error This program will only work with the GNU libc 39 | /* GNU features used: printf("%m") */ 40 | #endif 41 | 42 | #include "xmalloc.h" 43 | #include "argparse.h" 44 | #include "logging.h" 45 | #include "rfc821.h" 46 | #include "rfc822.h" 47 | #include "rwbuf.h" 48 | 49 | 50 | #define DEFAULT_PORT 25 51 | 52 | 53 | enum opt_values { aNull = 0, 54 | oListen = 'l', 55 | oServer = 's', 56 | oPort = 'p', 57 | oFrom = 'f', 58 | oTo = 't', 59 | oVerbose = 'v', 60 | oQuiet = 'q', 61 | oDebug = 500, 62 | oLoaded, 63 | 64 | }; 65 | 66 | static ARGPARSE_OPTS opts[] = { 67 | { 301, NULL, 0, "@\nOptions:\n " }, 68 | { oListen, "listen", 0, "wait for a connection" }, 69 | { oServer, "server", 0, "run as a server" }, 70 | { oPort, "port", 1, "|N|use port N (default is 25)"}, 71 | { oFrom, "from", 2, "|A|set MAIL FROM:"}, 72 | { oTo , "to", 2, "|A|set RCPT TO:"}, 73 | { oVerbose, "verbose", 0, "verbose" }, 74 | { oQuiet, "quiet", 0, "be more quiet"}, 75 | { oDebug, "debug", 4|16, "set debugging flags"}, 76 | { oLoaded, "loaded", 0, "always temporary error"}, 77 | {0} }; 78 | 79 | 80 | struct stringlist { 81 | struct stringlist *next; 82 | char d[1]; 83 | }; 84 | 85 | typedef struct server_data { 86 | int fd; 87 | const char *filename; 88 | FILE *stream; 89 | } *SERVER; 90 | 91 | 92 | static int verbose = 0; 93 | static int debug = 0; 94 | static int loaded = 0; 95 | 96 | static int start_listening( int port ); 97 | static int server_cb_rfc821( void *opaque, enum rfc821_events event, RFC821 smtp ); 98 | static int server_cb_rfc822( void *opaque, enum rfc822_events event, RFC822 msg ); 99 | 100 | 101 | /**************** 102 | * Wrappers needed for rwbuf.c so that the PTH library is not needed. 103 | */ 104 | ssize_t 105 | pth_read_ev(int fd, void *p, size_t n, void *evt ) 106 | { 107 | return read( fd, p, n ); 108 | } 109 | 110 | ssize_t 111 | pth_write(int fd, const void *p, size_t n) 112 | { 113 | return write( fd, p, n ); 114 | } 115 | 116 | void * 117 | pth_timeout( int a, int b) 118 | { 119 | return NULL; 120 | } 121 | 122 | void * 123 | pth_event(unsigned long t, ...) 124 | { 125 | return NULL; 126 | } 127 | 128 | int 129 | pth_event_free( void *a, int how) 130 | { 131 | return 0; 132 | } 133 | 134 | int 135 | pth_event_occurred( void *e ) 136 | { 137 | return 0; 138 | } 139 | 140 | 141 | static const char * 142 | my_strusage( int level ) 143 | { 144 | const char *p; 145 | switch( level ) { 146 | case 11: p = "simple-mta"; 147 | break; 148 | case 13: p = VERSION; break; 149 | case 14: p = "Copyright (C) 2000 Werner Koch Softwaresysteme"; break; 150 | case 19: p = "Please report bugs to .\n"; 151 | break; 152 | case 1: 153 | case 40: p = 154 | "Usage: simple-mta [options] (-h for help)" ; 155 | break; 156 | case 41: p = 157 | "Syntax: simple-mta [options] [host] [file]\n" 158 | " simple-mta [options] -l [file]\n" 159 | "Do a SMTP transaction\n"; 160 | break; 161 | 162 | default: p = NULL; 163 | } 164 | return p; 165 | } 166 | 167 | 168 | 169 | int 170 | main( int argc, char **argv ) 171 | { 172 | ARGPARSE_ARGS pargs; 173 | int server = 0; 174 | int port = DEFAULT_PORT; 175 | int looping = 0; 176 | const char *filename = NULL; 177 | const char *hostname = NULL; 178 | const char *mail_from = ""; 179 | struct stringlist *rcpt_to = NULL; 180 | struct stringlist *sl; 181 | 182 | set_strusage( my_strusage ); 183 | 184 | pargs.argc = &argc; 185 | pargs.argv = &argv; 186 | pargs.flags = 0; 187 | while( arg_parse( &pargs, opts) ) { 188 | switch( pargs.r_opt ) { 189 | case oListen: server = 1; break; 190 | case oPort: port = pargs.r.ret_int; break; 191 | case oServer: looping = 1; break; 192 | case oFrom: mail_from = pargs.r.ret_str; break; 193 | case oTo: 194 | sl = xmalloc( sizeof(*sl) + strlen(pargs.r.ret_str) ); 195 | strcpy( sl->d, pargs.r.ret_str ); 196 | sl->next = rcpt_to; 197 | rcpt_to = sl; 198 | break; 199 | case oVerbose: verbose++; break; 200 | case oQuiet: break; 201 | case oDebug: debug |= pargs.r.ret_ulong; break; 202 | case oLoaded: loaded++; break; 203 | default: pargs.err = 2; break; 204 | } 205 | } 206 | 207 | if( (debug & 4) ) 208 | rfc821_set_flag( NULL, RFC821FLG_DBGSMTP, 1 ); 209 | 210 | if( server ) { 211 | if( argc == 1 ) 212 | filename = *argv; 213 | else if( argc ) 214 | usage(1); 215 | } 216 | else { 217 | if( !argc ) 218 | hostname = "localhost"; 219 | else if( argc == 1 ) 220 | hostname = *argv; 221 | else if( argc == 2 ) { 222 | hostname = *argv; 223 | filename = argv[1]; 224 | } 225 | else 226 | usage(1); 227 | } 228 | 229 | signal(SIGPIPE, SIG_IGN); /* better ignore this */ 230 | 231 | if( server ) { 232 | int listen_fd; 233 | struct sockaddr_in paddr; 234 | socklen_t plen = sizeof( paddr ); 235 | RFC821 smtp; 236 | struct server_data state; 237 | 238 | listen_fd = start_listening( port ); 239 | if( listen_fd == -1 ) 240 | return 1; 241 | 242 | do { 243 | memset( &state, 0, sizeof state ); 244 | state.filename = filename; 245 | if( verbose ) 246 | log_info( "waiting on port %d\n", port ); 247 | 248 | state.fd = accept( listen_fd, (struct sockaddr *)&paddr, &plen); 249 | if( state.fd == -1 ) { 250 | log_error( "accept failed: %m\n" ); 251 | continue; 252 | } 253 | if( verbose ) 254 | log_info( "connect from %s:%d\n", 255 | inet_ntoa(paddr.sin_addr), (int)ntohs(paddr.sin_port) ); 256 | if( rw_init( state.fd ) ) { 257 | log_error("fd %d: rw_init failed\n", state.fd ); 258 | continue; 259 | } 260 | 261 | if (loaded > 1) 262 | { 263 | log_info("fd %d: closing connection due to --loaded\n", 264 | state.fd ); 265 | rw_writestr (state.fd, "421 Try again later\r\n"); 266 | close (state.fd); 267 | state.fd = -1; 268 | continue; 269 | } 270 | 271 | smtp = rfc821_open( server_cb_rfc821, &state ); 272 | if( !smtp ) { 273 | log_error("rfc821_open failed\n" ); 274 | } 275 | else { 276 | rfc821_set_proto_comment( smtp, "simple-mta server" ); 277 | rfc821_set_rfc822_cb( smtp, server_cb_rfc822, &state ); 278 | if( rfc821_handler( smtp, state.fd, inet_ntoa(paddr.sin_addr), 279 | (int)ntohs(paddr.sin_port)) ) 280 | log_error("smtp processing failed\n" ); 281 | rfc821_close( smtp ); 282 | } 283 | 284 | close( state.fd ); 285 | } while( looping ); 286 | close( listen_fd ); 287 | } 288 | else { /* client */ 289 | int fd, sock; 290 | struct protoent *pe; 291 | struct hostent *host; 292 | struct sockaddr_in addr; 293 | int rc; 294 | RFC821 smtp; 295 | RFC822 msg; 296 | 297 | if( port < 1 || port > 65534 ) { 298 | log_error("port %d is invalid\n", port ); 299 | exit(1); 300 | } 301 | 302 | if( filename ) { 303 | fd = open( filename, O_RDONLY ); 304 | if( fd == -1 ) { 305 | log_error("failed to open `%s': %m\n", filename ); 306 | exit(1); 307 | } 308 | } 309 | else 310 | fd = 0; 311 | 312 | if( rw_init( fd ) ) { 313 | log_error("rw_init failed\n"); 314 | exit(1); 315 | } 316 | 317 | 318 | if( !(pe = getprotobyname("tcp")) ) { 319 | log_error("getprotobyname failed: %m\n" ); 320 | exit(1); 321 | } 322 | 323 | addr.sin_family = AF_INET; 324 | addr.sin_port = htons(port); 325 | host = gethostbyname((char*)hostname); 326 | if( !host ) { 327 | log_error("host `%s' not found\n", hostname ); 328 | exit(1); 329 | } 330 | addr.sin_addr = *(struct in_addr*)host->h_addr; 331 | 332 | 333 | sock = socket(AF_INET, SOCK_STREAM, pe->p_proto ); 334 | if( sock == -1 ) { 335 | log_error("error creating socket: %m\n" ); 336 | exit(1); 337 | } 338 | 339 | if( connect( sock, (struct sockaddr *)&addr, sizeof addr) == -1 ) { 340 | log_error("error connecting `%s': %m\n", hostname ); 341 | close(sock); 342 | exit(1); 343 | } 344 | 345 | if( rw_init( sock ) ) { 346 | log_error("rw_init failed\n" ); 347 | exit(1); 348 | } 349 | 350 | smtp = rfc821_open( NULL, NULL ); 351 | if( !smtp ) { 352 | log_error("rfc821_open failed\n" ); 353 | exit(1); 354 | } 355 | 356 | rfc821_set_proto_comment( smtp, "simple-mta client" ); 357 | rc = rfc821_start_session( smtp, sock ); 358 | if( rc ) { 359 | log_error("rfc821_start_session failed: rc=%d\n", rc ); 360 | rfc821_cancel( smtp ); close( sock ); 361 | exit(1); 362 | } 363 | 364 | 365 | msg = rfc822_open( NULL, NULL ); 366 | if( !msg ) { 367 | log_error("rfc822_open failed\n" ); 368 | rfc821_cancel( smtp ); close( sock ); 369 | exit(1); 370 | } 371 | for( ;; ) { 372 | size_t length; 373 | char *line = rw_readline( fd, 2000, &length, NULL ); 374 | if( !line ) 375 | break; /* EOF */ 376 | if( length && line[length-1] == '\r' ) 377 | line[--length] = 0; 378 | if( rfc822_insert( msg, line, length ) ) { 379 | rfc822_cancel( msg ); 380 | rfc821_cancel( smtp ); close( sock ); 381 | exit(1); 382 | } 383 | } 384 | if( fd != 0 ) 385 | close(fd); 386 | 387 | 388 | rc = rfc821_send_sender( smtp, mail_from ); 389 | if( rc ) { 390 | log_error("MAIL command failed: rc=%d\n", rc ); 391 | rfc822_cancel( msg ); 392 | rfc821_cancel( smtp ); close( sock ); 393 | exit(1); 394 | } 395 | 396 | for( sl = rcpt_to; sl; sl = sl->next ) { 397 | rc = rfc821_send_recipient( smtp, sl->d ); 398 | if( rc ) { 399 | log_error("RCPT command failed: rc=%d\n", rc ); 400 | rfc822_cancel( msg ); 401 | rfc821_cancel( smtp ); close( sock ); 402 | exit(1); 403 | } 404 | } 405 | 406 | 407 | rc = rfc821_copy_header_lines( smtp, msg ); 408 | if( !rc ) 409 | rc = rfc821_copy_body_lines( smtp, msg ); 410 | if( !rc ) 411 | rc = rfc821_send_body_line( smtp, NULL, 0 ); 412 | if( rc ) { 413 | log_error("DATA command failed: rc=%d\n", rc ); 414 | rfc822_cancel( msg ); 415 | rfc821_cancel( smtp ); close( sock ); 416 | exit(1); 417 | } 418 | rfc822_close( msg ); 419 | rfc821_close( smtp ); close( sock ); 420 | } 421 | 422 | 423 | return 0; 424 | } 425 | 426 | 427 | static int 428 | start_listening( int port ) 429 | { 430 | int fd; 431 | int one = 1; 432 | struct protoent *pe; 433 | struct sockaddr_in addr; 434 | 435 | if( port < 1 || port > 65534 ) { 436 | log_error("port %d is invalid\n", port ); 437 | return -1; 438 | } 439 | 440 | if( !(pe = getprotobyname("tcp")) ) { 441 | log_error("getprotobyname failed: %m\n" ); 442 | return -1; 443 | } 444 | 445 | fd = socket( AF_INET, SOCK_STREAM, pe->p_proto ); 446 | if( fd < 0 ) { 447 | log_error("error creating socket: %m\n" ); 448 | return -1; 449 | } 450 | if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, 451 | (const void *)&one, sizeof one) ) { 452 | log_error("error setting SO_REUSEADDR: %m\n" ); 453 | close(fd); 454 | return -1; 455 | } 456 | 457 | memset( &addr, 0, sizeof addr ); 458 | addr.sin_family = AF_INET; 459 | addr.sin_addr.s_addr = htonl( INADDR_ANY ); 460 | addr.sin_port = htons(port); 461 | if( bind( fd, (struct sockaddr*)&addr, sizeof addr ) ) { 462 | log_error("error binding port %d: %m\n", port ); 463 | close(fd); 464 | return -1; 465 | } 466 | 467 | if( listen( fd, 5 ) ) { 468 | log_error("error listening on port %d: %m\n", port ); 469 | close(fd); 470 | return -1; 471 | } 472 | 473 | return fd; 474 | } 475 | 476 | /**************** 477 | * This function is called by the rfc821 layer for certain events 478 | * This rfc821.h for a list of events. This function should 479 | * return with 0 for normal success or with an errorcode to let 480 | * the rfc821 layer return an error code. 481 | */ 482 | static int 483 | server_cb_rfc821( void *opaque, enum rfc821_events event, RFC821 smtp ) 484 | { 485 | SERVER state = opaque; 486 | int rc = 0; 487 | 488 | /*log_debug("fd %d: server_cb_rfc821: event %d\n", state->fd, event );*/ 489 | switch( event ) { 490 | case RFC821EVT_DATA: 491 | if( state->filename ) { 492 | state->stream = fopen( state->filename, "wb"); 493 | if( !state->stream ) { 494 | log_error("failed to open `%s': %m\n", state->filename ); 495 | rc = 1; 496 | } 497 | } 498 | else 499 | state->stream = stdout; 500 | break; 501 | 502 | case RFC821EVT_DATA_END: 503 | break; 504 | } 505 | 506 | return rc; 507 | } 508 | 509 | 510 | static int 511 | server_cb_rfc822( void *opaque, enum rfc822_events event, RFC822 msg ) 512 | { 513 | SERVER state = opaque; 514 | int rc = 0; 515 | 516 | if (loaded) 517 | return 2; /* This should force the 821 layer to send a temporary 518 | error code. */ 519 | 520 | /*log_debug("fd %d: server_cb_rfc822: event %d\n", state->fd, event );*/ 521 | if( event == RFC822EVT_FINISH && state->stream ) { 522 | void *ectx; 523 | const char *line; 524 | size_t n; 525 | 526 | for( ectx=NULL; !rc && (line = rfc822_enum_header_lines( msg, &ectx)); ) { 527 | if( fputs( line, state->stream ) == EOF 528 | || putc('\n', state->stream ) == EOF ) { 529 | log_error("fputs() failed: %m\n" ); 530 | rc = 1; 531 | } 532 | } 533 | rfc822_enum_header_lines( NULL, &ectx ); /* close enumerator */ 534 | 535 | putc('\n', state->stream ); 536 | 537 | for( ectx=NULL; !rc && (line = rfc822_enum_body_lines( msg, &ectx, &n)); ) { 538 | int nn; 539 | if( n && (nn=fwrite( line, n, 1, state->stream )) != 1 ) { 540 | log_error("fwrite() failed n=%d nn=%d: %m\n", n, nn ); 541 | rc = 1; 542 | } 543 | else if( putc('\n', state->stream ) == EOF ) { 544 | log_error("putc() failed: %m\n" ); 545 | rc = 1; 546 | } 547 | } 548 | rfc822_enum_body_lines( NULL, &ectx, NULL ); /* close enumerator */ 549 | if( state->stream == stdout ) 550 | ; 551 | else if( fclose(state->stream) ) { 552 | log_error("fclose() failed: %m\n" ); 553 | rc = 1; 554 | } 555 | state->stream = NULL; 556 | } 557 | 558 | return rc; 559 | } 560 | 561 | 562 | -------------------------------------------------------------------------------- /src/geamd.c: -------------------------------------------------------------------------------- 1 | /* geamd.c - The GEAM daemon 2 | * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf 3 | * Copyright (C) 2001, 2004 g10 Code GmbH 4 | * 5 | * This file is part of GEAM. 6 | * 7 | * GEAM is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * GEAM is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include /* for initgroups() */ 40 | 41 | #include "geamd.h" 42 | #include "argparse.h" 43 | #include "smtpproxy.h" 44 | #include "rfc821.h" 45 | #include "nethelp.h" 46 | 47 | #define DEFAULT_PORT 8025 48 | #define GPG_PROGRAM "/usr/local/bin/gpg" 49 | 50 | 51 | enum opt_values { aNull = 0, 52 | oVerbose = 'v', 53 | oQuiet = 'q', 54 | oOptions = 'C', 55 | oPort = 500, 56 | oNoFork, 57 | oInnerhostName, 58 | oInnerhostPort, 59 | oOuterhostName, 60 | oOuterhostPort, 61 | oReceivedHeadersMax, 62 | oAliasFile, 63 | oEncryptFile, 64 | oDecryptFile, 65 | oGPGBinary, 66 | oGPGHomedir, 67 | oLogFile, 68 | oUserName, 69 | oGroupName, 70 | oInnerNet, 71 | 72 | oDebug 73 | }; 74 | 75 | static ARGPARSE_OPTS opts[] = { 76 | { 301, NULL, 0, N_("@\nOptions:\n ") }, 77 | { oVerbose, "verbose", 0, N_("verbose") }, 78 | { oQuiet, "quiet", 0, N_("be more quiet")}, 79 | { oDebug, "debug", 4|16, N_("set debugging flags")}, 80 | { oNoFork, "no-fork", 0, N_("do not run as a daemon")}, 81 | { oOptions, "config", 2, N_("|FILE|read options from FILE")}, 82 | { oPort, "port", 1, N_("|N|listen on port N")}, 83 | { oInnerhostName, "inner-host-name", 2, "@" }, 84 | { oInnerhostPort, "inner-host-port", 1, "@" }, 85 | { oOuterhostName, "outer-host-name", 2, "@" }, 86 | { oOuterhostPort, "outer-host-port", 1, "@" }, 87 | { oInnerNet, "inner-net", 2, "@" }, 88 | { oReceivedHeadersMax, "received-headers-max", 1, "@" }, 89 | { oAliasFile, "alias-file", 2 , "|FILE|read aliases from FILE" }, 90 | { oEncryptFile,"encrypt-file", 2 , "|FILE|read encrypt info from FILE" }, 91 | { oDecryptFile,"decrypt-file", 2 , "|FILE|read decrypt info from FILE" }, 92 | { oGPGBinary, "gpg-program", 2 , "@" }, 93 | { oGPGHomedir,"gpg-homedir", 2 , "@" }, 94 | { oLogFile, "log-file", 2, "@" }, 95 | { oUserName, "user", 2, "@" }, 96 | { oGroupName, "group", 2, "@" }, 97 | {0} }; 98 | 99 | 100 | struct start_args { 101 | int fd; 102 | struct sockaddr peer_addr; 103 | int peer_port; 104 | char peer_addr_str[1]; 105 | }; 106 | 107 | static void *start_proxy_handler( void *arg ); 108 | static void handlesignals( int signo ); 109 | static void become_daemon(void); 110 | static int start_listening( int port ); 111 | static void change_userid( const char *username, const char *groupname ); 112 | 113 | 114 | static const char * 115 | my_strusage( int level ) 116 | { 117 | const char *p; 118 | switch( level ) { 119 | case 11: p = "geamd"; 120 | break; 121 | case 13: p = VERSION; break; 122 | case 14: p = "Copyright (C) 2004 g10 Code GmbH"; break; 123 | case 19: p = _("Please report bugs to .\n"); 124 | break; 125 | case 1: 126 | case 40: p = 127 | _("Usage: geamd [options] (-h for help)"); 128 | break; 129 | case 41: p = 130 | _("Syntax: geamd [options]\n" 131 | "run the SMTP encryption proxy\n"); 132 | break; 133 | 134 | default: p = NULL; 135 | } 136 | return p; 137 | } 138 | 139 | static void 140 | add_inner_net( const char *s ) 141 | { 142 | NETWORK_ADDRESS a; 143 | 144 | a = parse_network_address( s ); 145 | if( !a ) { 146 | log_error(_("invalid network address '%s'\n"), s); 147 | exit(2); 148 | } 149 | if( !opt.inner_nets ) { 150 | opt.inner_nets = a; 151 | } 152 | else { 153 | append_network_address( opt.inner_nets, a ); 154 | } 155 | } 156 | 157 | int 158 | main( int argc, char **argv ) 159 | { 160 | ARGPARSE_ARGS pargs; 161 | int orig_argc; 162 | char **orig_argv; 163 | FILE *configfp = NULL; 164 | char *configname; 165 | unsigned int configlineno; 166 | int nofork = 0; 167 | int port = DEFAULT_PORT; 168 | pth_attr_t tattr; 169 | pth_event_t ev; 170 | int listen_fd; 171 | char *innerhost_name = NULL; 172 | int innerhost_port = 0; 173 | char *outerhost_name = NULL; 174 | int outerhost_port = 0; 175 | sigset_t sigs; 176 | int signo; 177 | const char *logfile; 178 | const char *username; 179 | const char *groupname; 180 | 181 | set_strusage( my_strusage ); 182 | /*log_set_name("gaemd"); */ 183 | srand48( time(NULL) ); 184 | 185 | /* setup defaults */ 186 | configname = xstrdup( "/etc/geam/geamd.conf" ); 187 | opt.alias_file = "aliases"; 188 | opt.encrypt_file = "encrypt"; 189 | opt.decrypt_file = "decrypt"; 190 | opt.received_headers_max = 30; 191 | opt.gpg_binary = GPG_PROGRAM; 192 | opt.gpg_homedir = "/etc/geam/gpg"; 193 | logfile = "/var/log/geam/geamd"; 194 | username = "mail"; 195 | groupname = "mail"; 196 | 197 | opt.debug = 0; 198 | 199 | /* check whether we have a config file on the commandline */ 200 | orig_argc = argc; 201 | orig_argv = argv; 202 | pargs.argc = &argc; 203 | pargs.argv = &argv; 204 | pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */ 205 | while( arg_parse( &pargs, opts) ) { 206 | if( pargs.r_opt == oOptions ) 207 | configname = pargs.r.ret_str; 208 | } 209 | 210 | argc = orig_argc; 211 | argv = orig_argv; 212 | pargs.argc = &argc; 213 | pargs.argv = &argv; 214 | pargs.flags= 1; /* do not remove the args */ 215 | next_pass: 216 | if( configfp ) { 217 | fclose( configfp ); 218 | configfp = NULL; 219 | } 220 | else if( configname ) { 221 | configlineno = 0; 222 | configfp = fopen( configname, "r" ); 223 | if( !configfp ) { 224 | log_error(_("can't open configuration file `%s': %s\n"), 225 | configname, strerror(errno) ); 226 | configname = NULL; 227 | } 228 | } 229 | 230 | while( optfile_parse( configfp, configname, &configlineno, &pargs, opts) ) { 231 | switch( pargs.r_opt ) { 232 | case oQuiet: opt.quiet = 1; break; 233 | case oVerbose: opt.verbose++; break; 234 | case oDebug: opt.debug |= pargs.r.ret_ulong; break; 235 | case oNoFork: nofork = 1; break; 236 | case oPort: port = pargs.r.ret_int; break; 237 | case oInnerhostName: 238 | free(innerhost_name); 239 | innerhost_name = xstrdup(pargs.r.ret_str); 240 | break; 241 | case oInnerhostPort: innerhost_port = pargs.r.ret_int; break; 242 | case oOuterhostName: 243 | free(outerhost_name); 244 | outerhost_name = xstrdup(pargs.r.ret_str); 245 | break; 246 | case oOuterhostPort: outerhost_port = pargs.r.ret_int; break; 247 | 248 | case oInnerNet: 249 | add_inner_net( pargs.r.ret_str ); 250 | break; 251 | 252 | case oReceivedHeadersMax: 253 | opt.received_headers_max = pargs.r.ret_int; 254 | break; 255 | 256 | case oAliasFile: opt.alias_file = pargs.r.ret_str; break; 257 | case oEncryptFile: opt.encrypt_file = pargs.r.ret_str; break; 258 | case oDecryptFile: opt.decrypt_file = pargs.r.ret_str; break; 259 | 260 | case oGPGBinary: opt.gpg_binary = pargs.r.ret_str; break; 261 | case oGPGHomedir: opt.gpg_homedir = pargs.r.ret_str; break; 262 | case oLogFile: logfile = pargs.r.ret_str; break; 263 | case oUserName: username = pargs.r.ret_str; break; 264 | case oGroupName: groupname = pargs.r.ret_str; break; 265 | 266 | case oOptions: break; /* already processed */ 267 | default : pargs.err = configfp? 1:2; break; 268 | } 269 | } 270 | if ( configfp ) 271 | goto next_pass; 272 | 273 | if( configname && *configname == '/' ) { 274 | /* The options file has an absolute path. We modify the other 275 | * configuration files, so that they are in the same directory 276 | * - but only when they have a relative path too */ 277 | size_t dirlen = strrchr( configname, '/' ) - configname; 278 | 279 | if( *opt.alias_file != '/' ) { 280 | char *p = xmalloc( dirlen + strlen(opt.alias_file) + 2 ); 281 | memcpy(p, configname, dirlen ); 282 | strcpy(stpcpy(p+dirlen,"/"),opt.alias_file); 283 | opt.alias_file = p; 284 | } 285 | if( *opt.encrypt_file != '/' ) { 286 | char *p = xmalloc( dirlen + strlen(opt.encrypt_file) + 2 ); 287 | memcpy(p, configname, dirlen ); 288 | strcpy(stpcpy(p+dirlen,"/"),opt.encrypt_file); 289 | opt.encrypt_file = p; 290 | } 291 | if( *opt.decrypt_file != '/' ) { 292 | char *p = xmalloc( dirlen + strlen(opt.decrypt_file) + 2 ); 293 | memcpy(p, configname, dirlen ); 294 | strcpy(stpcpy(p+dirlen,"/"),opt.decrypt_file); 295 | opt.decrypt_file = p; 296 | } 297 | if( *opt.gpg_homedir != '/' ) { 298 | char *p = xmalloc( dirlen + strlen(opt.gpg_homedir) + 2 ); 299 | memcpy(p, configname, dirlen ); 300 | strcpy(stpcpy(p+dirlen,"/"),opt.gpg_homedir); 301 | opt.gpg_homedir = p; 302 | } 303 | 304 | } 305 | else if( configname ) { 306 | /* Because we chdir to /, we do not alow a relative name 307 | * for the configuration name. This file name is used to deduce 308 | * the base for the other relative filenames - we better put out 309 | * a wrning in this case */ 310 | log_info("no absolute path name given for configuration file\n"); 311 | } 312 | 313 | 314 | log_set_file( logfile ); 315 | if( DBG_SMTP ) 316 | rfc821_set_flag( NULL, RFC821FLG_DBGSMTP, 1 ); 317 | 318 | if( !nofork ) 319 | become_daemon(); 320 | 321 | log_info( "%s %s started (pid=%u)\n", strusage(11), strusage(13), 322 | (unsigned int)getpid() ); 323 | if( smtpproxy_set_smarthost( innerhost_name, innerhost_port, 324 | outerhost_name, outerhost_port ) ) { 325 | log_error("invalid smarthost\n"); 326 | exit(1); 327 | } 328 | 329 | if( smtpproxy_read_configs() ) { 330 | log_error("failed to read the configuration information\n"); 331 | exit(1); 332 | } 333 | 334 | if( !pth_init() ) 335 | log_fatal("failed to initialize the Pth library\n"); 336 | signal( SIGPIPE, SIG_IGN ); 337 | 338 | listen_fd = start_listening( port ); 339 | if( listen_fd == -1 ) 340 | return 1; 341 | 342 | change_userid( username, groupname ); 343 | 344 | tattr = pth_attr_new(); 345 | pth_attr_set( tattr, PTH_ATTR_JOINABLE, 0 ); 346 | pth_attr_set( tattr, PTH_ATTR_STACK_SIZE, 32*1024); 347 | pth_attr_set( tattr, PTH_ATTR_NAME, "smtpproxy"); 348 | 349 | sigemptyset( &sigs ); 350 | sigaddset( &sigs, SIGHUP ); 351 | sigaddset( &sigs, SIGUSR1 ); 352 | sigaddset( &sigs, SIGUSR2 ); 353 | sigaddset( &sigs, SIGINT ); 354 | sigaddset( &sigs, SIGTERM ); 355 | ev = pth_event(PTH_EVENT_SIGS, &sigs, &signo ); 356 | for(;;) { 357 | struct start_args *sarg; 358 | char *p; 359 | struct sockaddr_in paddr; 360 | socklen_t plen = sizeof( paddr ); 361 | int fd; 362 | 363 | if( opt.shutdown_pending ) { 364 | if( pth_ctrl( PTH_CTRL_GETTHREADS ) == 1 ) 365 | break; 366 | 367 | /* Do not accept anymore connections and wait for the threads 368 | * to terminate */ 369 | signo = 0; 370 | pth_wait(ev); 371 | if( pth_event_occurred( ev ) && signo ) { 372 | handlesignals( signo ); 373 | } 374 | 375 | continue; 376 | } 377 | 378 | fd = pth_accept_ev( listen_fd, (struct sockaddr *)&paddr, &plen, ev); 379 | if( fd == -1 ) { 380 | if( pth_event_occurred( ev ) ) { 381 | handlesignals( signo ); 382 | continue; 383 | } 384 | log_error( "accept failed: %s - waiting 1s\n", strerror(errno) ); 385 | pth_sleep(1); 386 | continue; 387 | } 388 | 389 | p = inet_ntoa(paddr.sin_addr); 390 | sarg = xmalloc( sizeof *sarg + strlen(p) ); 391 | sarg->fd = fd; 392 | sarg->peer_port = (int)ntohs(paddr.sin_port); 393 | memcpy( &sarg->peer_addr, (struct sockaddr *)&paddr, sizeof( paddr ) ); 394 | strcpy( sarg->peer_addr_str, p ); 395 | 396 | if( !pth_spawn( tattr, start_proxy_handler, sarg ) ) { 397 | log_error( "error spawning connection handler: %s\n", 398 | strerror(errno) ); 399 | close(fd); 400 | } 401 | } 402 | 403 | pth_event_free(ev, PTH_FREE_ALL); 404 | log_info( "%s %s stopped\n", strusage(11), strusage(13) ); 405 | 406 | 407 | return 0; 408 | } 409 | 410 | 411 | static char * 412 | encode36( char *buf, unsigned long value, int minlen ) 413 | { 414 | char *p, *p0; 415 | int n; 416 | 417 | p = buf; 418 | do { 419 | n = value % 36; 420 | if( n < 10 ) 421 | *p++ = n + '0'; 422 | else 423 | *p++ = (n-10)+'a'; 424 | 425 | } while( (value /= 36 ) ); 426 | *p = 0; 427 | for( p0=buf, p--; p0 < p; ) { 428 | char c = *p0; 429 | *p0++ = *p; 430 | *p-- = c; 431 | } 432 | n = strlen(buf); 433 | 434 | if( n < minlen ) { 435 | memmove(buf+(minlen-n), buf, n+1); 436 | memset(buf, '0', (minlen-n)); 437 | } 438 | 439 | return buf; 440 | } 441 | 442 | 443 | 444 | 445 | 446 | static void * 447 | start_proxy_handler( void *arg ) 448 | { 449 | void *rv; 450 | struct start_args *a = arg; 451 | char sessid[30], pbuf[10], tbuf[10], cbuf[10]; 452 | static int counter; 453 | 454 | encode36(pbuf, getpid(), 4); 455 | encode36(tbuf, time(NULL), 6); 456 | encode36(cbuf, counter, 3 ); 457 | if( ++counter >= (36*36*36) ) 458 | counter = 0; 459 | /* we make sure that the session ID will always start with a digit 460 | * even if the sessio ID gets larger by prefixing the 0 */ 461 | snprintf( sessid, sizeof sessid, "%s%s-%s-%s", 462 | isdigit(*pbuf)?"":"0", 463 | pbuf, tbuf, cbuf ); 464 | 465 | log_info( "%s connect from %s:%d (fd=%d)\n", sessid, 466 | a->peer_addr_str, a->peer_port, a->fd ); 467 | 468 | rv = smtpproxy_handler( a->fd, sessid, &a->peer_addr, 469 | a->peer_addr_str, 470 | a->peer_port ); 471 | log_info( "%s ready\n", sessid ); 472 | free( a ); 473 | 474 | return rv; 475 | } 476 | 477 | static void 478 | handlesignals( int signo ) 479 | { 480 | switch( signo ) 481 | { 482 | case SIGHUP: 483 | log_info("SIGHUP received - re-reading configuration\n"); 484 | smtpproxy_read_configs(); 485 | break; 486 | 487 | case SIGUSR1: 488 | if( opt.verbose < 5 ) 489 | opt.verbose++; 490 | if( opt.verbose == 3 ) 491 | rfc821_set_flag( NULL, RFC821FLG_DBGSMTP, 1 ); 492 | log_info("SIGUSR1 received - verbosity set to %d\n", opt.verbose ); 493 | break; 494 | 495 | case SIGUSR2: 496 | if( opt.verbose == 3 ) 497 | rfc821_set_flag( NULL, RFC821FLG_DBGSMTP, 0 ); 498 | if( opt.verbose ) 499 | opt.verbose--; 500 | log_info("SIGUSR1 received - verbosity set to %d\n", opt.verbose ); 501 | break; 502 | 503 | case SIGTERM: 504 | if( !opt.shutdown_pending ) 505 | log_info("SIGTERM received - shutting down ...\n" ); 506 | else 507 | log_info("SIGTERM received - still %ld running threads\n", 508 | pth_ctrl( PTH_CTRL_GETTHREADS ) ); 509 | opt.shutdown_pending++; 510 | if( opt.shutdown_pending > 2 ) { 511 | log_info("shutdown forced\n" ); 512 | log_info("%s %s stopped\n", strusage(11), strusage(13) ); 513 | exit(0); 514 | } 515 | break; 516 | 517 | case SIGINT: 518 | log_info( "SIGINT received - immediate shutdown\n" ); 519 | log_info( "%s %s stopped\n", strusage(11), strusage(13) ); 520 | exit(0); 521 | break; 522 | 523 | default: 524 | log_info("signal %d received - no action defined\n", signo); 525 | } 526 | } 527 | 528 | 529 | 530 | static void 531 | become_daemon() 532 | { 533 | long nfile; 534 | int i, n; 535 | int childpid; 536 | 537 | if( opt.verbose ) 538 | log_info("becoming a daemon ...\n"); 539 | fflush(NULL); 540 | 541 | /* FIXME: handle the TTY signals */ 542 | 543 | if( (childpid = fork()) == -1 ) 544 | log_fatal("can't fork first child: %s\n", strerror(errno)); 545 | else if( childpid > 0 ) 546 | exit(0); /* terminate parent */ 547 | 548 | /* Disassociate from controlling terminal etc. */ 549 | if( setsid() == -1 ) 550 | log_fatal("setsid() failed: %s\n", strerror(errno) ); 551 | 552 | /* close all files but not the log files */ 553 | if( (nfile=sysconf( _SC_OPEN_MAX )) < 0 ) { 554 | #ifdef _POSIX_OPEN_MAX 555 | nfile = _POSIX_OPEN_MAX; 556 | #else 557 | nfile = 20; /* assume a reasonable value */ 558 | #endif 559 | } 560 | n = log_get_fd(); 561 | for(i=0; i < nfile; i++ ) 562 | if( i != n ) 563 | close(i); 564 | errno = 0; 565 | 566 | if( chdir("/") ) 567 | log_fatal("chdir to root failed: %s\n", strerror(errno) ); 568 | umask(0); 569 | 570 | if( opt.verbose ) 571 | log_info("now running as daemon\n"); 572 | } 573 | 574 | static int 575 | start_listening( int port ) 576 | { 577 | int fd; 578 | int one = 1; 579 | struct protoent *pe; 580 | struct sockaddr_in addr; 581 | 582 | if( port < 1 || port > 65534 ) { 583 | log_error("port %d is invalid\n", port ); 584 | return -1; 585 | } 586 | 587 | if( !(pe = getprotobyname("tcp")) ) { 588 | log_error("getprotobyname failed: %s\n", strerror(errno) ); 589 | return -1; 590 | } 591 | 592 | fd = socket( AF_INET, SOCK_STREAM, pe->p_proto ); 593 | if( fd < 0 ) { 594 | log_error("error creating socket: %s\n", strerror(errno) ); 595 | return -1; 596 | } 597 | if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, 598 | (const void *)&one, sizeof one) ) { 599 | log_error("error setting SO_REUSEADDR: %s\n", strerror(errno) ); 600 | close(fd); 601 | return -1; 602 | } 603 | 604 | memset( &addr, 0, sizeof addr ); 605 | addr.sin_family = AF_INET; 606 | addr.sin_addr.s_addr = htonl( INADDR_ANY ); 607 | addr.sin_port = htons(port); 608 | if( bind( fd, (struct sockaddr*)&addr, sizeof addr ) ) { 609 | log_error("error binding port %d: %s\n", port, strerror(errno) ); 610 | close(fd); 611 | return -1; 612 | } 613 | 614 | if( listen( fd, 5 ) ) { 615 | log_error("error listening on port %d: %s\n", port, strerror(errno) ); 616 | close(fd); 617 | return -1; 618 | } 619 | 620 | return fd; 621 | } 622 | 623 | static void 624 | change_userid( const char *username, const char *groupname ) 625 | { 626 | uid_t uid; 627 | struct passwd *pw; 628 | gid_t gid; 629 | struct group *gr; 630 | 631 | if( geteuid() ) { 632 | log_info("note: user ID not changed\n"); 633 | return; 634 | } 635 | 636 | pw = getpwnam( username ); 637 | if( !pw ) { 638 | log_error("change user to `%s' failed: no such user\n", groupname ); 639 | exit(1); 640 | } 641 | uid = pw->pw_uid; 642 | gr = getgrnam( groupname ); 643 | if( !gr ) { 644 | log_error("change group to `%s' failed: no such group\n", groupname ); 645 | exit(1); 646 | } 647 | gid = gr->gr_gid; 648 | 649 | if( setgid( gid ) ) { 650 | log_error("change group to `%s' failed: %m\n", groupname ); 651 | exit(1); 652 | } 653 | 654 | if( initgroups( username, gid ) ) { 655 | log_error("initgroups for `%s' failed: %m\n", username ); 656 | exit(1); 657 | } 658 | 659 | if( setuid( uid ) ) { 660 | log_error("change user to `%s' failed: %m\n", username ); 661 | exit(1); 662 | } 663 | log_info("running as %s:%s (%u:%u)\n", username,groupname, 664 | (unsigned int)uid, (unsigned int)gid ); 665 | 666 | } 667 | 668 | 669 | -------------------------------------------------------------------------------- /doc/localstyle.dsl.in: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | ]]> 8 | 9 | 11 | ]]> 12 | ]> 13 | 14 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ;;========================================================================== 36 | ;; PRINT 37 | ;;========================================================================== 38 | 39 | (define %gentext-de-by% "") ;; Copyright 1900 by Otto Mueller 40 | ;; there is no by (von) in German 41 | 42 | ;;====================================== 43 | ;;General Options 44 | ;;====================================== 45 | 46 | ;;Do you want to print on both sides of the paper? 47 | (define %two-side% 48 | #t) 49 | 50 | ;;Do you want enumerated sections? (E.g, 1.1, 1.1.1, 1.2, etc.) 51 | (define %section-autolabel% 52 | #f) 53 | 54 | ;;What is the default extension for graphics? 55 | (define %graphic-default-extension% 56 | "eps") 57 | 58 | ;;Show URL links? If the text of the link and the URL are identical, 59 | ;;the parenthetical URL is suppressed. 60 | (define %show-ulinks% 61 | #t) 62 | 63 | ;;Tex Backend on 64 | (define tex-backend 65 | #t) 66 | 67 | ;;Define Line Spacing 68 | (define %line-spacing-factor% 1.1) 69 | 70 | ;;Define the Paragraph Style 71 | (define para-style 72 | (style 73 | font-size: %bf-size% 74 | font-weight: 'medium 75 | font-posture: 'upright 76 | font-family-name: %body-font-family% 77 | line-spacing: (* %bf-size% %line-spacing-factor%))) 78 | 79 | (define ($object-titles-after$) 80 | (list (normalize "figure"))) 81 | 82 | ;Make Ulinks footnotes to stop bleeding in the edges - this increases 83 | ;jade time tremendously! 84 | (define %footnote-ulinks% 85 | #t) 86 | 87 | ;;====================================== 88 | ;;Book Options 89 | ;;====================================== 90 | 91 | 92 | ;;Do you want a title page for a Book? 93 | (define %generate-book-titlepage% 94 | #t) 95 | 96 | ;;Do you want a separate page for the title? 97 | (define %generate-book-titlepage-on-separate-page% 98 | #t) 99 | 100 | ;;Generate Book TOC? 101 | (define %generate-book-toc% 102 | #t) 103 | 104 | ;;Do you want a TOC for the element part? 105 | (define %generate-part-toc% 106 | #f) 107 | 108 | ;;Do you want the part toc on the part titlepage or separate? 109 | (define %generate-part-toc-on-titlepage% 110 | #t) 111 | 112 | ;;Generate Part Title Page? 113 | (define %generate-part-titlepage% 114 | #f) 115 | 116 | ;;Do you want the Part intro on the part title page? 117 | (define %generate-partintro-on-titlepage% 118 | #t) 119 | 120 | ;;What elements should have a LOT? 121 | (define ($generate-book-lot-list$) 122 | (list (normalize "example") 123 | (normalize "equation"))) 124 | 125 | ;;Do you want chapters enumerated? 126 | (define %chapter-autolabel% 127 | #t) 128 | 129 | ;;Automatically label chapters if no label is given? 130 | (define %chap-app-running-head-autolabel% 131 | #t) 132 | 133 | ;;====================================== 134 | ;;Article Options 135 | ;;====================================== 136 | 137 | ;;Do you want a title page for an Article? 138 | (define %generate-article-titlepage% 139 | #t) 140 | 141 | ;;Do you want a separate page for the title? 142 | (define %generate-article-titlepage-on-separate-page% 143 | #t) 144 | 145 | ;;Do you want the article toc on the titlepage or separate? 146 | (define %generate-article-toc-on-titlepage% 147 | #t) 148 | 149 | ;;Do you want to start new page numbers with each article? 150 | (define %article-page-number-restart% 151 | #f) 152 | 153 | ;;====================================== 154 | ;;Columns 155 | ;;====================================== 156 | 157 | ;;How many columns do you want? 158 | (define %page-n-columns% 159 | 1) 160 | 161 | ;;How much space between columns? 162 | (define %page-column-sep% 163 | 0.2in) 164 | 165 | ;;====================================== 166 | ;;Fonts 167 | ;;====================================== 168 | 169 | ;;Defines the general size of the text in the document. normal(10), 170 | ;;presbyopic(12), and large-type(24). 171 | (define %visual-acuity% 172 | "normal") 173 | 174 | ;;What font would you like for titles? 175 | (define %title-font-family% 176 | "Helvetica") 177 | 178 | ;;What font would you like for the body? 179 | (define %body-font-family% 180 | "Palatino") 181 | 182 | ;;What font would you like for mono-seq? 183 | (define %mono-font-family% 184 | "Courier New") 185 | 186 | ;;If the base fontsize is 10pt, and '%hsize-bump-factor%' is 187 | ;; 1.2, hsize 1 is 12pt, hsize 2 is 14.4pt, hsize 3 is 17.28pt, etc 188 | (define %hsize-bump-factor% 189 | 1.1) 190 | ;;1.2 191 | 192 | ;;What size do you want the body fonts? 193 | (define %bf-size% 194 | (case %visual-acuity% 195 | (("tiny") 9pt) 196 | (("normal") 11pt) 197 | (("presbyopic") 12pt) 198 | (("large-type") 24pt))) 199 | 200 | (define-unit em %bf-size%) 201 | 202 | ;;====================================== 203 | ;;Margins 204 | ;;====================================== 205 | 206 | (define %left-right-margin% 6pi) 207 | 208 | ;;How much indentation for the body? 209 | (define %body-start-indent% 210 | 4pi) 211 | 212 | ;;How big is the left margin? (relative to physical page) 213 | (define %left-margin% 214 | 8pi) ;white-paper-column 215 | 216 | ;;How big is the right margin? (relative to physical page) 217 | (define %right-margin% 218 | 8pi) ;white-paper-column 219 | 220 | ;;How big do you want the margin at the top? 221 | (define %top-margin% 222 | (if (equal? %visual-acuity% "large-type") 223 | 7.5pi 224 | 4pi)) 225 | 226 | ;;How big do you want the margin at the bottom? 227 | (define %bottom-margin% 228 | (if (equal? %visual-acuity% "large-type") 229 | 7.5pi 230 | 2pi)) 231 | 232 | ;;Define the text width. (Change the elements in the formula rather 233 | ;;than the formula itself) 234 | 235 | ;(define %text-width% (- %page-width% (* %left-right-margin% 2))) 236 | (define %text-width% (- %page-width% (+ %left-margin% %right-margin%))) 237 | 238 | ;;Define the body width. (Change the elements in the formula rather 239 | ;;than the formula itself) 240 | (define %body-width% 241 | (- %text-width% %body-start-indent%)) 242 | 243 | ;;Define distance between paragraphs 244 | (define %para-sep% 245 | (/ %bf-size% 2.0)) 246 | 247 | ;;Define distance between block elements (figures, tables, etc.). 248 | (define %block-sep% 249 | (* %para-sep% 2.0)) 250 | 251 | ;;Indent block elements? 252 | (define %block-start-indent% 253 | 0pt) 254 | 255 | ;;====================================== 256 | ;;Admon Graphics 257 | ;;====================================== 258 | 259 | ;;Do you want admon graohics on? 260 | (define %admon-graphics% 261 | #f) 262 | 263 | ;;====================================== 264 | ;;Quadding 265 | ;;====================================== 266 | 267 | ;;What quadding do you want by default; start, center, justify, or end? 268 | (define %default-quadding% 269 | 'start) 270 | 271 | ;;What quadding for component titles(Chapter, Appendix, etc)? 272 | (define %component-title-quadding% 273 | 'start) 274 | 275 | ;;What quadding for section titles? 276 | (define %section-title-quadding% 277 | 'start) 278 | 279 | ;;What quadding for section sub-titles? 280 | (define %section-subtitle-quadding% 281 | 'start) 282 | 283 | ;;What quadding for article title? 284 | (define %article-title-quadding% 285 | 'start) 286 | 287 | ;;What quadding for division subtitles? 288 | (define %division-subtitle-quadding% 289 | 'start) 290 | 291 | ;;What quadding for component subtitles? 292 | (define %component-subtitle-quadding% 293 | 'start) 294 | 295 | ;;What quadding for article sub-titles? 296 | (define %article-subtitle-quadding% 297 | 'start) 298 | 299 | ;;====================================== 300 | ;;Paper Options 301 | ;;====================================== 302 | 303 | ;;What size paper do you need? A4, USletter, USlandscape, or RedHat? 304 | (define %paper-type% 305 | "A4") 306 | 307 | ;;Now define those paper types' width 308 | (define %page-width% 309 | (case %paper-type% 310 | (("A4") 210mm) 311 | (("USletter") 8.5in) 312 | (("RedHat") 7.0in) 313 | (("USlandscape") 11in))) 314 | 315 | ;;Now define those paper types' height 316 | (define %page-height% 317 | (case %paper-type% 318 | (("A4") 297mm) 319 | (("USletter") 11in) 320 | (("RedHat") 8.5in) 321 | (("USlandscape") 8.5in))) 322 | 323 | 324 | ;;====================== =============== 325 | ;;Functions 326 | ;;====================================== 327 | 328 | (define (OLSTEP) 329 | (case 330 | (modulo (length (hierarchical-number-recursive "ORDEREDLIST")) 4) 331 | ((1) 1.2em) 332 | ((2) 1.2em) 333 | ((3) 1.6em) 334 | ((0) 1.4em))) 335 | 336 | (define (ILSTEP) 1.0em) 337 | 338 | (define (PROCSTEP ilvl) 339 | (if (> ilvl 1) 1.8em 1.4em)) 340 | 341 | (define (PROCWID ilvl) 342 | (if (> ilvl 1) 1.8em 1.4em)) 343 | 344 | (define ($comptitle$) 345 | (make paragraph 346 | font-family-name: %title-font-family% 347 | font-weight: 'bold 348 | font-size: (HSIZE 2) 349 | line-spacing: (* (HSIZE 2) %line-spacing-factor%) 350 | space-before: (* (HSIZE 2) %head-before-factor%) 351 | space-after: (* (HSIZE 2) %head-after-factor%) 352 | start-indent: 0pt 353 | first-line-start-indent: 0pt 354 | quadding: 'start 355 | keep-with-next?: #t 356 | (process-children-trim))) 357 | 358 | ;;Callouts are confusing in Postscript... fix them. 359 | (define %callout-fancy-bug% 360 | #f) 361 | 362 | ;;====================================== 363 | ;;Non-printing Elements 364 | ;;====================================== 365 | 366 | (element COMMENT (empty-sosofo)) 367 | (element TITLEABBREV (empty-sosofo)) 368 | (element SETINFO (empty-sosofo)) 369 | (element BIBLIOENTRY (empty-sosofo)) 370 | (element BIBLIOMISC (empty-sosofo)) 371 | (element BOOKBIBLIO (empty-sosofo)) 372 | (element SERIESINFO (empty-sosofo)) 373 | 374 | ;;====================================== 375 | ;;Formalpara titles 376 | ;;====================================== 377 | 378 | ;;Change the way Formal Paragraph titles are displayed. The commented 379 | ;;out section will run the titles in the paragraphs. 380 | (element (formalpara title) 381 | ;(make sequence 382 | ;font-weight: 'bold 383 | ;($runinhead$)) 384 | ($lowtitle$ 5)) 385 | 386 | ;;====================================== 387 | ;;Inlines 388 | ;;====================================== 389 | 390 | (element application ($mono-seq$)) 391 | (element command ($bold-seq$)) 392 | (element filename ($mono-seq$)) 393 | (element function ($mono-seq$)) 394 | (element guibutton ($bold-seq$)) 395 | (element guiicon ($bold-seq$)) 396 | (element guilabel ($italic-seq$)) 397 | (element guimenu ($bold-seq$)) 398 | (element guimenuitem ($bold-seq$)) 399 | (element hardware ($bold-mono-seq$)) 400 | (element keycap ($bold-seq$)) 401 | (element literal ($mono-seq$)) 402 | (element parameter ($italic-mono-seq$)) 403 | (element prompt ($mono-seq$)) 404 | (element symbol ($charseq$)) 405 | (element emphasis ($italic-seq$)) 406 | 407 | 408 | ;;===================================== 409 | ;;Title Page Changes 410 | ;;===================================== 411 | 412 | (mode article-titlepage-recto-mode 413 | 414 | (element authorgroup 415 | (make display-group 416 | lines: 'asis 417 | (literal "by") 418 | (process-children))) 419 | 420 | (element affiliation 421 | (make display-group 422 | use: article-titlepage-recto-style 423 | quadding: 'start 424 | (process-children))) 425 | 426 | (element address 427 | (make display-group 428 | use: article-titlepage-recto-style 429 | quadding: 'start 430 | (process-children))) 431 | 432 | (element email 433 | (make display-group 434 | use: article-titlepage-recto-style 435 | quadding: 'start))) 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 449 | 450 | 451 | 452 | 453 | ;; this is necessary because right now jadetex does not understand 454 | ;; symbolic entities, whereas things work well with numeric entities. 455 | (declare-characteristic preserve-sdata? 456 | "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" 457 | #f) 458 | 459 | 460 | ;;========================= 461 | ;;Common Stuff 462 | ;;========================= 463 | 464 | ;;Should there be a link to the legalnotice? 465 | (define %generate-legalnotice-link% 466 | #t) 467 | 468 | ;;What graphics extensions allowed? 469 | (define %graphic-extensions% 470 | '("gif" "png" "jpg" "jpeg" "tif" "tiff" "eps" "epsf" )) 471 | 472 | ;;What is the default extension for images? 473 | (define %graphic-default-extension% "png") 474 | 475 | ;;Use element ids as filenames? 476 | (define %use-id-as-filename% 477 | #t) 478 | 479 | 480 | ;;========================= 481 | ;;Book Stuff 482 | ;;========================= 483 | 484 | ;;Do you want a TOC for Books? 485 | (define %generate-book-toc% 486 | #t) 487 | 488 | ;;What depth should the TOC generate? 489 | ;;Only top level of appendixes 490 | (define (toc-depth nd) 491 | (if (string=? (gi nd) (normalize "book")) 492 | 3 493 | (if (string=? (gi nd) (normalize "appendix")) 494 | 0 495 | 1))) 496 | 497 | ;;What elements should have an LOT? 498 | (define ($generate-book-lot-list$) 499 | (list (normalize "table") 500 | (normalize "example") 501 | (normalize "equation"))) 502 | 503 | ;;Do you want a title page for your Book? 504 | (define %generate-book-titlepage% 505 | #t) 506 | 507 | ;;========================= 508 | ;;Part Stuff 509 | ;;========================= 510 | 511 | ;;Should parts have TOCs? 512 | (define %generate-part-toc% 513 | #t) 514 | 515 | ;;Should part TOCs be on their titlepages? 516 | (define %generate-part-toc-on-titlepage% 517 | #t) 518 | 519 | ;;Do you want a title page for your part? 520 | (define %generate-part-titlepage% 521 | #t) 522 | 523 | ;;Should the Part intro be on the part title page? 524 | (define %generate-partintro-on-titlepage% 525 | #t) 526 | 527 | ;;======================== 528 | ;;Chapter Stuff 529 | ;;======================= 530 | 531 | (define $generate-chapter-toc$ 532 | (lambda () 533 | #f)) 534 | 535 | ;;========================= 536 | ;;Navigation 537 | ;;========================= 538 | 539 | ;;Should there be navigation at top? 540 | (define %header-navigation% 541 | #t) 542 | 543 | ;;Should there be navigation at bottom? 544 | (define %footer-navigation% 545 | #t) 546 | 547 | ;;Use tables to create the navigation? 548 | (define %gentext-nav-use-tables% 549 | #t) 550 | 551 | ;;If tables are used for navigation, 552 | ;;how wide should they be? 553 | (define %gentext-nav-tblwidth% 554 | "100%") 555 | 556 | ;;Add arrows to navigation 557 | (define (gentext-en-nav-prev prev) 558 | (make sequence (literal "<<< Previous"))) 559 | 560 | (define (gentext-en-nav-next next) 561 | (make sequence (literal "Next >>>"))) 562 | 563 | 564 | ;;========================= 565 | ;;Tables and Lists 566 | ;;========================= 567 | 568 | ;;Should Variable lists be tables? 569 | (define %always-format-variablelist-as-table% 570 | #f) 571 | 572 | ;;What is the length of the 'Term' in a variablelist? 573 | (define %default-variablelist-termlength% 574 | 20) 575 | 576 | ;;When true | If the terms are shorter than 577 | ;;the termlength above then the variablelist 578 | ;;will be formatted as a table. 579 | (define %may-format-variablelist-as-table% 580 | #f) 581 | 582 | ;;This overrides the tgroup definition 583 | ;;(copied from 1.20, dbtable.dsl). 584 | ;;It changes the table background color, 585 | ;;cell spacing and cell padding. 586 | 587 | (element tgroup 588 | (let* ((wrapper (parent (current-node))) 589 | (frameattr (attribute-string (normalize "frame") wrapper)) 590 | (pgwide (attribute-string (normalize "pgwide") wrapper)) 591 | (footnotes (select-elements (descendants (current-node)) 592 | (normalize "footnote"))) 593 | (border (if (equal? frameattr (normalize "none")) 594 | '(("BORDER" "0")) 595 | '(("BORDER" "1")))) 596 | (bgcolor '(("BGCOLOR" "#E0E0E0"))) 597 | (width (if (equal? pgwide "1") 598 | (list (list "WIDTH" ($table-width$))) 599 | '())) 600 | (head (select-elements (children (current-node)) (normalize "thead"))) 601 | (body (select-elements (children (current-node)) (normalize "tbody"))) 602 | (feet (select-elements (children (current-node)) (normalize "tfoot")))) 603 | (make element gi: "TABLE" 604 | attributes: (append 605 | border 606 | width 607 | bgcolor 608 | '(("CELLSPACING" "0")) 609 | '(("CELLPADDING" "4")) 610 | (if %cals-table-class% 611 | (list (list "CLASS" %cals-table-class%)) 612 | '())) 613 | (process-node-list head) 614 | (process-node-list body) 615 | (process-node-list feet) 616 | (make-table-endnotes)))) 617 | 618 | ;;=================== 619 | ;; Admon Graphics 620 | ;;=================== 621 | 622 | ;;Should Admon Graphics be used? 623 | (define %admon-graphics% 624 | #t) 625 | 626 | ;;Where are those admon graphics? 627 | (define %admon-graphics-path% 628 | "./stylesheet-images/") 629 | 630 | ;;Given an admonition node, returns the 631 | ;;name of the graphic that should 632 | ;;be used for that admonition. 633 | 634 | (define ($admon-graphic$ #!optional (nd (current-node))) 635 | (cond ((equal? (gi nd) (normalize "tip")) 636 | (string-append %admon-graphics-path% "tip.gif")) 637 | ((equal? (gi nd) (normalize "note")) 638 | (string-append %admon-graphics-path% "note.gif")) 639 | ((equal? (gi nd) (normalize "important")) 640 | (string-append %admon-graphics-path% "important.gif")) 641 | ((equal? (gi nd) (normalize "caution")) 642 | (string-append %admon-graphics-path% "caution.gif")) 643 | ((equal? (gi nd) (normalize "warning")) 644 | (string-append %admon-graphics-path% "warning.gif")) 645 | (else (error (string-append (gi nd) " is not an admonition."))))) 646 | 647 | ;;Given an admonition node, returns 648 | ;;the width of the graphic that will 649 | ;;be used for that admonition. 650 | (define ($admon-graphic-width$ #!optional (nd (current-node))) 651 | "25") 652 | 653 | ;;========================= 654 | ;;Labels 655 | ;;========================= 656 | 657 | ;;Enumerate Chapters? 658 | (define %chapter-autolabel% 659 | #f) 660 | 661 | ;;Enumerate Sections? 662 | (define %section-autolabel% 663 | #f) 664 | 665 | ;;========================= 666 | ;; HTML Attributes 667 | ;;========================= 668 | 669 | ;;What attributes should be hung off 670 | ;;of 'body'? 671 | (define %body-attr% 672 | (list 673 | (list "BGCOLOR" "#FFFFFF") 674 | (list "TEXT" "#000000") 675 | (list "LINK" "#0000FF") 676 | (list "VLINK" "#840084") 677 | (list "ALINK" "#0000FF"))) 678 | 679 | ;;Default extension for filenames? 680 | (define %html-ext% 681 | ".html") 682 | 683 | ;;Use a CSS stylesheet? 684 | ;;Which one? 685 | ;(define %stylesheet% 686 | ; "./gnome.css") 687 | 688 | ;;======================== 689 | ;;Title Pages for Books 690 | ;;======================= 691 | 692 | (define (book-titlepage-recto-elements) 693 | (list (normalize "title") 694 | (normalize "subtitle") 695 | (normalize "authorgroup") 696 | (normalize "copyright") 697 | (normalize "revhistory") 698 | (normalize "legalnotice") 699 | (normalize "orgname"))) 700 | 701 | 702 | ;;How should elements on title page look? 703 | (mode book-titlepage-recto-mode 704 | 705 | (element authorgroup 706 | (make sequence 707 | (literal "by:") 708 | (process-children))) 709 | 710 | ;;Author name is too big - change it! 711 | (element author 712 | (let ((author-name (author-string)) 713 | (author-affil (select-elements (children (current-node)) 714 | (normalize "affiliation")))) 715 | (make sequence 716 | (make element gi: "H4" 717 | attributes: (list (list "CLASS" (gi))) 718 | (make element gi: "A" 719 | attributes: (list (list "NAME" (element-id))) 720 | (literal author-name))) 721 | (process-node-list author-affil)))) 722 | 723 | ;;Address? 724 | (element address 725 | (make sequence 726 | (make element gi: "DIV" 727 | attributes: (list (list "CLASS" (gi))) 728 | (process-children)))) 729 | 730 | ;;Get rid of spam-producing "mailto" links 731 | ;;and get rid of email indentation 732 | (element email 733 | (make sequence 734 | (make element gi: "DIV" 735 | attributes: (list (list "CLASS" (gi))) 736 | (process-children)))) 737 | 738 | 739 | ;;revhistory table is MUCH too wide! 740 | (element revhistory 741 | (make element gi: "DIV" 742 | attributes: (list (list "CLASS" (gi))) 743 | (make element gi: "TABLE" 744 | attributes: (list 745 | (list "WIDTH" "35%") 746 | (list "BORDER" "0")) 747 | (make sequence 748 | (make element gi: "TR" 749 | (make element gi: "TH" 750 | attributes: '(("ALIGN" "LEFT") 751 | ("VALIGN" "TOP") 752 | ("COLSPAN" "3")) 753 | (make element gi: "B" 754 | (literal (gentext-element-name 755 | (gi (current-node))))))) 756 | (process-children))))) 757 | 758 | ;;subtitle sizing 759 | (element subtitle 760 | (make element gi: "H4" 761 | attributes: (list (list "CLASS" (gi))) 762 | (process-children-trim)))) 763 | 764 | ;;======================== 765 | ;;Title Pages for Articles 766 | ;;======================== 767 | 768 | ;;Should Articles have a TOC? 769 | (define %generate-article-toc% 770 | #t) 771 | 772 | ;;Which elements should appear 773 | ;;on title page? 774 | (define (article-titlepage-recto-elements) 775 | (list (normalize "title") 776 | (normalize "subtitle") 777 | (normalize "authorgroup") 778 | (normalize "copyright") 779 | (normalize "revhistory") 780 | (normalize "legalnotice") 781 | (normalize "abstract"))) 782 | 783 | ;;How should elements on title page look? 784 | (mode article-titlepage-recto-mode 785 | 786 | (element authorgroup 787 | (make sequence 788 | (literal "by:") 789 | (process-children))) 790 | 791 | ;;Author name is too big - change it! 792 | (element author 793 | (let ((author-name (author-string)) 794 | (author-affil (select-elements (children (current-node)) 795 | (normalize "affiliation")))) 796 | (make sequence 797 | (make element gi: "H4" 798 | attributes: (list (list "CLASS" (gi))) 799 | (make element gi: "A" 800 | attributes: (list (list "NAME" (element-id))) 801 | (literal author-name))) 802 | (process-node-list author-affil)))) 803 | 804 | ;;Address? 805 | (element address 806 | (make sequence 807 | (make element gi: "DIV" 808 | attributes: (list (list "CLASS" (gi))) 809 | (process-children)))) 810 | 811 | ;;Get rid of spam-producing "mailto" links 812 | ;;and get rid of email indentation 813 | (element email 814 | (make sequence 815 | (make element gi: "DIV" 816 | attributes: (list (list "CLASS" (gi))) 817 | (process-children)))) 818 | 819 | ;;Point Abstract to custom table function 820 | ;;(See $dcm-abstract-object$ below. For default 821 | ;;use $semiformal-object$ 822 | (element abstract 823 | (make element gi: "DIV" 824 | ($dcm-abstract-object$))) 825 | 826 | (element (abstract title) (empty-sosofo)) 827 | 828 | ;;revhistory table is MUCH too wide! 829 | (element revhistory 830 | (make element gi: "DIV" 831 | attributes: (list (list "CLASS" (gi))) 832 | (make element gi: "TABLE" 833 | attributes: (list 834 | (list "WIDTH" "35%") 835 | (list "BORDER" "0")) 836 | (make sequence 837 | (make element gi: "TR" 838 | (make element gi: "TH" 839 | attributes: '(("ALIGN" "LEFT") 840 | ("VALIGN" "TOP") 841 | ("COLSPAN" "3")) 842 | (make element gi: "B" 843 | (literal (gentext-element-name 844 | (gi (current-node))))))) 845 | (process-children))))) 846 | 847 | ;;subtitle sizing 848 | (element subtitle 849 | (make element gi: "H4" 850 | attributes: (list (list "CLASS" (gi))) 851 | (process-children-trim)))) 852 | 853 | ;;================= 854 | ;; INLINES 855 | ;;================= 856 | 857 | ;Define my own series of fonts for various elements 858 | (element application ($mono-seq$)) 859 | (element command ($bold-seq$)) 860 | (element filename ($mono-seq$)) 861 | (element function ($mono-seq$)) 862 | (element guibutton ($bold-seq$)) 863 | (element guiicon ($bold-seq$)) 864 | (element guilabel ($bold-mono-seq$)) 865 | (element guimenu ($bold-seq$)) 866 | (element guimenuitem ($bold-seq$)) 867 | (element guisubmenu ($bold-seq$)) 868 | (element hardware ($bold-mono-seq$)) 869 | (element keycap ($bold-seq$)) 870 | (element literal ($mono-seq$)) 871 | (element parameter ($italic-mono-seq$)) 872 | (element prompt ($mono-seq$)) 873 | (element symbol ($charseq$)) 874 | (element emphasis ($italic-seq$)) 875 | 876 | 877 | ;;==================== 878 | ;; General Formatting 879 | ;;==================== 880 | 881 | ;;Formal Paras are ugly by default! 882 | ;;Make the title run in - otherwise 883 | ;;you should use a sect! 884 | 885 | (element formalpara 886 | (make element gi: "DIV" 887 | attributes: (list 888 | (list "CLASS" (gi))) 889 | (make element gi: "P" 890 | (process-children)))) 891 | 892 | ;(element (formalpara title) ($lowtitle$ 5)) 893 | (element (formalpara title) 894 | (make element gi: "B" 895 | ($runinhead$))) 896 | 897 | ;;make captions come after objects in the list 898 | (define ($object-titles-after$) 899 | (list (normalize "figure"))) 900 | 901 | 902 | ;;Literal Elements 903 | 904 | ;;Indent Literal layouts? 905 | (define %indent-literallayout-lines% 906 | #f) 907 | 908 | ;;Indent Programlistings? 909 | (define %indent-programlisting-lines% 910 | #f) 911 | 912 | ;;Number lines in Programlistings? 913 | (define %number-programlisting-lines% 914 | #f) 915 | 916 | ;;Should verbatim items be 'shaded' with a table? 917 | (define %shade-verbatim% 918 | #t) 919 | 920 | ;;Define shade-verbatim attributes 921 | (define ($shade-verbatim-attr$) 922 | (list 923 | (list "BORDER" "0") 924 | (list "BGCOLOR" "#E0E0E0") 925 | (list "WIDTH" ($table-width$)))) 926 | 927 | ;;=================== 928 | ;; Entities 929 | ;;=================== 930 | 931 | ;;Netscape doesn't handle trademark 932 | ;;entity right at all!! Get rid of it. 933 | 934 | (element trademark 935 | (make sequence 936 | (process-children) 937 | (make element gi: "sup" 938 | (literal "TM")))) 939 | 940 | 941 | 942 | ;;=================== 943 | ;; New Definitions 944 | ;;================== 945 | 946 | (define ($dcm-abstract-object$) 947 | (make element gi: "TABLE" 948 | attributes: '(("BORDER" "0") 949 | ("BGCOLOR" "#E0E0E0") 950 | ("WIDTH" "50%") 951 | ("CELLSPACING" "0") 952 | ("CELLPADDING" "0") 953 | ("ALIGN" "CENTER")) 954 | (make element gi: "TR" 955 | (make element gi: "TD" 956 | attributes: '(("VALIGN" "TOP")) 957 | (make element gi: "B" 958 | (literal "Abstract")))) 959 | (make element gi: "TR" 960 | (make element gi: "TD" 961 | attributes: '(("VALIGN" "TOP")) 962 | (process-children))))) 963 | 964 | ;;Redefine Titlepage Separator on Articles 965 | 966 | (define (article-titlepage-separator side) 967 | (make empty-element gi: "HR" 968 | attributes: '(("WIDTH" "75%") 969 | ("ALIGN" "CENTER") 970 | ("COLOR" "#000000") 971 | ("SIZE" "1")))) 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | -------------------------------------------------------------------------------- /src/rfc822.c: -------------------------------------------------------------------------------- 1 | /* rfc822.c 2 | * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf 3 | * 4 | * This file is part of GEAM. 5 | * 6 | * GEAM is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * GEAM is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | 22 | 23 | /* FIXME: According to RFC822 binary 0 are allowed at many places. We 24 | * do not handle this correct especially in the field parsing code. It 25 | * should be easy to fix and the API provides a interfcaes which returns 26 | * the length but in addition makes sure that returned strings are always 27 | * ended by a \0 28 | */ 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "xmalloc.h" 46 | #include "stringhelp.h" 47 | #include "rfc822.h" 48 | 49 | enum token_type { 50 | tSPACE, 51 | tATOM, 52 | tQUOTED, 53 | tDOMAINLIT, 54 | tSPECIAL 55 | }; 56 | 57 | /* For now we directly use our TOKEN as the parse context */ 58 | typedef struct rfc822_parse_context *TOKEN; 59 | struct rfc822_parse_context { 60 | TOKEN next; 61 | enum token_type type; 62 | int cont; 63 | /*TOKEN owner_pantry;*/ 64 | char data[1]; 65 | }; 66 | 67 | struct hdr_line { 68 | struct hdr_line *next; 69 | int cont; /* this is a continuation of the previous line */ 70 | char line[1]; 71 | }; 72 | 73 | typedef struct hdr_line *HDR_LINE; 74 | 75 | struct body_line { 76 | struct body_line *next; 77 | size_t length; 78 | char data[1]; 79 | }; 80 | typedef struct body_line *BODY_LINE; 81 | 82 | 83 | struct rfc822_data { 84 | int (*callback)(void*, enum rfc822_events, RFC822 ); 85 | void *callback_value; 86 | int callback_error; 87 | int in_body; 88 | HDR_LINE hdr_lines; 89 | HDR_LINE *hdr_lines_head; 90 | BODY_LINE bdy_lines; 91 | BODY_LINE *bdy_lines_head; 92 | }; 93 | 94 | static int insert_header( RFC822 msg, char *line, size_t length ); 95 | static int insert_body( RFC822 msg, char *line, size_t length ); 96 | static int transition_to_body( RFC822 msg ); 97 | static HDR_LINE find_header( RFC822 msg, const char *name, 98 | int which, HDR_LINE *rprev ); 99 | 100 | 101 | char * 102 | rfc822_timestamp(char *buffer, size_t buflen ) 103 | { 104 | time_t now; 105 | struct tm *t; 106 | int u_yday, u_hour, u_min, zone, zone_s, zone_h, zone_m; 107 | char *p; 108 | 109 | time( &now ); 110 | t = gmtime( &now ); 111 | u_yday = t->tm_yday; 112 | u_hour = t->tm_hour; 113 | u_min = t->tm_min; 114 | 115 | t = localtime( &now ); 116 | 117 | zone = (t->tm_hour - u_hour) * 60 + (t->tm_min - u_min); 118 | if( t->tm_yday == u_yday ) 119 | ; /* same day */ 120 | else if( t->tm_yday == u_yday+1 ) 121 | zone += 1440; /* one ahead */ 122 | else 123 | zone -= 1440; 124 | 125 | if( zone < 0 ) { 126 | zone_s = '-'; 127 | zone = -zone; 128 | } 129 | else 130 | zone_s = '+'; 131 | 132 | zone_h = zone / 60; 133 | zone_m = (zone - zone_h*60); 134 | 135 | 136 | if( buffer ) { 137 | p = buffer; 138 | } 139 | else { 140 | buflen = 50; 141 | p = xmalloc( buflen ); 142 | } 143 | snprintf(p, buflen, "%.3s, %d %.3s %4d %02d:%02d:%02d %c%02d%02d", 144 | "SunMonTueWedThuFriSat" + (t->tm_wday%7)*3, 145 | t->tm_mday, 146 | "JanFebMarAprMayJunJulAufSepOctNovDez" + (t->tm_mon%12)*3, 147 | t->tm_year + 1900, 148 | t->tm_hour, t->tm_min, t->tm_sec, zone_s, zone_h, zone_m ); 149 | return p; 150 | } 151 | 152 | 153 | 154 | static int 155 | do_callback( RFC822 msg, enum rfc822_events event ) 156 | { 157 | int rc; 158 | 159 | if( !msg->callback || msg->callback_error ) 160 | return 0; 161 | rc = msg->callback( msg->callback_value, event, msg ); 162 | if( rc ) 163 | msg->callback_error = rc; 164 | return rc; 165 | } 166 | 167 | static void 168 | release_handle_data( RFC822 msg ) 169 | { 170 | HDR_LINE hdr, hdr2; 171 | BODY_LINE bdy, bdy2; 172 | 173 | for(hdr = msg->hdr_lines; hdr; hdr = hdr2 ) { 174 | hdr2 = hdr->next; 175 | free(hdr); 176 | } 177 | msg->hdr_lines = NULL; 178 | msg->hdr_lines_head = NULL; 179 | 180 | for(bdy = msg->bdy_lines; bdy; bdy = bdy2 ) { 181 | bdy2 = bdy->next; 182 | free(bdy); 183 | } 184 | msg->bdy_lines = NULL; 185 | msg->bdy_lines_head = NULL; 186 | } 187 | 188 | RFC822 189 | rfc822_open( int (*cb)( void *, enum rfc822_events, RFC822 ), void *cb_value ) 190 | { 191 | RFC822 msg = calloc(1, sizeof *msg ); 192 | if( msg ) { 193 | msg->hdr_lines_head = &msg->hdr_lines; 194 | msg->bdy_lines_head = &msg->bdy_lines; 195 | msg->callback = cb; 196 | msg->callback_value = cb_value; 197 | if( do_callback( msg, RFC822EVT_OPEN ) ) { 198 | release_handle_data( msg ); 199 | free(msg); 200 | msg = NULL; 201 | } 202 | } 203 | return msg; 204 | } 205 | 206 | 207 | 208 | void 209 | rfc822_cancel( RFC822 msg ) 210 | { 211 | do_callback( msg, RFC822EVT_CANCEL ); 212 | release_handle_data( msg ); 213 | free(msg); 214 | } 215 | 216 | void 217 | rfc822_close( RFC822 msg ) 218 | { 219 | do_callback( msg, RFC822EVT_CLOSE ); 220 | release_handle_data( msg ); 221 | free(msg); 222 | } 223 | 224 | 225 | int 226 | rfc822_insert( RFC822 msg, char *line, size_t length ) 227 | { 228 | return msg->in_body? insert_body( msg, line, length ) 229 | : insert_header( msg, line, length ); 230 | } 231 | 232 | 233 | int 234 | rfc822_finish( RFC822 msg ) 235 | { 236 | return do_callback( msg, RFC822EVT_FINISH ); 237 | } 238 | 239 | 240 | /**************** 241 | * Note: For program supplied (and therefore syntactically correct) 242 | * header lines, rfc822_add_header() may be used. 243 | */ 244 | int 245 | insert_header( RFC822 msg, char *line, size_t length ) 246 | { 247 | HDR_LINE hdr; 248 | 249 | if( !length ) { 250 | msg->in_body = 1; 251 | return transition_to_body(msg); 252 | } 253 | trim_trailing_spaces(line); 254 | /* Hmmm: should we check for invalid header data here? */ 255 | 256 | hdr = malloc( sizeof( *hdr ) + strlen(line) ); 257 | if( !hdr ) 258 | return RFC822ERR_NOMEM; 259 | hdr->next = NULL; 260 | hdr->cont = (*line == ' ' || *line == '\t'); 261 | strcpy(hdr->line, line ); 262 | 263 | *msg->hdr_lines_head = hdr; 264 | msg->hdr_lines_head = &hdr->next; 265 | 266 | /* lets help the caller to prevent mail loops 267 | * It is okay to use length here, also this value 268 | * not correct due to the space trimming */ 269 | if( length >= 9 && !memicmp(line, "Received:", 9) ) 270 | do_callback( msg, RFC822EVT_RCVD_SEEN ); 271 | return 0; 272 | } 273 | 274 | 275 | /**************** 276 | * Note: We handle the body transparent to allow binary zeroes in it. 277 | */ 278 | int 279 | insert_body( RFC822 msg, char *line, size_t length ) 280 | { 281 | BODY_LINE bdy = malloc( sizeof( *bdy ) + length ); 282 | if( !bdy ) 283 | return RFC822ERR_NOMEM; 284 | bdy->next = NULL; 285 | bdy->length = length; 286 | memcpy(bdy->data, line, length); 287 | bdy->data[length] = 0; 288 | 289 | *msg->bdy_lines_head = bdy; 290 | msg->bdy_lines_head = &bdy->next; 291 | return 0; 292 | } 293 | 294 | 295 | /**************** 296 | * We have read in all header lines and are about to receive the body 297 | * part. The delimiter line has already been processed. 298 | */ 299 | static int 300 | transition_to_body( RFC822 msg ) 301 | { 302 | return do_callback( msg, RFC822EVT_T2BODY ); 303 | } 304 | 305 | 306 | /**************** 307 | * Add header lines to the existing ones. 308 | * Such a line may include LFs which are used to split the line 309 | * int several fields. This must be a valid header line. 310 | */ 311 | int 312 | rfc822_add_header( RFC822 msg, const char *line ) 313 | { 314 | HDR_LINE hdr; 315 | const char *lf; 316 | size_t n; 317 | int do_cb; 318 | 319 | /* send the notification only if we have not processed all header lines */ 320 | do_cb = !msg->in_body && strlen(line) >= 9 && !memicmp(line, "Received:", 9); 321 | 322 | do { 323 | lf = strchr( line, '\n' ); 324 | n = lf? ( lf - line ) : strlen( line ); 325 | hdr = malloc( sizeof( *hdr ) + n ); 326 | if( !hdr ) 327 | return RFC822ERR_NOMEM; 328 | hdr->next = NULL; 329 | hdr->cont = (*line == ' ' || *line == '\t'); 330 | memcpy(hdr->line, line, n ); 331 | hdr->line[n] = 0; 332 | 333 | *msg->hdr_lines_head = hdr; 334 | msg->hdr_lines_head = &hdr->next; 335 | } while( lf && *(line=lf+1) ); 336 | 337 | if( do_cb ) 338 | do_callback( msg, RFC822EVT_RCVD_SEEN ); 339 | 340 | return 0; 341 | } 342 | 343 | int 344 | rfc822_add_headerf( RFC822 msg, const char *fmt, ... ) 345 | { 346 | char *buffer = NULL; 347 | int rc; 348 | va_list arg_ptr; 349 | 350 | va_start( arg_ptr, fmt ); 351 | vasprintf( &buffer, fmt, arg_ptr ); 352 | va_end( arg_ptr ); 353 | rc = rfc822_add_header( msg, buffer ); 354 | free(buffer); 355 | return rc; 356 | } 357 | 358 | /**************** 359 | * Rename header: 360 | * 361 | * which gives the mode: 362 | * 0 := Do it for all the fields. 363 | * -1 := Take the last occurence 364 | * n := Take the n-th one. 365 | */ 366 | int 367 | rfc822_rename_header( RFC822 msg, const char *oldname, 368 | const char *newname, int which ) 369 | { 370 | HDR_LINE h, hprev; 371 | int seq = which; 372 | size_t oldlen, newlen, n; 373 | int glob = 0; 374 | char *p0, *pc; 375 | 376 | newlen = strlen(newname); 377 | oldlen = strlen(oldname); 378 | if( oldlen && oldname[oldlen-1] == '*' ) { 379 | oldlen--; 380 | glob = 1; 381 | } 382 | 383 | hprev = NULL; /* start with the first one */ 384 | seq=which?which:1; 385 | for(;;) { 386 | h = find_header( msg, oldname, seq, &hprev ); 387 | if( !h ) 388 | return 0; /* no such field */ 389 | p0 = h->line; 390 | pc = p0 + oldlen; 391 | assert( glob || p0[oldlen]==':' ); 392 | 393 | n = pc - p0; /* what we have to replace by newlen */ 394 | if( newlen == n ) 395 | memcpy( p0, newname, newlen ); 396 | else if( newlen < n ) { 397 | memcpy( p0, newname, newlen ); 398 | memmove( p0+newlen, pc, strlen(pc)+1 ); 399 | } 400 | else { 401 | HDR_LINE hnew = malloc( sizeof( *hnew ) 402 | + strlen(p0) - oldlen + newlen ); 403 | if( !hnew ) 404 | return RFC822ERR_NOMEM; 405 | hnew->cont = 0; 406 | memcpy(hnew->line, newname, newlen ); 407 | strcpy(hnew->line+newlen, pc ); 408 | 409 | hnew->next = h->next; 410 | if( hprev ) 411 | hprev->next = hnew; 412 | else 413 | msg->hdr_lines = hnew; 414 | if( msg->hdr_lines_head == &h->next ) 415 | msg->hdr_lines_head = &hnew->next; 416 | free(h); 417 | h = hnew; 418 | } 419 | 420 | if( which || !h->next ) 421 | return 0; /* ready (we only want to rename one field) */ 422 | hprev = h->next; /* so that find_header start with the next one */ 423 | } 424 | } 425 | 426 | 427 | /**************** 428 | * Remove header: 429 | * 430 | * which gives the mode: 431 | * 0 := Do it for all the fields. 432 | * -1 := Take the last occurence 433 | * n := Take the n-th one. 434 | */ 435 | int 436 | rfc822_remove_header( RFC822 msg, const char *name, int which ) 437 | { 438 | HDR_LINE h, hnext, hprev; 439 | int seq = which; 440 | size_t len; 441 | int glob = 0; 442 | 443 | len = strlen(name); 444 | if( len && name[len-1] == '*' ) { 445 | len--; 446 | glob = 1; 447 | } 448 | 449 | hprev = NULL; /* start with the first one */ 450 | seq=which?which:1; 451 | for(;;) { 452 | h = find_header( msg, name, seq, &hprev ); 453 | if( !h ) 454 | return 0; /* no such field */ 455 | 456 | while( h->next && h->next->cont ) { 457 | hnext = h->next; 458 | free(h); 459 | h = hnext; 460 | } 461 | 462 | hnext = h->next; 463 | if( hprev ) { 464 | hprev->next = hnext; 465 | if( msg->hdr_lines_head == &h->next ) 466 | msg->hdr_lines_head = &hprev->next; 467 | } 468 | else { 469 | msg->hdr_lines = hnext; 470 | if( msg->hdr_lines_head == &h->next ) 471 | msg->hdr_lines_head = &msg->hdr_lines; 472 | } 473 | 474 | free(h); 475 | h = hnext; 476 | 477 | if( which || !h ) 478 | return 0; /* ready (we only want to remove one field) */ 479 | hprev = h; 480 | } 481 | } 482 | 483 | 484 | /**************** 485 | * Get a copy of a headerline, the line is returned as one long string with 486 | * LF to separate the continuation line. Caller must free thre return buffer. 487 | * which may be used to enumerate over all lines. Wildcards are allowed. 488 | * 489 | * which gives the mode: 490 | * -1 := Take the last occurence 491 | * n := Take the n-th one. 492 | */ 493 | char * 494 | rfc822_get_header( RFC822 msg, const char *name, int which ) 495 | { 496 | HDR_LINE h, h2; 497 | char *buf, *p; 498 | size_t n; 499 | 500 | h = find_header( msg, name, which, NULL ); 501 | if( !h ) 502 | return 0; /* no such field */ 503 | 504 | n = strlen(h->line)+1; 505 | for( h2 = h->next; h2 && h2->cont; h2 = h2->next ) 506 | n += strlen(h2->line)+1; 507 | 508 | buf = p = xmalloc( n ); 509 | p = stpcpy(p, h->line); 510 | *p++ = '\n'; 511 | for( h2 = h->next; h2 && h2->cont; h2 = h2->next ) { 512 | p = stpcpy(p, h2->line); 513 | *p++ = '\n'; 514 | } 515 | p[-1] = 0; 516 | return buf; 517 | } 518 | 519 | 520 | /**************** 521 | * Enumerate all header. Caller has to provide the address of a pointer 522 | * which has to be initialzed to NULL, the caller should then never change this 523 | * pointer until he has closed the enumeration by passing again the address 524 | * of the pointer but with msg set to NULL. 525 | * The function returns pointers to all the header lines or NULL when 526 | * all lines have been enumerated. 527 | */ 528 | const char* 529 | rfc822_enum_header_lines( RFC822 msg, void **context ) 530 | { 531 | struct hdr_line *l; 532 | 533 | if( !msg ) /*close*/ 534 | return NULL; /* this is quite easy in our implementation */ 535 | 536 | if( *context == msg ) 537 | return NULL; 538 | 539 | l = *context? (struct hdr_line*)*context : msg->hdr_lines; 540 | 541 | if( l ) { 542 | *context = l->next? (void*)(l->next) : (void*)msg; 543 | return l->line; 544 | } 545 | *context = msg; /* mark end of list */ 546 | return NULL; 547 | } 548 | 549 | 550 | /**************** 551 | * Enumerate the body. Caller has to provide the address of a pointer 552 | * which has to be initialzed to NULL, the caller should then never change this 553 | * pointer until he has closed the enumeration by passing again the address 554 | * of the pointer but with msg set to NULL. 555 | * The function returns pointers to all the body lines or NULL when 556 | * all lines have been enumerated. 557 | */ 558 | const char* 559 | rfc822_enum_body_lines( RFC822 msg, void **context, size_t *nbytes ) 560 | { 561 | struct body_line *l; 562 | 563 | if( !msg ) /*close*/ 564 | return NULL; /* this is quite easy in our implementation */ 565 | 566 | if( *context == msg ) 567 | return NULL; 568 | 569 | l = *context? (struct body_line*)*context : msg->bdy_lines; 570 | 571 | if( l ) { 572 | *context = l->next? (void*)(l->next) : (void*)msg; 573 | if( nbytes ) 574 | *nbytes = l->length; 575 | return l->data; 576 | } 577 | *context = msg; /* mark end of list */ 578 | return NULL; 579 | } 580 | 581 | 582 | /**************** 583 | * Find a header field. If the Name does end in an asterisk this is meant 584 | * to be a wildcard. 585 | * 586 | * which -1 : Retrieve the last field 587 | * >0 : Retrieve the n-th field 588 | * rprev may be used to return the predecessor of the returned field; 589 | * which may be NULL for the very first one. It has to be initialzed 590 | * to either NULL in which case the search start at the first header line, 591 | * or it may point to a headerline, where the search should start 592 | */ 593 | static HDR_LINE 594 | find_header( RFC822 msg, const char *name, int which, HDR_LINE *rprev ) 595 | { 596 | HDR_LINE hdr, prev=NULL, mark=NULL; 597 | char *p; 598 | size_t namelen, n; 599 | int found = 0; 600 | int glob = 0; 601 | 602 | namelen = strlen(name); 603 | if( namelen && name[namelen-1] =='*' ) { 604 | namelen--; 605 | glob = 1; 606 | } 607 | 608 | hdr = msg->hdr_lines; 609 | if( rprev && *rprev ) { 610 | /* spool forward to the requested starting place. 611 | * we cannot simply set this as we have to return 612 | * the previous list element too */ 613 | for(; hdr && hdr != *rprev; prev = hdr, hdr = hdr->next ) 614 | ; 615 | } 616 | 617 | for(; hdr; prev = hdr, hdr = hdr->next ) { 618 | if( hdr->cont ) 619 | continue; 620 | if( !(p = strchr( hdr->line, ':' )) ) 621 | continue; /* invalid header, just skip it. */ 622 | n = p - hdr->line; 623 | if( !n ) 624 | continue; /* invalid name */ 625 | if( (glob? (namelen <= n) : (namelen == n)) 626 | && !memicmp( hdr->line, name, namelen ) ) { 627 | found++; 628 | if( which == -1 ) 629 | mark = hdr; 630 | else if( found == which ) { 631 | if( rprev ) 632 | *rprev = prev; 633 | return hdr; 634 | } 635 | } 636 | } 637 | if( mark && rprev ) 638 | *rprev = prev; 639 | return mark; 640 | } 641 | 642 | 643 | 644 | static const char * 645 | skip_ws( const char *s ) 646 | { 647 | while( *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' ) 648 | s++; 649 | return s; 650 | } 651 | 652 | 653 | static void 654 | release_token_list( TOKEN t ) 655 | { 656 | while( t ) { 657 | TOKEN t2 = t->next; 658 | /* fixme: If we have owner_pantry, put the token back to 659 | * this pantry so that it can be reused later */ 660 | free( t ); 661 | t = t2; 662 | } 663 | } 664 | 665 | 666 | static TOKEN 667 | new_token( enum token_type type, const char *buf, size_t length ) 668 | { 669 | TOKEN t; 670 | 671 | /* fixme: look through our pantries to find a suitable 672 | * token for reuse */ 673 | t = xmalloc( sizeof *t + length ); 674 | t->next = NULL; 675 | t->type = type; 676 | t->data[0] = 0; 677 | if( buf ) { 678 | memcpy(t->data, buf, length ), 679 | t->data[length] = 0; /* make sure it is a C string */ 680 | } 681 | else 682 | t->data[0] = 0; 683 | return t; 684 | } 685 | 686 | static TOKEN 687 | append_to_token( TOKEN old, const char *buf, size_t length ) 688 | { 689 | size_t n = strlen(old->data); 690 | TOKEN t; 691 | 692 | t = xmalloc( sizeof *t + n + length ); 693 | t->next = old->next; 694 | t->type = old->type; 695 | memcpy( t->data, old->data, n ); 696 | memcpy( t->data+n, buf, length ); 697 | t->data[n+length] = 0; 698 | old->next = NULL; 699 | release_token_list(old); 700 | return t; 701 | } 702 | 703 | 704 | 705 | /**************** 706 | * Parse a field into tokens as defined by rfc822. 707 | */ 708 | static TOKEN 709 | parse_field( HDR_LINE hdr ) 710 | { 711 | static const char specials[] = "<>@.,;:\\[]\"()"; 712 | static const char specials2[]= "<>@.,;:"; 713 | static const char tspecials[] = "/?=<>@,;:\\[]\"()"; 714 | static const char tspecials2[]= "/?=<>@.,;:"; 715 | static struct { const char *name; int namelen; } tspecial_header[] = { 716 | { "Content-Type", 12 }, 717 | { "Content-Transfer-Encoding", 25 }, 718 | { NULL, 0 } 719 | }; 720 | const char *delimiters; 721 | const char *delimiters2; 722 | const char *line, *s, *s2; 723 | size_t n; 724 | int i, invalid = 0; 725 | TOKEN t, tok, *tok_head; 726 | 727 | if( !hdr ) 728 | return NULL; 729 | 730 | tok = NULL; 731 | tok_head = &tok; 732 | 733 | line = hdr->line; 734 | if( !(s = strchr( line, ':' )) ) 735 | return NULL; /* oops */ 736 | 737 | n = s - line; 738 | if( !n ) 739 | return NULL; /* oops: invalid name */ 740 | delimiters = specials; 741 | delimiters2 = specials2; 742 | for(i=0; tspecial_header[i].name; i++ ) { 743 | if( n == tspecial_header[i].namelen 744 | && !memicmp( line, tspecial_header[i].name, n ) ) 745 | { 746 | delimiters = tspecials; 747 | delimiters2 = tspecials2; 748 | break; 749 | } 750 | } 751 | 752 | /* Add this point we could store the fieldname in the parsing structure. 753 | * If we decide to do this, we should lowercase the name except for the 754 | * first character which should be uppercased. This way we don't 755 | * need to apply the case insensitive compare in the future 756 | */ 757 | 758 | s++; /* move over the colon */ 759 | for(;;) { 760 | if( !*s ) { 761 | if( !hdr->next || !hdr->next->cont ) 762 | break; 763 | hdr = hdr->next; 764 | s = hdr->line; 765 | } 766 | 767 | if( *s == '(' ) { 768 | int level = 1; 769 | int in_quote = 0; 770 | 771 | invalid = 0; 772 | for(s++ ; ; s++ ) { 773 | if( !*s ) { 774 | if( !hdr->next || !hdr->next->cont ) 775 | break; 776 | hdr = hdr->next; 777 | s = hdr->line; 778 | } 779 | 780 | if( in_quote ) { 781 | if( *s == '\"' ) 782 | in_quote = 0; 783 | else if( *s == '\\' && s[1] ) /* what about continuation?*/ 784 | s++; 785 | } 786 | else if( *s == ')' ) { 787 | if( !--level ) 788 | break; 789 | } 790 | else if( *s == '(' ) 791 | level++; 792 | else if( *s == '\"' ) 793 | in_quote = 1; 794 | } 795 | if( !*s ) 796 | ;/* actually this is an error, but we don't care about it */ 797 | else 798 | s++; 799 | } 800 | else if( *s == '\"' || *s == '[' ) { 801 | /* We do not check for non-allowed nesting of domainliterals */ 802 | int term = *s == '\"' ? '\"' : ']'; 803 | invalid = 0; 804 | s++; 805 | t = NULL; 806 | 807 | for(;;) { 808 | for( s2 = s; *s2; s2++ ) { 809 | if( *s2 == term ) 810 | break; 811 | else if( *s2 == '\\' && s2[1] ) /* what about continuation?*/ 812 | s2++; 813 | } 814 | 815 | t = t ? append_to_token( t, s, s2-s) 816 | : new_token( term == '\"'? tQUOTED 817 | : tDOMAINLIT, s, s2-s); 818 | 819 | if( *s2 || !hdr->next || !hdr->next->cont ) 820 | break; 821 | hdr = hdr->next; 822 | s = hdr->line; 823 | } 824 | *tok_head = t; 825 | tok_head = &t->next; 826 | s = s2; 827 | if( *s ) 828 | s++; /* skip the delimiter */ 829 | } 830 | else if( (s2 = strchr( delimiters2, *s )) ) { 831 | /* special characters which are not handled above */ 832 | invalid = 0; 833 | t = new_token( tSPECIAL, s, 1 ); 834 | *tok_head = t; 835 | tok_head = &t->next; 836 | s++; 837 | } 838 | else if( *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' ) { 839 | invalid = 0; 840 | s = skip_ws(s+1); 841 | } 842 | else if( *s > 0x20 && !(*s & 128) ) { /* atom */ 843 | invalid = 0; 844 | for( s2 = s+1; *s2 > 0x20 845 | && !(*s2 & 128 ) 846 | && !strchr( delimiters, *s2 ); s2++ ) 847 | ; 848 | t = new_token( tATOM, s, s2-s ); 849 | *tok_head = t; 850 | tok_head = &t->next; 851 | s = s2; 852 | } 853 | else { /* invalid character */ 854 | if( !invalid ) { /* for parsing we assume only one space */ 855 | t = new_token( tSPACE, NULL, 0); 856 | *tok_head = t; 857 | tok_head = &t->next; 858 | invalid = 1; 859 | } 860 | s++; 861 | } 862 | } 863 | return tok; 864 | } 865 | 866 | 867 | 868 | 869 | /**************** 870 | * Find and parse a header field. 871 | * which indicates what to do if there are multiple instance of the same 872 | * field (like "Received"); the followinf value are defined: 873 | * -1 := Take the last occurence 874 | * 0 := Reserved 875 | * n := Take the n-th one. 876 | * Returns a handle for further operations on the parse context of the field 877 | * or NULL if the field was not found. 878 | */ 879 | RFC822_PARSE_CTX 880 | rfc822_parse_header( RFC822 msg, const char *name, int which ) 881 | { 882 | HDR_LINE hdr; 883 | 884 | if( !which ) 885 | return NULL; 886 | 887 | hdr = find_header( msg, name, which, NULL ); 888 | if( !hdr ) 889 | return NULL; 890 | return parse_field( hdr ); 891 | } 892 | 893 | void 894 | rfc822_release_parse_ctx( RFC822_PARSE_CTX ctx ) 895 | { 896 | if( ctx ) 897 | release_token_list( ctx ); 898 | } 899 | 900 | 901 | 902 | /**************** 903 | * Check whether t points to a parameter. 904 | * A parameter starts with a semicolon and it is assumed that t 905 | * points to exactly this one. 906 | */ 907 | static int 908 | is_parameter( TOKEN t ) 909 | { 910 | t = t->next; 911 | if( !t || t->type != tATOM ) 912 | return 0; 913 | t = t->next; 914 | if( !t || !(t->type == tSPECIAL && t->data[0]=='=') ) 915 | return 0; 916 | t = t->next; 917 | if( !t ) 918 | return 1; /* we assume that an non existing valie is an empty one */ 919 | return t->type == tQUOTED || t->type == tATOM; 920 | } 921 | 922 | /**************** 923 | * Some header (Content-type) have a special syntax where attribute=value 924 | * pairs are used after a leading semicolon. the parse_field code 925 | * knows about these fields and changes the parsing to the one defined 926 | * in RFC2045. 927 | * Returns a pointer to the value which is valid as long as the 928 | * parse context is valid; NULL is returned in case that attr is not 929 | * defined in the header, a missing value is reppresented by an empty string. 930 | */ 931 | const char * 932 | rfc822_query_parameter( RFC822_PARSE_CTX ctx, const char *attr ) 933 | { 934 | TOKEN t, a; 935 | 936 | for( t = ctx; t ; t = t->next ) { 937 | /* skip to the next semicolon */ 938 | for( ; t && !(t->type == tSPECIAL && t->data[0]==';'); t = t->next ) 939 | ; 940 | if( !t ) 941 | return NULL; 942 | if( is_parameter( t ) ) { /* look closer */ 943 | a = t->next; /* we know that this is an atom */ 944 | if( !stricmp( a->data, attr ) ) { /* found */ 945 | t = a->next->next; 946 | /* either t is now an atom, a quoted string or NULL in 947 | * which case we retrun an empty string */ 948 | return t? t->data : ""; 949 | } 950 | } 951 | } 952 | return NULL; 953 | } 954 | 955 | /**************** 956 | * This function may be used for the Content-Type header to figure out 957 | * the media type and subtype. 958 | * Returns: a pointer to the media type and if subtype is not NULL, 959 | * a pointer to the subtype. 960 | */ 961 | const char * 962 | rfc822_query_media_type( RFC822_PARSE_CTX ctx, const char **subtype ) 963 | { 964 | TOKEN t = ctx; 965 | const char *type; 966 | 967 | if( t->type != tATOM ) 968 | return NULL; 969 | type = t->data; 970 | t = t->next; 971 | if( !t || t->type != tSPECIAL || t->data[0] != '/' ) 972 | return NULL; 973 | t = t->next; 974 | if( !t || t->type != tATOM ) 975 | return NULL; 976 | if( subtype ) 977 | *subtype = t->data; 978 | return type; 979 | } 980 | 981 | 982 | 983 | 984 | 985 | #ifdef TESTING 986 | 987 | static void 988 | dump_token_list( TOKEN t ) 989 | { 990 | for( ; t; t = t->next ) { 991 | switch( t->type ) { 992 | case tSPACE: printf(" space\n"); break; 993 | case tATOM: printf(" atom `%s'\n", t->data ); break; 994 | case tQUOTED: printf(" quoted `%s'\n", t->data ); break; 995 | case tDOMAINLIT: printf(" domainlit `%s'\n", t->data ); break; 996 | case tSPECIAL: printf(" special `%s'\n", t->data ); break; 997 | } 998 | } 999 | } 1000 | 1001 | static void 1002 | show_param( RFC822_PARSE_CTX ctx, const char *name ) 1003 | { 1004 | const char *s; 1005 | 1006 | if( !ctx ) 1007 | return; 1008 | s = rfc822_query_parameter( ctx, name ); 1009 | if( !s ) 1010 | printf("%s: [not found]\n", name ); 1011 | else 1012 | printf("%s: `%s'\n", name, s ); 1013 | } 1014 | 1015 | int 1016 | main( int argc, char **argv ) 1017 | { 1018 | char line[5000]; 1019 | char *name, *newname=NULL; 1020 | size_t length; 1021 | RFC822 msg; 1022 | RFC822_PARSE_CTX ctx; 1023 | const char *s1, *s2; 1024 | 1025 | if( argc > 2 ) { 1026 | newname = argv[2]; 1027 | name = argv[1]; 1028 | } 1029 | else if( argc > 1 ) 1030 | name = argv[1]; 1031 | else 1032 | name = "Content-Type"; 1033 | 1034 | 1035 | msg = rfc822_open( NULL, NULL ); 1036 | if( !msg ) 1037 | abort(); 1038 | 1039 | while( fgets( line, sizeof(line), stdin ) ) { 1040 | length = strlen( line ); 1041 | if( length && line[length-1] == '\n' ) 1042 | line[--length] = 0; 1043 | if( length && line[length-1] == '\r' ) 1044 | line[--length] = 0; 1045 | if( rfc822_insert( msg, line, length ) ) 1046 | abort(); 1047 | } 1048 | 1049 | 1050 | if( newname ) { 1051 | HDR_LINE h; 1052 | 1053 | if( rfc822_rename_header( msg, name, newname, 0 ) ) 1054 | abort(); 1055 | 1056 | for(h = msg->hdr_lines; h; h = h->next ) 1057 | puts( h->line ); 1058 | } 1059 | else if( 1 ) { 1060 | HDR_LINE h; 1061 | 1062 | if( rfc822_remove_header( msg, name,0 ) ) 1063 | abort(); 1064 | 1065 | for(h = msg->hdr_lines; h; h = h->next ) 1066 | puts( h->line ); 1067 | 1068 | } 1069 | else { 1070 | ctx = rfc822_parse_header( msg, name, -1 ); 1071 | dump_token_list( ctx); 1072 | s1 = ctx? rfc822_query_media_type( ctx, &s2 ) : NULL; 1073 | if( s1 ) 1074 | printf("media: `%s' `%s'\n", s1, s2 ); 1075 | else 1076 | printf("media: [not found]\n"); 1077 | show_param( ctx, "boundary" ); 1078 | show_param( ctx, "protocol" ); 1079 | show_param( ctx, "micalg" ); 1080 | 1081 | rfc822_release_parse_ctx( ctx ); 1082 | } 1083 | 1084 | rfc822_close( msg ); 1085 | return 0; 1086 | } 1087 | #endif 1088 | --------------------------------------------------------------------------------