use external module for clib

This commit is contained in:
Vítor Santos Costa 2011-03-15 16:26:44 +00:00
parent 6b5046bb8c
commit 123cf5af84
137 changed files with 0 additions and 36767 deletions

View File

@ -1,486 +0,0 @@
[Sep 9 2009]
* ADDED: uri_file_name/2
* ADDED: library(uri), providing a much faster and modern API to handling
URIs and IRIs.
[Aug 18 2009]
* CLEANUP: Bug#413: Complete 'make distclean'. Feliks Kluzniak
[Aug 7 2009]
* MODIFIED: WinSock interface now signals WSAECONNABORTED as EOF when reading. This is somewhat debatable, but compatible with the Unix version of the socket interface. Matt Lilley.
[Aug 3 2009]
* PORT: Avoid name-clash on SOCK_* constants.
[Jul 27 2009]
* FIXED: Another timer issue that could crash the alarm-scheduler.
* FIXED: The library(time) now uses SIGUSR2 rather then SIGALRM if available to avoid interference from libreadline's signal handling of SIGALRM.
* FIXED: Crash in alarm-timers (Multi-threaded unix version)
[Jul 21 2009]
* MODIFIED: Make initialization/1 ISO compliant
This patch is a modest cleanup to the implementation of '$load_file'/3
from init.pl and provides an ISO compatible implementation of
initialization/1. This executes the argument goal *after* loading the
file rather than when encountering the directive. Often this makes no
difference, but notably load_foreign_library/1 is an exception.
Therefore we added use_foreign_library/1,2 that act as a directive and
provides proper integration with saved-states automatically. Loading
code using initialization(load_foreign_library(...)) will load the
library immediately and issue a warning.
See initialization/1,2 for details and further hints for dealing with
possible compatibility problems.
[Jul 8 2009]
* ADDED: alarm_at/4. Addition provided by Samar Abdallah.
[Jul 6 2009]
* FIXED: library(time) (Unix version): properly handle multiple alarms at the same time. Reported by Samer Abdallah.
[Jun 15 2009]
* BUILD: Skip RFC2202 tests if Prolog is not compiled with unbounded arithmetic. Keri Harris.
[Jun 2 2009]
* ADDED: uninstall_alarm/1
[Mar 30 2009]
* FIXED: alarm handling on Win64 (Kerri Haris)
[Mar 19 2009]
* CLEANUP: Removed all trailing whitespace from all source-files. This avoids many GIT (merge) warnings.
[Mar 12 2009]
* MODIFIED: Renamed concat_atom/2,3 into atomic_list_concat/2,3 for compatibility. Moved the old predicates into library(backcomp). It is adviced to update your code, but 99% of the code will remain working because the old definitions are autoloaded.
[Feb 4 2009]
* FIXED: Uninitialised variable in environment parsing of process.c. Keri Harris.
[Jan 29 2009]
* CLEANUP: generalisations in the socket library design to allow TIPC to
reuse parts of it. Contributed by Jeff Rosenwald.
* PORT: Port new environment initialisation of process_create/3 to Windows.
The new environment processing code is free of limits (of course, except
limits of the operating system).
[Jan 28 2009]
* ADDED: env option to process_create/3 to specify the environment for
the child process.
[Jan 26 2009]
* FIXED: make install_alarm/1 produce an error when installing twice.
* MODIFIED: Renamed setup_and_call_cleanup/3,4 to setup_call_cleanup/3 and setup_call_catcher_cleanup/4; added to library(backcomp).
* ADDED: library(streaminfo) for debugging (network) stream issues
[Jan 23 2009]
* CHECK: Fixed makefile for modified test entry-point
[Jan 22 2009]
* ADDED: free_on_close option to open_memory_file/4
* CLEANUP: library(time) to use meta_predicate declaration and make debugging a
bit simpler.
[Oct 9 2008]
* ADDED: library(unix): support symbolic signal names.
* FIXED: Many errors in exceptions raised after failing system calls
by the libraries from the clib package.
[Oct 2 2008]
* ENHANCED: Cache value of gethostname/1.
[Sep 11 2008]
* PORT: Add AC_PREREQ to configure.h for systems that auto-select autoconf
versions. After tip by Ulrich Neumerkel.
[Sep 9 2008]
* ADDED: TCP sockets: support TCP_NODELAY using tcp_setopt(Socket, nodelay(true)).
After patch submitted by Matt Lilley.
[Aug 14 2008]
* FIXED: Possible crash if closing a socket in Windows fails. Matt Lilley.
[Aug 13 2008]
* FIXED: Windows: closing the read-handle of a socket reported an error. Matt Lilley.
[Aug 11 2008]
* INSTALL: Remove all configure files from the git repository
[Jul 4 2008]
* FIXED: library(process) stream administration (could lead to errors in close)
[Jul 3 2008]
* FIXED: Avoid possible deadlock in PL_cleanup_fork(). Michiel William Kauw-A-Tjoe
[Jun 25 2008]
* ADDED: memory_file_to_atom/3 and memory_file_to_codes/3 to convert encodings.
[Jun 27 2008]
* FIXED: read_line_to_codes/3: foreign implementation did not unlock stream.
[Jun 13 2008]
* FIXED: Include initialization to load process.so. Matt Lilley.
[May 21 2008]
* FIXED: Error message when using a service name in tcp_bind/connect.
Jean-Marc Vanel.
[May 20 2008]
* PORT: Port UDP socket support to Windows
* MODIFIED: Streams in socket.pl and ssl.pl appeared unbuffered. They
are now fully buffered.
[May 19 2008]
* ADDED: support for 'as(Type) option to udp_receive/4
[May 16 2008]
* FIXED: Process streams are by default in text-mode using full buffering.
[May 12 2008]
* PORT: Ported library(process) to Windows
[May 11 2008]
* ADDED: library(process), providing SICStus 4 compatible process interaction
to the clib packages. Currently runs on Unix systems only (tested Linux and
MacOS X 10.4).
This patch also extends the foreign interface with the PL_get_signum_ex()
and PL_cleanup_fork().
[Mar 10 2008]
* FIXED: Pass error while waiting for accept() in Windows
[Feb 26 2008]
* PORT: Fix compilation of SHA1 routines for SUN/SPARC. Robert Andersson.
[Feb 15 2008]
* FIXED: cgi_get_form/1 now assumes input data is in UTF-8.
[Jan 23 2008]
* PORT: Bug#346: Allow overriding COFLAGS and CWFLAGS in package
configuration. Keri Harris.
[Jan 15 2008]
* PORT: Fix cpp handling in clib package configure. This is assumed to
fix the Darwinports on MacOS Leopard. Nico, Ryoko et Anna.
Oct 6, 2007
* FIXED: call_with_time_limit non-determinism. Norbert Fuchs.
Sep 25, 2007
* Make SHA routines compile on Solaris
Sep 3, 2007
* Possible not working timer alarm. Ulrich Neumerkel.
Jul 30, 2007
* FIXED: Bug#302: memory leak in atom_to_memory_file/2 with filled
output argument. Keri Harris.
Jul 12, 2007
* FIXED: call_with_time_limit/2 if the alarm fires before call_cleanup
is entered, a theoretical problem using short timeouts on a loaded
machine.
* ADDED: install_alarm/1.
* FIXED: Avoid exit of Prolog on uncaught exception from
call_with_time_limit/2. Ulrich Neumerkel.
May 3, 2007
* ADDED: open_memory_file/4, providing encoding facilities. Matt Lilley.
Apr 23, 2007
* FIXED: tcp_accept to deal with stream handles (broken in nbio redesign).
Mar 7, 2007
* FIXED: Put debug message "shutdown(6=-1, SD_RECEIVE) failed" under
tcp_debug/1. Mike Elston
Mar 6, 2007
* FIXED: Waiting for a socket with XPCE enabled.
* ADDED: SHA-1 and SHA-2 support in new library(sha).
Feb 28, 2007
* Re-renerated HTML docs (outdated)
Feb 26, 2007
* FIXED: complete redesign of nonblock.c socket layer to deal with
validness of socket handles.
Feb 9, 2007
* ADDED: MD5 hashes to crypt. Added library(crypt) to Windows version
(only supporting MD5).
Feb 2, 2007
* Fixed alloca issues in socket.c. Richard O'Keefe.
Jan 31, 2007
* Documentation update to document issues in the Windows timer
implementation.
Jan 23, 2007
* size_t cleanup.
Dec 12, 2006
* FIXED: Error handling in read_line_to_codes/[2,3] and
read_stream_to_codes/[2,3].
Nov 8, 2006
* CLEANUP: GCC warnings
Oct 27, 2006
* FIXED: random/3 never to generate upper bound. Nicos.
Oct 16, 2006
* ADDED: YAP/SICStus compatible library(random).
Sep 7, 2006
* FIXED: Bug#205 make --> $(MAKE). Marc Espie
Feb 1, 2006
* FIXED: Remove DOS ^M from files in maildrop package. Richard O'Keefe.
Jan 19, 2006
* Fixed: Bug#137: make time.c compile for single-threaded operation
Keri Harris.
Jan 12, 2006
* Fixed: rewrote most of time.c, providing alarm/4 using portable
pthread code.
Jan 10, 2006
* UDP ssize_t portability issues
Dec 23, 2005
* Start work on UDP support in socket.pl.
Oct 14, 2005
* Fixed signedness error in library memfile, returning incorrect values
for size_memory_file/2
Oct 11, 2005
* PORT: Use plld to compile maildrop as position independent code
May 22, 2005
* PORT: Added maildrop RFC libraries to distribution
Apr 23, 2005
* FIXED: mime_parse/3: read stream with Sgetcode rather than Sgetc to
deal with encoding issues.
Feb 17, 2005
* ADDED: Provide wide-character support for library(memfile).
Dec 16, 2004
* FIXED: Socket and ssl interaction problems (Windows). Matt Lilley.
October 04, 2004
* FIXED: library(socket) and library(ssl): potential crash and starvation
issue. Appears to happen only on Windows NT, but the problem can -at
least in theory- also appear in other Windows versions. With thanks
to Mike Elston for providing the test program.
Sep 21, 2004
* FIXED: cgi_get_form/1 for www-form-encoded strings with lowercase
%xx. John Paolillo.
Jul 18, 2004
* CLEANUP: ensure mimimal library dependency. After discussion on
mailinglist.
Jul 5, 2004
* CLEANUP: split socket library in two to be able to reuse the
non-blocking socket stuff in the SSL library.
May 5, 2004
* FIXED: memory leak in open_memory_file/3. Fabien Todescato.
Oct 2, 2003
* PORT: Configure socket library for IRIX 6.5 (Rob Myers).
Aug 28, 2003
* FIXED: Complete rewrite of library(socket) for MS-Windows.
Jun 2, 2003
* FIXED: time:remove_alarm/1 for MS-WIndows. Mike Elston.
Mar 14, 2003
* ADDED: Code to make sockets cooperate with signals, so
call_with_time_limit/2 works on blocking socket operations.
* FIXED: Error handling on sockets (Windows)
* FIXED: call_with_time_limit/2 module problem
Feb 2, 2003
* FIXED: call_with_time_limit/2 if the argument goal fails. Wouter
Jansweijer.
Dec 18, 2002
* FIXED: make all socket calls resume on EINTR (Unix systems).
Dec 7, 2002
* FIXED: hand open sockets to other threads (blocking problems in Windows).
Dec 6, 2002
* FIXED: blocking write in sockets and make tcp_close_socket close the
associated streams (if any).
Dec 4, 2002
* FIXED: tcp_close_socket/1 to work on the listened socket. Peter Marks.
Dec 2, 2002
* ADDED: tcp_bind(+Socket, -Port) to bind with an arbitrary free port.
Nov 29, 2002
* FIXED: MS-Windows tcp_read() not to wait for messages after we have
seen FD_CLOSE. Holger Kanwischer.
* ADDED: Make library(socket) suitable for multi-threaded operation in
MS-Windows. Mike Elston.
Nov 26, 2002
* ADDED: Make library(time) suitable for multi-threaded operation.
* ADDED: library(rlimit) for accessing POSIX process limits
Jul 24, 2002
* ADDED: tcp_setopt(Socket, dispatch(false))
Jun 20, 2002
* FIXED: Handle WSAEWOULDBLOCK in tcp_acept() to get a blocking accept
call.
Jun 11, 2002
* ADDED: library(files), providing uncommon access to file objects.
29/04/2002
* Add initialization to load_foreign_library for calls lacking this.
Holger Kanwischer.
28/03/2002
* Record position on socket-streams (SIO_RECORDPOS).
* Many changes to library(socket): fixes for the Windows implementation,
dispatch events during tcp_read() while waiting for input.
01/02/2002
* Modified copyright for compatibility with the now LGPL SWI-Prolog system
07/12/2001
* FIXED: memory_file_to_atom/2 and friends to return size 0, empty atom
when the file contains no data.
10/06/2001
* ADDED: library(mime) for MIME message parsing.
07/10/2000
* ADDED: Allow for descriptor to arguments of dup/2.
30/06/1999
* ADDED: cgi.pl, cgi.c and form.[ch] providing cgi_get_form/1 to get the
Form-data if SWI-Prolog is installed as a CGI script.
06/04/1999
* Renamed the predicates from the socket package to tcp_<their-old-name>.
These predicates are meant as low-level primitives and their normal name
is too general.

View File

@ -1,184 +0,0 @@
################################################################
# Makefile template for SWI-Prolog CLIB package
#
# This template is used by configure to create Makefile. See
# the file INSTALL for further installation instructions.
#
# License: LGPL
#
# Author: Jan Wielemaker (wielemak@science.uva.nl)
################################################################
PACKAGE=clib
DOC=clib
PKGCFLAGS=-I$(srcdir) -I$(srcdir)/maildrop/rfc2045 -I$(srcdir)/maildrop/rfc822
include ../Makefile.defs
NETLIBS=@CLIB_NETLIBS@
CRYPTLIBS=@CLIB_CRYPTLIBS@
MIMELIBS=maildrop/rfc2045/librfc2045.a maildrop/rfc822/librfc822.a
LIBPL= @CLIB_PLTARGETS@ streaminfo.pl process.pl prolog_server.pl sha.pl \
uri.pl
TARGETS= @CLIB_TARGETS@ readutil.@SO@ streaminfo.@SO@ process.@SO@ \
sha4pl.@SO@ uri.@SO@
UNXOBJ= error.o unix.o
SOCKOBJ= error.o socket.o nonblockio.o
CGIOBJ= error.o form.o cgi.o
CRYPTOBJ= error.o crypt.o md5.o md5passwd.o
MEMOBJ= error.o memfile.o
MIMEOBJ= error.o mime.o
TIMEOBJ= error.o time.o
FILESOBJ= error.o files.o
RLIMITOBJ= error.o rlimit.o
URIOBJ= uri.o
RANDOMOBJ= random.o
READUTILOBJ= readutil.o
PROCESSOBJ= error.o process.o
STREAMINFOOBJ= error.o streaminfo.o
SHAOBJ= error.o sha4pl.o sha1/sha1.o sha1/sha2.o \
sha1/hmac_sha1.o sha1/hmac_sha256.o
all: $(TARGETS)
random.@SO@: $(RANDOMOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(RANDOMOBJ)
unix.@SO@: $(UNXOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(UNXOBJ)
socket.@SO@: $(SOCKOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(SOCKOBJ) $(NETLIBS)
cgi.@SO@: $(CGIOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(CGIOBJ)
crypt.@SO@: $(CRYPTOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(CRYPTOBJ) $(CRYPTLIBS)
memfile.@SO@: $(MEMOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(MEMOBJ) $(LIBS)
mime.@SO@: $(MIMEOBJ) $(MIMELIBS)
$(LD) $(LDSOFLAGS) -o $@ $(MIMEOBJ) $(MIMELIBS)
time.@SO@: $(TIMEOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(TIMEOBJ) $(LIBS)
files.@SO@: $(FILESOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(FILESOBJ) $(LIBS)
rlimit.@SO@: $(RLIMITOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(RLIMITOBJ) $(LIBS)
readutil.@SO@: $(READUTILOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(READUTILOBJ)
process.@SO@: $(PROCESSOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(PROCESSOBJ)
streaminfo.@SO@: $(STREAMINFOOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(STREAMINFOOBJ)
sha4pl.@SO@: $(SHAOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(SHAOBJ)
uri.@SO@: $(URIOBJ)
$(LD) $(LDSOFLAGS) -o $@ $(URIOBJ)
socket.o: $(srcdir)/socket.c $(srcdir)/sockcommon.c
sha1/sha1.o:
$(CC) -c $(CFLAGS) -DUSE_SHA1 -o $@ $(srcdir)/sha1/sha1.c
sha1/sha2.o:
$(CC) -c $(CFLAGS) -DUSE_SHA1 -o $@ $(srcdir)/sha1/sha2.c
sha1/hmac_sha1.o:
$(CC) -c $(CFLAGS) -DUSE_SHA1 -o $@ $(srcdir)/sha1/hmac.c
sha1/hmac_sha256.o:
$(CC) -c $(CFLAGS) -DUSE_SHA256 -o $@ $(srcdir)/sha1/hmac.c
maildrop/rfc822/librfc822.a:
(cd maildrop/rfc822 && $(MAKE))
maildrop/rfc2045/librfc2045.a:
(cd maildrop/rfc2045 && $(MAKE))
install: $(TARGETS)
mkdir -p $(DESTDIR)$(SOLIBDIR)
for f in $(TARGETS); do \
$(INSTALL_PROGRAM) $$f $(DESTDIR)$(SOLIBDIR); \
done
mkdir -p $(DESTDIR)$(PLLIBDIR)
for f in $(LIBPL); do \
$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(PLLIBDIR); \
done
( cd $(srcdir) ; $(PL) -f none -g make -t halt )
ln-install::
@$(MAKE) INSTALL_DATA='../ln-install' INSTALL_PROGRAM='../ln-install' install
rpm-install: install
html-install::
mkdir -p $(DESTDIR)$(PKGDOC)
$(INSTALL) -m 644 clib.html $(DESTDIR)$(PKGDOC)
pdf-install::
mkdir -p $(DESTDIR)$(PKGDOC)
$(INSTALL) -m 644 clib.pdf $(DESTDIR)$(PKGDOC)
uninstall::
(cd $(PLBASE)/lib/$(PLARCH) && rm -f $(TARGETS))
(cd $(PLBASE)/library && rm -f $(LIBPL))
$(PL) -f none -g make -t halt
################################################################
# Testing
################################################################
check: check-socket check-memfile check-unit check-process \
check-read check-uri check-cgi
torture: torture-socket
check-socket::
( cd $(srcdir) && $(PL) -q -f test_socket.pl -F none -g test_socket,halt -t 'halt(1)' )
torture-socket::
( cd $(srcdir) && $(PL) -q -f stresssocket.pl -F none -g test,halt -t 'halt(1)' )
check-memfile::
( cd $(srcdir) && $(PL) -q -f test_memfile.pl -F none -g test_memfile,halt -t 'halt(1)' )
check-unit::
( cd $(srcdir) && $(PL) -q -f test.pl -g run_tests,halt -t 'halt(1)' )
check-uri::
( cd $(srcdir) && $(PL) -q -f test_uri.pl -g true -t test_uri )
check-cgi::
( cd $(srcdir) && $(PL) -q -f test_cgi.pl -g true -t test_cgi )
check-process::
( cd $(srcdir) && $(PL) -q -f test_process.pl -g true -t test_process )
check-read::
( cd $(srcdir) && $(PL) -q -f test_readutil.pl -g true -t test_readutil )
################################################################
# Documentation
################################################################
TEXEXTRA=process.tex uri.tex filesex.tex
$(TEX): $(TEXEXTRA)
uri.tex: uri.pl
$(PLTOTEX) 'library(uri)'
process.tex: process.pl
$(PLTOTEX) 'library(process)'
filesex.tex: filesex.pl
$(PLTOTEX) 'library(filesex)'
################################################################
# Clean
################################################################
clean:
rm -f $(OBJ) *~ *.o *% a.out core config.log sha1/*.o
rm -f $(TEX)
-(cd maildrop/rfc822 && $(MAKE) clean)
-(cd maildrop/rfc2045 && $(MAKE) clean)
distclean: clean
rm -f $(TARGETS) config.cache config.h config.status Makefile
rm -f clib.aux clib.log clib.out clib.toc
rm -rf html
-(cd maildrop/rfc822 && $(MAKE) distclean)
-(cd maildrop/rfc2045 && $(MAKE) distclean)

View File

@ -1,172 +0,0 @@
################################################################
# Build the SWI-Prolog tabling package for MS-Windows
#
# Author: Jan Wielemaker
#
# Use:
# nmake /f Makefile.mak
# nmake /f Makefile.mak install
################################################################
PLHOME=..\..
!include $(PLHOME)\src\rules.mk
PKGDLL=socket
SOCKOBJ= socket.obj nonblockio.obj error.obj
CGIOBJ= error.obj form.obj cgi.obj
CRYPTOBJ= error.obj crypt.obj md5.obj md5passwd.obj bsd-crypt.obj
MEMOBJ= error.obj memfile.obj
MIMEOBJ= error.obj mime.obj
MIMELIBS= rfc2045.lib rfc822.lib
TIMEOBJ= error.obj time.obj
READOBJ= readutil.obj
PROCESSOBJ= error.obj process.obj
RANDOMOBJ= random.obj
SHAOBJ= error.obj sha4pl.obj sha1/sha1.obj sha1/sha2.obj \
sha1/hmac_sha1.obj sha1/hmac_sha256.obj
URIOBJ= uri.obj
FILESOBJ= error.obj files.obj
TIMELIBS= winmm.lib
all: socket.dll cgi.dll memfile.dll mime.dll time.dll readutil.dll \
random.dll crypt.dll sha4pl.dll process.dll uri.dll files.dll
readutil.dll: $(READOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(READOBJ) $(PLLIB) $(LIBS)
process.dll: $(PROCESSOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(PROCESSOBJ) $(PLLIB) $(LIBS)
socket.dll: $(SOCKOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(SOCKOBJ) $(PLLIB) $(LIBS)
cgi.dll: $(CGIOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(CGIOBJ) $(PLLIB) $(LIBS)
crypt.dll: $(CRYPTOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(CRYPTOBJ) $(PLLIB) $(LIBS)
memfile.dll: $(MEMOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(MEMOBJ) $(PLLIB) $(LIBS)
mime.dll: $(MIMEOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(MIMEOBJ) $(PLLIB) $(LIBS) $(MIMELIBS)
time.dll: $(TIMEOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(TIMEOBJ) $(PLLIB) $(LIBS) $(TIMELIBS)
random.dll: $(RANDOMOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(RANDOMOBJ) $(PLLIB) $(LIBS)
sha4pl.dll: $(SHAOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(SHAOBJ) $(PLLIB) $(LIBS)
uri.dll: $(URIOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(URIOBJ) $(PLLIB) $(LIBS)
files.dll: $(FILESOBJ)
$(LD) /dll /out:$@ $(LDFLAGS) $(FILESOBJ) $(PLLIB) $(LIBS)
sha1/hmac_sha1.obj: sha1/hmac.c
$(CC) -I $(PLHOME)\include $(CFLAGS) /DUSE_SHA1 /Fo$@ sha1/hmac.c
sha1/hmac_sha256.obj: sha1/hmac.c
$(CC) -I $(PLHOME)\include $(CFLAGS) /DUSE_SHA256 /Fo$@ sha1/hmac.c
process.obj: win_error.c
files.obj: win_error.c
!IF "$(CFG)" == "rt"
install: idll
!ELSE
install: idll ilib
!ENDIF
################################################################
# Testing
################################################################
check: check-socket
torture: torture-socket
check-socket::
"$(PLCON)" -q -f testsocket.pl -F none -g tcp_test,halt -t 'halt(1)'
torture-socket::
"$(PLCON)" -q -f stresssocket.pl -F none -g test,halt -t 'halt(1)'
################################################################
# Installation
################################################################
idll::
copy socket.dll "$(BINDIR)"
copy cgi.dll "$(BINDIR)"
copy crypt.dll "$(BINDIR)"
copy memfile.dll "$(BINDIR)"
copy mime.dll "$(BINDIR)"
copy time.dll "$(BINDIR)"
copy random.dll "$(BINDIR)"
copy readutil.dll "$(BINDIR)"
copy process.dll "$(BINDIR)"
copy sha4pl.dll "$(BINDIR)"
copy uri.dll "$(BINDIR)"
copy files.dll "$(BINDIR)"
!IF "$(PDB)" == "true"
copy socket.pdb "$(BINDIR)"
copy cgi.pdb "$(BINDIR)"
copy memfile.pdb "$(BINDIR)"
copy mime.pdb "$(BINDIR)"
copy time.pdb "$(BINDIR)"
copy readutil.pdb "$(BINDIR)"
copy process.pdb "$(BINDIR)"
copy sha4pl.pdb "$(BINDIR)"
copy uri.pdb "$(BINDIR)"
copy files.pdb "$(BINDIR)"
!ENDIF
ilib::
copy socket.pl "$(PLBASE)\library"
copy prolog_server.pl "$(PLBASE)\library"
copy streampool.pl "$(PLBASE)\library"
copy cgi.pl "$(PLBASE)\library"
copy crypt.pl "$(PLBASE)\library"
copy memfile.pl "$(PLBASE)\library"
copy mime.pl "$(PLBASE)\library"
copy random.pl "$(PLBASE)\library"
copy time.pl "$(PLBASE)\library"
copy sha.pl "$(PLBASE)\library"
copy uri.pl "$(PLBASE)\library"
copy filesex.pl "$(PLBASE)\library"
copy process.pl "$(PLBASE)\library"
$(MAKEINDEX)
uninstall::
del "$(BINDIR)\socket.dll"
del "$(BINDIR)\streampool.dll"
del "$(BINDIR)\cgi.dll"
del "$(BINDIR)\crypt.dll"
del "$(BINDIR)\memfile.dll"
del "$(BINDIR)\mime.dll"
del "$(BINDIR)\random.dll"
del "$(BINDIR)\time.dll"
del "$(BINDIR)\readutil.dll"
del "$(BINDIR)\sha4pl.dll"
del "$(BINDIR)\uri.dll"
del "$(BINDIR)\files.dll"
del "$(PLBASE)\library\socket.pl"
del "$(PLBASE)\library\cgi.pl"
del "$(PLBASE)\library\crypt.pl"
del "$(PLBASE)\library\memfile.pl"
del "$(PLBASE)\library\mime.pl"
del "$(PLBASE)\library\random.pl"
del "$(PLBASE)\library\time.pl"
del "$(PLBASE)\library\sha.pl"
del "$(PLBASE)\library\uri.pl"
del "$(PLBASE)\library\filesex.pl"
del "$(PLBASE)\library\process.pl"
$(MAKEINDEX)
html-install::
copy clib.html "$(PKGDOC)"
xpce-install::
clean::
if exist *.obj del *.obj
if exist sha1\*.obj del sha1\*.obj
if exist *~ del *~
distclean: clean
-DEL *.dll *.lib *.exp *.ilk *.pdb 2>nul

View File

@ -1,30 +0,0 @@
---+ SWI-Prolog Library CLIB
Author: Jan Wielemaker
Copyright: SWI-Prolog conditions
LGPL for C-code, GPL+exception for Prolog-code
This library contains SWI-Prolog foreign-libraries to deal with various
OS-dependent or obscure stuff from SWI-Prolog.
Currently provided:
* library(unix)
Unix process management and other Unix-specific extensions:
fork/1, exec/1, pipe/2, etc.
* library(process)
Create and manage processes, compatible to SICStus 4.
* library(socket)
General purpose inet tcp socket library. Loosely based on a TCP
library from Gordon Streeter.
* library(cgi)
Get form-arguments from input and/or environment for CGI scripts
* library(crypt)
Unix password generation and validation.
* library(memfile)
Read-write to memory-buffers, an alternative to temporary files.

View File

@ -1 +0,0 @@
1.2.1

File diff suppressed because it is too large Load Diff

View File

@ -1,189 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <SWI-Prolog.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "clib.h"
#include "form.h"
#ifdef __WINDOWS__ /* strtoll is C99, but it is only 2011 ... */
#define strtoll(s,e,b) _strtoi64(s,e,b)
#endif
static int
isinteger(const char *s, long long *val, size_t len)
{ char *e;
if ( len == (size_t)-1 )
len = strlen(s);
if ( len == 0 )
return FALSE;
*val = strtoll(s, &e, 10);
if ( e == s+len )
return TRUE;
return FALSE;
}
static int
isfloat(const char *s, double *val, size_t len)
{ char *e;
if ( len == (size_t)-1 )
len = strlen(s);
if ( len == 0 )
return FALSE;
*val = strtod(s, &e);
if ( e == s+len )
return TRUE;
return FALSE;
}
static int
add_to_form(const char *name, size_t nlen,
const char *value, size_t len,
void *closure)
{ term_t head = PL_new_term_ref();
term_t tail = (term_t) closure;
term_t val = PL_new_term_ref();
long long vl;
double vf;
int rc;
atom_t aname = 0;
if ( isinteger(value, &vl, len) )
rc = PL_put_int64(val, vl);
else if ( isfloat(value, &vf, len) )
rc = PL_put_float(val, vf);
else
rc = PL_unify_chars(val, PL_ATOM|REP_UTF8, len, value);
rc = ( rc &&
PL_unify_list(tail, head, tail) &&
(aname = PL_new_atom_nchars(nlen, name)) &&
PL_unify_term(head,
PL_FUNCTOR, PL_new_functor(aname, 1),
PL_TERM, val) );
if ( aname )
PL_unregister_atom(aname);
return rc;
}
static int
mp_add_to_form(const char *name, size_t nlen,
const char *value, size_t len,
const char *file, void *closure)
{ term_t head = PL_new_term_ref();
term_t tail = (term_t) closure;
term_t val = PL_new_term_ref();
long long vl;
double vf;
int rc;
atom_t aname = 0;
if ( isinteger(value, &vl, len) )
rc = PL_put_int64(val, vl);
else if ( isfloat(value, &vf, len) )
rc = PL_put_float(val, vf);
else
rc = PL_unify_chars(val, PL_ATOM|REP_UTF8, len, value);
rc = ( rc &&
PL_unify_list(tail, head, tail) &&
(aname = PL_new_atom_nchars(nlen, name)) &&
PL_unify_term(head,
PL_FUNCTOR, PL_new_functor(aname, 1),
PL_TERM, val) );
if ( aname )
PL_unregister_atom(aname);
return rc;
}
static foreign_t
pl_cgi_get_form(term_t form)
{ size_t len = 0;
char *data;
int must_free = FALSE;
term_t list = PL_copy_term_ref(form);
char *ct, *boundary;
if ( !get_raw_form_data(&data, &len, &must_free) )
return FALSE;
if ( (ct = getenv("CONTENT_TYPE")) &&
(boundary = strstr(ct, "boundary=")) )
{ boundary = strchr(boundary, '=')+1;
switch( break_multipart(data, len, boundary,
mp_add_to_form, (void *)list) )
{ case FALSE:
return FALSE;
case TRUE:
break;
default:
assert(0);
return FALSE;
}
} else
{ switch( break_form_argument(data, add_to_form, (void *)list) )
{ case FALSE:
return FALSE;
case TRUE:
break;
case ERROR_NOMEM:
return pl_error("cgi_get_form", 1, NULL,
ERR_RESOURCE, "memory");
case ERROR_SYNTAX_ERROR:
return pl_error("cgi_get_form", 1, NULL,
ERR_SYNTAX, "cgi_value");
default:
assert(0);
return FALSE;
}
}
if ( must_free )
free(data);
return PL_unify_nil(list);
}
install_t
install_cgi()
{ PL_register_foreign("cgi_get_form", 1, pl_cgi_get_form, 0);
}

View File

@ -1,82 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(cgi,
[ cgi_get_form/1 % -ListOf Name(Value)
]).
:- use_module(library(shlib)).
:- use_foreign_library(foreign(cgi), install_cgi).
/** <module> Read CGI parameters
Below is a very simple CGI script that prints the passed parameters. To
test it, compile this program using the command below, copy it to your
cgi-bin directory (or make it otherwise known as a CGI-script) and try
the query =|http://myhost.mydomain/cgi-bin/cgidemo?hello=world|=
==
% swipl -o cgidemo --goal=main --toplevel=halt -c cgidemo.pl
==
==
:- use_module(library(cgi)).
main :-
set_stream(current_output, encoding(utf8)),
cgi_get_form(Arguments),
format('Content-type: text/html; charset=UTF-8~n~n', []),
format('<html>~n', []),
format('<head>~n', []),
format('<title>Simple SWI-Prolog CGI script</title>~n', []),
format('</head>~n~n', []),
format('<body>~n', []),
format('<p>', []),
print_args(Arguments),
format('</body>~n</html>~n', []).
print_args([]).
print_args([A0|T]) :-
A0 =.. [Name, Value],
format('<b>~w</b>=<em>~w</em><br>~n', [Name, Value]),
print_args(T).
==
*/
%% cgi_get_form(-Form)
%
% Decodes standard input and the environment variables to obtain a
% list of arguments passed to the CGI script. This predicate both
% deals with the CGI *GET* method as well as the *POST* method. If
% the data cannot be obtained, an existence_error exception is
% raised.
%
% @param Form is a list of Name(Value) terms.

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CLIB_H_INCLUDED
#define CLIB_H_INCLUDED
#include <SWI-Prolog.h>
#include "error.h"
#define CompoundArg(name, arity) \
PL_FUNCTOR, PL_new_functor(PL_new_atom(name), (arity))
#define AtomArg(name) \
PL_CHARS, name
#define IntArg(i) \
PL_INTEGER, (long)(i)
install_t install_process(void);
install_t install_socket(void);
#endif /*CLIB_H_INCLUDED*/

View File

@ -1,132 +0,0 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(install-sh)
AC_PREREQ([2.50])
AC_CONFIG_HEADER(config.h)
AC_SUBST(TARGETS)
AC_SUBST(PLTARGETS)
AC_SUBST(NETLIBS)
AC_SUBST(CRYPTLIBS)
m4_include([../ac_swi_c.m4])
TARGETS="random.$SO unix.$SO socket.$SO cgi.$SO memfile.$SO files.$SO mime.$SO crypt.$SO"
AC_CHECK_FUNC(socket, [], [
AC_CHECK_LIB(socket, socket,
[NETLIBS="$NETLIBS -lsocket"; LIBS="$LIBS -lsocket"]
AC_DEFINE(HAVE_LIBSOCKET, 1,
"Define if you have the socket library (-lsocket)."))])
AC_CHECK_FUNC(gethostent, [], [
AC_CHECK_LIB(nsl, gethostent,
[NETLIBS="$NETLIBS -lnsl"]
AC_DEFINE(HAVE_LIBNSL, 1,
"Define if you have the nsl library (-lnsl)."))])
oldlibs="$LIBS"
AC_CHECK_LIB(crypt, crypt)
CRYPTLIBS="$LIBS"
AC_CHECK_FUNCS(crypt)
LIBS="$oldlibs"
AC_MSG_CHECKING("Configuring MIME libraries")
case "$CC" in
.*) ACC="../../$CC"
;;
*) ACC="$CC"
esac
case "$LD" in
.*) ALD="../../$LD"
;;
*) ALD="$LD"
esac
case "$CPP" in
.*) ACPP="../../$CPP"
;;
*) ACPP="$CPP"
esac
( CC=$ACC; LD=$ALD; CPP=$ACPP; CFLAGS=$CFLAGS; LDFLAGS=$LDFLAGS;
export CC LD CFLAGS LDFLAGS
(cd maildrop/rfc822 && $SHELL configure)
(cd maildrop/rfc2045 && $SHELL configure)
)
AC_MSG_RESULT("Done")
AC_MSG_CHECKING(h_errno)
AC_TRY_COMPILE(
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
],
[ int x = h_errno;
], AC_DEFINE(HAVE_H_ERRNO, 1,
[Define of h_errno is provided])
AC_MSG_RESULT(yes),
AC_MSG_RESULT(no))
AC_CHECK_HEADERS(malloc.h alloca.h unistd.h sys/time.h fcntl.h utime.h)
AC_CHECK_HEADERS(execinfo.h sys/resource.h crypt.h)
AC_CHECK_HEADERS(sys/types.h sys/wait.h sys/stat.h)
AC_CHECK_HEADERS(netinet/tcp.h)
AC_CHECK_SIZEOF(long, 4)
AC_CHECK_SIZEOF(long long, 8)
AC_CHECK_FUNCS(setsid strerror setitimer utime getrlimit vfork)
AC_CHECK_TYPES(socklen_t, [], [],
[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_CHECK_TYPES(ssize_t, [], [],
[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_MSG_CHECKING(_XOPEN_SOURCE)
AC_TRY_COMPILE(
[
#define _XOPEN_SOURCE
#include <unistd.h>
],
[
], AC_DEFINE(DEFINE_XOPEN_SOURCE, 1,
"Define if _XOPEN_SOURCE is needed")
AC_MSG_RESULT(yes),
AC_MSG_RESULT(no))
with_time=yes
AC_ARG_WITH(time, [ --without-time Exclude alarm library],
[case "$withval" in
yes) with_time=yes ;;
no) with_time=no ;;
esac])
if test "$with_time" = yes; then
if test "$ac_cv_func_setitimer" = "yes"; then
TARGETS="$TARGETS time.$SO"
else
echo "WARNING: no setitimer(); dropping time.pl from targets"
fi
fi
if test "$ac_cv_func_getrlimit" = "yes"; then
TARGETS="$TARGETS rlimit.$SO"
else
"WARNING: no getrlimit(); dropping rlimit.pl from targets"
fi
PLTARGETS=`echo $TARGETS | sed -e "s/\.$SO/.pl/g" -e "s/files.pl/filesex.pl/"`
if echo "$PLTARGETS" | grep socket.pl 2>&1 >/dev/null; then
PLTARGETS="$PLTARGETS streampool.pl"
fi
AC_OUTPUT(Makefile)

View File

@ -1,165 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemaker@cs.vu.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2010, University of Amsterdam, VU Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef DEFINE_XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#else
extern char *crypt(const char *key, const char *setting);
#endif
#include <stdlib.h>
#include <string.h>
#include <SWI-Stream.h>
#include <SWI-Prolog.h>
#include "clib.h"
/* md5passwd.c */
extern char *md5_crypt(const char *pw, const char *salt);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simple interface to the Unix password encryption routine. Implemented
for providing authorization in the multi-threaded Prolog based HTTP
deamon and therefore providing a thread-safe interface.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef _REENTRANT
#include <pthread.h>
static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
#define LOCK() pthread_mutex_lock(&crypt_mutex)
#define UNLOCK() pthread_mutex_unlock(&crypt_mutex)
#else
#define LOCK()
#define UNLOCK()
#endif
static foreign_t
pl_crypt(term_t passwd, term_t encrypted)
{ char *pw, *e;
char salt[20];
if ( !PL_get_chars(passwd, &pw, CVT_ATOM|CVT_STRING|CVT_LIST|BUF_RING) )
return pl_error("crypt", 2, NULL, ERR_ARGTYPE,
1, passwd, "text");
if ( PL_get_chars(encrypted, &e, CVT_ATOM|CVT_STRING|CVT_LIST|BUF_RING) )
{ char *s2;
if ( strncmp(e, "$1$", 3) == 0 ) /* MD5 Hash */
{ char *p = strchr(e+3, '$');
size_t slen;
if ( p && (slen=(size_t)(p-e-3)) < sizeof(salt) )
{ strncpy(salt, e+3, slen);
salt[slen] = 0;
s2 = md5_crypt(pw, salt);
return (strcmp(s2, e) == 0) ? TRUE : FALSE;
} else
{ Sdprintf("No salt???\n");
return FALSE;
}
} else
{ int rval;
salt[0] = e[0];
salt[1] = e[1];
salt[2] = '\0';
LOCK();
s2 = crypt(pw, salt);
rval = (strcmp(s2, e) == 0 ? TRUE : FALSE);
UNLOCK();
return rval;
}
} else
{ term_t tail = PL_copy_term_ref(encrypted);
term_t head = PL_new_term_ref();
int slen = 2;
int n;
int (*unify)(term_t t, const char *s) = PL_unify_list_codes;
char *s2;
int rval;
for(n=0; n<slen; n++)
{ if ( PL_get_list(tail, head, tail) )
{ int i;
char *t;
if ( PL_get_integer(head, &i) && i>=0 && i<=255 )
{ salt[n] = i;
} else if ( PL_get_atom_chars(head, &t) && t[1] == '\0' )
{ salt[n] = t[0];
unify = PL_unify_list_chars;
} else
{ return pl_error("crypt", 2, NULL, ERR_ARGTYPE,
2, head, "character");
}
if ( n == 1 && salt[0] == '$' && salt[1] == '1' )
slen = 3;
else if ( n == 2 && salt[2] == '$' )
slen = 8+3;
} else
break;
}
for( ; n < slen; n++ )
{ int c = 'a'+(int)(26.0*rand()/(RAND_MAX+1.0));
if ( rand() & 0x1 )
c += 'A' - 'a';
salt[n] = c;
}
salt[n] = 0;
LOCK();
if ( slen > 2 )
{ s2 = md5_crypt(pw, salt);
} else
{ s2 = crypt(pw, salt);
}
rval = (*unify)(encrypted, s2);
UNLOCK();
return rval;
}
}
install_t
install_crypt()
{ PL_register_foreign("crypt", 2, pl_crypt, 0);
}

View File

@ -1,41 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(crypt,
[ crypt/2
]).
:- use_foreign_library(foreign(crypt), install_crypt).
% crypt(+Passwd, ?Encripted).
%
% Used to test an encrypted passwd or create one. In the latter
% case, the first 2 letter must be instantiated

View File

@ -1,29 +0,0 @@
#!/usr/bin/pl -q -g main -s
/* $Id$
Part of SWI-Prolog
This example code is in the public domain
*/
:- use_module(library(cgi)).
main :-
cgi_get_form(Arguments),
format('Content-type: text/html~n~n', []),
format('<html>~n', []),
format('<head>~n', []),
format('<title>Simple SWI-Prolog CGI script output</title>~n', []),
format('</head>~n~n', []),
format('<body>~n', []),
format('<h1>Form arguments</h1>'),
format('<p>', []),
print_args(Arguments),
format('<body>~n</html>~n', []),
halt.
print_args([]).
print_args([A0|T]) :-
A0 =.. [Name, Value],
format('<b>~w</b>=<em>~w</em><br>~n', [Name, Value]),
print_args(T).

View File

@ -1,33 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi.psy.uva.nl/projects/SWI-Prolog/
Copying: GPL-2. See the file COPYING or http://www.gnu.org
Copyright (C) 1990-2001 SWI, University of Amsterdam. All rights reserved.
*/
:- use_module(library(unix)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simple demo illustrating the combination of fork/1 and pipe/2 to make
Prolog fork a child to do some work and get back when done. Using
wait_for_input/3 you can make the main Prolog task wait for multiple
childs to return results.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
fork_demo(Result) :-
pipe(Read, Write),
fork(Pid),
( Pid == child
-> close(Read),
format(Write, '~q.~n', [hello(world)]),
flush_output(Write), % stream is fully buffered!
halt
; close(Write),
read(Read, Result),
close(Read)
).

View File

@ -1,60 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi.psy.uva.nl/projects/SWI-Prolog/
Copying: GPL-2. See the file COPYING or http://www.gnu.org
Copyright (C) 1990-2000 SWI, University of Amsterdam. All rights reserved.
*/
:- module(subcommand,
[ pipe_through_command/3 % +Command, +In, -Out
]).
:- use_module(library(unix)).
% pipe_through_command(+Command, +In, -Out)
%
% Pipe text In through command Command and put the output of command
% in Out.
%
% Example:
%
% ?- pipe_through_command(tr('a-z', 'A-Z'), hello, X)
%
% X = 'HELLO'
pipe_through_command(Command, In, Out) :-
pipe(ChildIn, MeOut),
pipe(MeIn, ChildOut),
fork(Pid),
( Pid == child,
close(MeOut),
close(MeIn),
dup(ChildIn, 0),
dup(ChildOut, 1),
close(ChildIn),
close(ChildOut),
exec(Command)
; close(ChildIn),
close(ChildOut),
write(MeOut, In),
close(MeOut),
read_input(MeIn, Out),
close(MeIn),
wait(Pid, _Status) % avoid zombi
).
read_input(In, Atom) :-
get_code(In, C0),
read_input(C0, In, Codes),
atom_codes(Atom, Codes).
read_input(-1, _, []) :- !.
read_input(C, In, [C|T]) :-
get_code(In, C1),
read_input(C1, In, T).

View File

@ -1,117 +0,0 @@
/* $Id$
Part of SWI-Prolog
This example code is in the public domain
*/
:- asserta(library_directory('.')).
:- asserta(user:file_search_path(foreign, '.')).
:- use_module(library(socket)).
/*******************************
* SOCKET (CLIENT) *
*******************************/
get_http_data(Host, URL) :-
tcp_socket(Socket),
tcp_connect(Socket, Host:80),
tcp_open_socket(Socket, Read, Write),
format(Write, 'GET ~w~n~n', URL),
flush_output(Write),
copy_stream(Read, user_output),
close(Read),
close(Write).
copy_stream(In, Out) :-
get0(In, C0),
copy_stream(C0, In, Out).
copy_stream(-1, _, _) :- !.
copy_stream(C, In, Out) :-
put(Out, C),
get0(In, C2),
copy_stream(C2, In, Out).
/*******************************
* SOCKET (SERVER) *
*******************************/
:- dynamic
server/1,
client/2.
mkserver :-
mkserver(3000).
mkserver(Port) :-
tcp_socket(Socket),
tcp_bind(Socket, Port),
tcp_listen(Socket, 5),
tcp_open_socket(Socket, Read, _),
asserta(server(Read)).
dispatch :-
repeat,
\+ dispatch1, !.
dispatch1 :-
findall(C, client(C, _), Clients),
server(Server),
wait_for_input([Server|Clients], Ready, 0),
dispatch(Ready).
dispatch([]).
dispatch([H|T]) :-
format('Dispatching ~w ... ', [H]), flush,
dispatch_fd(H),
format('ok~n'),
dispatch(T).
dispatch_fd(Server) :-
server(Server), !,
tcp_accept(Server, ClientSocket, Peer),
format('Connected from ~w~n', [Peer]),
tcp_fcntl(ClientSocket, setfl, nonblock),
tcp_open_socket(ClientSocket, Read, Write),
format(Write, 'Please to meet you!~n', []),
flush_output(Write),
assert(client(Read, Write)).
dispatch_fd(Client) :-
client(Client, Write),
format(Write, 'You typed: ', []),
copy_stream(Client, Write),
( at_end_of_stream(Client)
-> format('Closing client ~w~n', [Client]),
close(Client),
close(Write),
retractall(client(Client, _))
; flush_output(Write)
).
/*******************************
* CLIENT *
*******************************/
client :-
client(3000).
client(Port) :-
tcp_socket(Socket),
tcp_connect(Socket, localhost:Port),
tcp_open_socket(Socket, In, Out),
format(Out, 'Hello World~n', []),
flush_output(Out),
copy_line(In, user_output),
close(In),
close(Out).
copy_line(In, Out) :-
get0(In, C0),
copy_line(C0, In, Out).
copy_line(10, _, _) :- !.
copy_line(C, In, Out) :-
put(Out, C),
get0(In, C2),
copy_line(C2, In, Out).

View File

@ -1,522 +0,0 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2004-05-31.23
# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by `PROGRAMS ARGS'.
object Object file output by `PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputing dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit 0
;;
-v | --v*)
echo "depcomp $scriptversion"
exit 0
;;
esac
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> $depfile
echo >> $depfile
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> $depfile
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts `$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
tmpdepfile="$stripped.u"
if test "$libtool" = yes; then
"$@" -Wc,-M
else
"$@" -M
fi
stat=$?
if test -f "$tmpdepfile"; then :
else
stripped=`echo "$stripped" | sed 's,^.*/,,'`
tmpdepfile="$stripped.u"
fi
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
if test -f "$tmpdepfile"; then
outname="$stripped.o"
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
# Dependencies are output in .lo.d with libtool 1.4.
# With libtool 1.5 they are output both in $dir.libs/$base.o.d
# and in $dir.libs/$base.o.d and $dir$base.o.d. We process the
# latter, because the former will be cleaned when $dir.libs is
# erased.
tmpdepfile1="$dir.libs/$base.lo.d"
tmpdepfile2="$dir$base.o.d"
tmpdepfile3="$dir.libs/$base.d"
"$@" -Wc,-MD
else
tmpdepfile1="$dir$base.o.d"
tmpdepfile2="$dir$base.d"
tmpdepfile3="$dir$base.d"
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
if test -f "$tmpdepfile1"; then
tmpdepfile="$tmpdepfile1"
elif test -f "$tmpdepfile2"; then
tmpdepfile="$tmpdepfile2"
else
tmpdepfile="$tmpdepfile3"
fi
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no
for arg in "$@"; do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix="`echo $object | sed 's/^.*\././'`"
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
"$@" || exit $?
IFS=" "
for arg
do
case "$arg" in
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

View File

@ -1,210 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemaker@uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2008, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <errno.h>
#include <stdlib.h>
#include "clib.h"
#include <assert.h>
#include <string.h>
int
pl_error(const char *pred, int arity, const char *msg, int id, ...)
{ fid_t fid;
term_t except, formal, swi;
int rc;
va_list args;
if ( !(fid=PL_open_foreign_frame()) )
return FALSE;
except = PL_new_term_ref();
formal = PL_new_term_ref();
swi = PL_new_term_ref();
va_start(args, id);
switch(id)
{ case ERR_ERRNO:
{ int err = va_arg(args, int);
const char *action = va_arg(args, const char *);
const char *type = va_arg(args, const char *);
term_t object = va_arg(args, term_t);
if ( !object )
object = PL_new_term_ref();
msg = strerror(err);
switch(err)
{ case ENOMEM:
case EAGAIN: /* fork(); might be other resource */
rc = PL_unify_term(formal,
CompoundArg("resource_error", 1),
AtomArg("no_memory"));
break;
case EACCES:
case EPERM:
{ rc = PL_unify_term(formal,
CompoundArg("permission_error", 3),
AtomArg(action),
AtomArg(type),
PL_TERM, object);
break;
}
case ENOENT:
case ESRCH:
{ rc = PL_unify_term(formal,
CompoundArg("existence_error", 2),
AtomArg(type),
PL_TERM, object);
break;
}
default:
rc = PL_unify_atom_chars(formal, "system_error");
break;
}
break;
}
case ERR_ARGTYPE:
{ int argn = va_arg(args, int); /* argument position (unused) */
term_t actual = va_arg(args, term_t);
atom_t expected = PL_new_atom(va_arg(args, const char*));
if ( PL_is_variable(actual) && expected != PL_new_atom("variable") )
rc = PL_unify_atom_chars(formal, "instantiation_error");
else
rc = PL_unify_term(formal,
CompoundArg("type_error", 2),
PL_ATOM, expected,
PL_TERM, actual);
break;
}
case ERR_TYPE:
{ term_t actual = va_arg(args, term_t);
atom_t expected = PL_new_atom(va_arg(args, const char*));
if ( PL_is_variable(actual) && expected != PL_new_atom("variable") )
rc = PL_unify_atom_chars(formal, "instantiation_error");
else
rc = PL_unify_term(formal,
CompoundArg("type_error", 2),
PL_ATOM, expected,
PL_TERM, actual);
break;
}
case ERR_DOMAIN:
{ term_t actual = va_arg(args, term_t);
atom_t expected = PL_new_atom(va_arg(args, const char*));
rc = PL_unify_term(formal,
CompoundArg("domain_error", 2),
PL_ATOM, expected,
PL_TERM, actual);
break;
}
case ERR_EXISTENCE:
{ const char *type = va_arg(args, const char *);
term_t obj = va_arg(args, term_t);
rc = PL_unify_term(formal,
CompoundArg("existence_error", 2),
PL_CHARS, type,
PL_TERM, obj);
break;
}
case ERR_PERMISSION:
{ term_t obj = va_arg(args, term_t);
const char *op = va_arg(args, const char *);
const char *objtype = va_arg(args, const char *);
rc = PL_unify_term(formal,
CompoundArg("permission_error", 3),
AtomArg(op),
AtomArg(objtype),
PL_TERM, obj);
break;
}
case ERR_NOTIMPLEMENTED:
{ const char *op = va_arg(args, const char *);
term_t obj = va_arg(args, term_t);
rc = PL_unify_term(formal,
CompoundArg("not_implemented", 2),
AtomArg(op),
PL_TERM, obj);
}
case ERR_RESOURCE:
{ const char *res = va_arg(args, const char *);
rc = PL_unify_term(formal,
CompoundArg("resource_error", 1),
AtomArg(res));
}
case ERR_SYNTAX:
{ const char *culprit = va_arg(args, const char *);
rc = PL_unify_term(formal,
CompoundArg("syntax_error", 1),
AtomArg(culprit));
}
default:
assert(0);
}
va_end(args);
if ( rc && (pred || msg) )
{ term_t predterm = PL_new_term_ref();
term_t msgterm = PL_new_term_ref();
if ( pred )
{ rc = PL_unify_term(predterm,
CompoundArg("/", 2),
AtomArg(pred),
IntArg(arity));
}
if ( msg )
{ rc = PL_put_atom_chars(msgterm, msg);
}
if ( rc )
rc = PL_unify_term(swi,
CompoundArg("context", 2),
PL_TERM, predterm,
PL_TERM, msgterm);
}
if ( rc )
rc = PL_unify_term(except,
CompoundArg("error", 2),
PL_TERM, formal,
PL_TERM, swi);
PL_close_foreign_frame(fid);
if ( rc )
return PL_raise_exception(except);
return rc;
}

View File

@ -1,42 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef H_ERROR_INCLUDED
#define H_ERROR_INCLUDED
#include <stdarg.h>
#define ERR_ERRNO -1
#define ERR_TYPE -2
#define ERR_ARGTYPE -3
#define ERR_DOMAIN -4
#define ERR_EXISTENCE -5
#define ERR_PERMISSION -6
#define ERR_NOTIMPLEMENTED -7
#define ERR_RESOURCE -8
#define ERR_SYNTAX -9
int pl_error(const char *name, int arity,
const char *msg, int id, ...);
#endif /*H_ERROR_INCLUDED*/

View File

@ -1,260 +0,0 @@
/* Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemaker@cs.vu.nl
WWW: http://www.swi-prolog.org
Copyright (C): 2002-2010, University of Amsterdam
Vu University Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <SWI-Prolog.h>
#include "clib.h"
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#ifdef __WINDOWS__
#define MAKE_FUNCTORS 1
#include <windows.h>
#include "win_error.c"
#define statstruct struct _stati64
#define statfunc _wstati64
/*#define HAVE_UTIME 1: Broken ...*/
#ifdef HAVE_UTIME
#include <sys/utime.h>
#define utimestruct _utimbuf
#define utimefunc _wutime
#endif
#define FCHAR wchar_t
#define PL_get_file_name PL_get_file_nameW
#else /*__WINDOWS__*/
#define statstruct struct stat
#define statfunc stat
#define utimestruct struct utimbuf
#define utimefunc utime
#define FCHAR char
#endif /*__WINDOWS__*/
static functor_t FUNCTOR_access1;
static functor_t FUNCTOR_modified1;
static functor_t FUNCTOR_changed1;
static atom_t ATOM_now;
static atom_t ATOM_hard;
static atom_t ATOM_symbolic;
/*******************************
* TIME *
*******************************/
static int
add_time_option(term_t list, functor_t f, time_t time)
{ term_t tail = PL_copy_term_ref(list);
term_t head = PL_new_term_ref();
while(PL_get_list(tail, head, tail))
{ if ( PL_unify_functor(head, f) )
{ term_t a = PL_new_term_ref();
return (PL_get_arg(1, head, a) &&
PL_unify_float(a, (double)time));
}
}
if ( PL_unify_list(tail, head, tail) )
return PL_unify_term(head, PL_FUNCTOR, f, PL_FLOAT, (double)time);
return FALSE;
}
static int
close_list(term_t list)
{ term_t tail = PL_copy_term_ref(list);
term_t head = PL_new_term_ref();
while(PL_get_list(tail, head, tail))
;
return PL_unify_nil(tail);
}
static int
get_time_option(term_t list, functor_t f, time_t def, time_t *tme)
{ term_t tail = PL_copy_term_ref(list);
term_t head = PL_new_term_ref();
while(PL_get_list(tail, head, tail))
{ if ( PL_is_functor(head, f) )
{ term_t a = PL_new_term_ref();
double f;
_PL_get_arg(1, head, a);
if ( !PL_get_float(a, &f) )
{ atom_t now;
if ( PL_get_atom(a, &now) && now == ATOM_now )
{ time(tme);
return TRUE;
} else
return pl_error(NULL, 0, NULL, ERR_TYPE, a, "time");
}
*tme = (long)f;
return TRUE;
}
}
*tme = def;
return TRUE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
set_file_time(+Spec, -Old, +New)
Query/set file-times.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static foreign_t
pl_set_time_file(term_t spec, term_t old, term_t new)
{ FCHAR *name;
statstruct sbuf;
if ( !PL_get_file_name(spec, &name, 0) )
return FALSE;
if ( statfunc(name, &sbuf) )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "stat", "file", spec);
add_time_option(old, FUNCTOR_access1, sbuf.st_atime);
add_time_option(old, FUNCTOR_modified1, sbuf.st_mtime);
add_time_option(old, FUNCTOR_changed1, sbuf.st_ctime);
close_list(old);
if ( !PL_get_nil(new) )
#ifdef HAVE_UTIME
{ utimestruct tbuf;
if ( !get_time_option(new, FUNCTOR_access1,
sbuf.st_atime, &tbuf.actime) )
return FALSE;
if ( !get_time_option(new, FUNCTOR_modified1,
sbuf.st_mtime, &tbuf.modtime) )
return FALSE;
if ( utimefunc(name, &tbuf) != 0 )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "set_time", "file", spec);
}
#else
return pl_error(NULL, 0, NULL, ERR_NOTIMPLEMENTED, "set_time", name);
#endif
return TRUE;
}
/*******************************
* LINK *
*******************************/
static foreign_t
pl_link_file(term_t from, term_t to, term_t how)
{ FCHAR *fname, *tname;
atom_t hname;
if ( !PL_get_file_name(from, &fname, PL_FILE_OSPATH) ||
!PL_get_file_name(to, &tname, PL_FILE_OSPATH) )
return FALSE;
if ( !PL_get_atom(how, &hname) )
return pl_error(NULL, 0, NULL, ERR_TYPE, how, "atom");
#ifdef __WINDOWS__
if ( hname == ATOM_hard )
{ if ( !CreateHardLinkW(tname, fname, NULL) )
return win_error("CreateHardLink");
} else if ( hname == ATOM_symbolic )
{ static int (*symlink)(wchar_t *new, wchar_t *existing, DWORD flags);
static int fetched = FALSE;
if ( !fetched )
{ HMODULE hmod = GetModuleHandle("kernel32.dll");
void *addr = GetProcAddress(hmod, "CreateSymbolicLink");
symlink = addr;
fetched = TRUE;
}
if ( !symlink )
return pl_error(NULL, 0, NULL, ERR_DOMAIN, how, "link_type");
if ( !(*symlink)(tname, fname, 0) )
return win_error("CreateSymbolicLink");
} else
return pl_error(NULL, 0, NULL, ERR_DOMAIN, how, "link_type");
#else /*__WINDOWS__*/
if ( hname == ATOM_hard )
{ if ( link(fname, tname) != 0 )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "link", "file", to);
} else if ( hname == ATOM_symbolic )
{ if ( symlink(fname, tname) != 0 )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "link", "file", to);
} else
return pl_error(NULL, 0, NULL, ERR_DOMAIN, how, "link_type");
#endif /*__WINDOWS__*/
return TRUE;
}
install_t
install_files()
{ FUNCTOR_access1 = PL_new_functor(PL_new_atom("access"), 1);
FUNCTOR_modified1 = PL_new_functor(PL_new_atom("modified"), 1);
FUNCTOR_changed1 = PL_new_functor(PL_new_atom("changed"), 1);
ATOM_now = PL_new_atom("now");
ATOM_hard = PL_new_atom("hard");
ATOM_symbolic = PL_new_atom("symbolic");
#ifdef __WINDOWS__
win_init_errors();
#endif
PL_register_foreign("set_time_file", 3, pl_set_time_file, 0);
PL_register_foreign("link_file", 3, pl_link_file, 0);
}

View File

@ -1,202 +0,0 @@
/* Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemaker@cs.vu.nl
WWW: http://www.swi-prolog.org
Copyright (C): 2002-2010, University of Amsterdam
Vu University Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(files_ex,
[ set_time_file/3, % +File, -OldTimes, +NewTimes
link_file/3, % +OldPath, +NewPath, +Type
relative_file_name/3, % +AbsPath, +RelTo, -RelPath
directory_file_path/3, % +Dir, +File, -Path
copy_file/2, % +From, +To
make_directory_path/1 % +Directory
]).
/** <module> Extended operations on files
This module provides additional operations on files. This covers both
more obscure and possible non-portable low-level operations and
high-level utilities.
*/
:- use_foreign_library(foreign(files), install_files).
%% set_time_file(+File, -OldTimes, +NewTimes) is det.
%
% Query and set POSIX time attributes of a file. Both OldTimes and
% NewTimes are lists of option-terms. Times are represented in
% SWI-Prolog's standard floating point numbers. New times may be
% specified as =now= to indicate the current time. Defined options
% are:
%
% * access(Time)
% Describes the time of last access of the file. This value
% can be read and written.
%
% * modified(Time)
% Describes the time the contents of the file was last
% modified. This value can be read and written.
%
% * changed(Time)
% Describes the time the file-structure itself was changed by
% adding (link()) or removing (unlink()) names.
%
% Below are some example queries. The first retrieves the
% access-time, while the second sets the last-modified time to the
% current time.
%
% ==
% ?- set_time_file(foo, [acess(Access)], []).
% ?- set_time_file(foo, [], [modified(now)]).
% ==
%
% @bug Setting times does not work on Windows.
%% link_file(+OldPath, +NewPath, +Type) is det.
%
% Create a link in the filesystem from NewPath to OldPath. Type
% defines the type of link and is one of =hard= or =symbolic=.
%
% With some limitations, these functions also work on Windows.
% First of all, the unerlying filesystem must support links. This
% requires NTFS. Second, symbolic links are only supported in
% Vista and later.
%
% @error domain_error(link_type, Type) if the requested link-type
% is unknown or not supported on the target OS.
%% relative_file_name(+Path:atom, +RelTo:atom, -RelPath:atom) is det.
%
% True when RelPath is a relative path to AbsPath, relative to
% RelTo. Path and RelTo are first handed to absolute_file_name/2,
% which makes the absolute *and* canonical. Below is an example:
%
% ==
% ?- relative_file_name('/home/janw/nice',
% '/home/janw/deep/dir/file', Path).
% Path = '../../nice'.
% ==
%
% @param All paths must be in canonical POSIX notation, i.e.,
% using / to separate segments in the path. See
% prolog_to_os_filename/2.
% @bug This predicate is defined as a _syntactical_ operation.
relative_file_name(Path, RelTo, RelPath) :-
absolute_file_name(Path, AbsPath),
absolute_file_name(RelTo, AbsRelTo),
atomic_list_concat(PL, /, AbsPath),
atomic_list_concat(RL, /, AbsRelTo),
delete_common_prefix(PL, RL, PL1, PL2),
to_dot_dot(PL2, DotDot, PL1),
atomic_list_concat(DotDot, /, RelPath).
delete_common_prefix([H|T01], [H|T02], T1, T2) :- !,
delete_common_prefix(T01, T02, T1, T2).
delete_common_prefix(T1, T2, T1, T2).
to_dot_dot([], Tail, Tail).
to_dot_dot([_], Tail, Tail) :- !.
to_dot_dot([_|T0], ['..'|T], Tail) :-
to_dot_dot(T0, T, Tail).
%% directory_file_path(+Directory, +File, -Path) is det.
%% directory_file_path(?Directory, ?File, +Path) is det.
%
% True when Path is the full path-name for File in Dir. This is
% comparable to atom_concat(Directory, File, Path), but it ensures
% there is exactly one / between the two parts. Notes:
%
% * In mode (+,+,-), if File is given and absolute, Path
% is unified to File.
% * Mode (-,-,+) uses file_directory_name/2 and file_base_name/2
directory_file_path(Dir, File, Path) :-
nonvar(Dir), nonvar(File), !,
( is_absolute_file_name(File)
-> Path = File
; sub_atom(Dir, _, _, 0, /)
-> atom_concat(Dir, File, Path)
; atomic_list_concat([Dir, /, File], Path)
).
directory_file_path(Dir, File, Path) :-
nonvar(Path), !,
( nonvar(Dir)
-> ( sub_atom(Dir, _, _, 0, /)
-> atom_concat(Dir, File, Path)
; atom_concat(Dir, /, TheDir),
atom_concat(TheDir, File, Path)
)
; nonvar(File)
-> atom_concat(Dir, File, Path)
; file_directory_name(Path, Dir),
file_base_name(Path, File)
).
directory_file_path(_, _, _) :-
throw(error(instantiation_error(_), _)).
%% copy_file(From, To) is det.
%
% Copy a file into a new file or directory. The data is copied as
% binary data.
copy_file(From, To) :-
destination_file(To, From, Dest),
setup_call_cleanup(open(Dest, write, Out, [type(binary)]),
copy_from(From, Out),
close(Out)).
copy_from(File, Stream) :-
setup_call_cleanup(open(File, read, In, [type(binary)]),
copy_stream_data(In, Stream),
close(In)).
destination_file(Dir, File, Dest) :-
exists_directory(Dir), !,
atomic_list_concat([Dir, File], /, Dest).
destination_file(Dest, _, Dest).
%% make_directory_path(+Dir) is det.
%
% Create Dir and all required components (like mkdir -p). Can
% raise various file-specific exceptions.
make_directory_path(Dir) :-
make_directory_path_2(Dir), !.
make_directory_path(Dir) :-
permission_error(create, directory, Dir).
make_directory_path_2(Dir) :-
exists_directory(Dir), !.
make_directory_path_2(Dir) :-
Dir \== (/), !,
file_directory_name(Dir, Parent),
make_directory_path_2(Parent),
make_directory(Dir).

View File

@ -1,395 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2007, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <SWI-Prolog.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <assert.h>
#include "form.h"
#ifdef __WINDOWS__
#include <io.h>
#endif
#include "error.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Breaks a string holding data from a WWW form into its values. Outputs a
sequence of NAME=VALUE commands for a shell.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
dehex(int chr)
{ chr &= 0xff;
if ( chr >= '0' && chr <= '9' )
return chr - '0';
if ( chr >= 'A' && chr <= 'F' )
return chr - 'A' + 10;
if ( chr >= 'a' && chr <= 'f' )
return chr - 'a' + 10;
return -1;
}
static size_t
form_argument_decode(const char *in, size_t inlen, char *out, size_t outlen)
{ const char *ein = in+inlen;
size_t written = 0;
for(; in < ein; in++)
{ switch(*in)
{ case '+':
if ( ++written < outlen )
*out++ = ' ';
break;
case '%':
if ( in+2 < ein )
{ int h1 = dehex(*(++in));
int h2 = dehex(*(++in));
if ( h1 < 0 || h2 < 0 )
return (size_t)-1;
if ( ++written < outlen )
*out++ = h1<<4|h2;
} else
return (size_t)-1; /* syntax error */
break;
default:
if ( ++written < outlen )
*out++ = *in;
break;
}
}
if ( written < outlen )
*out++ = '\0';
return written;
}
#define SHORTVALUE 512
int
break_form_argument(const char *formdata,
int (*func)(const char* name,
size_t namelen,
const char *value,
size_t valuelen,
void *closure),
void *closure)
{ while ( *formdata )
{ char value[SHORTVALUE];
char *eq = strchr(formdata, '=');
if ( eq )
{ size_t nlen = eq-formdata;
char *end;
size_t vlen;
eq++;
end = strchr(eq, '&');
if ( !end )
end = eq+strlen(eq); /* end of the string */
if ( (vlen=form_argument_decode(eq, end-eq, value, SHORTVALUE)) >= SHORTVALUE )
{ char *buf;
if ( (buf=malloc(vlen+1)) )
{ size_t vlen2 = form_argument_decode(eq, end-eq, buf, vlen+1);
int rc;
assert(vlen2 == vlen);
rc = (func)(formdata, nlen, buf, vlen2, closure);
free(buf);
if ( !rc )
return rc;
} else
return ERROR_NOMEM;
} else if ( vlen == (size_t)-1 )
{ return ERROR_SYNTAX_ERROR;
} else
{ int rc = (func)(formdata, nlen, value, vlen, closure);
if ( !rc )
return rc;
}
if ( *end )
formdata = end+1;
else
formdata = end;
}
}
return TRUE;
}
static char *
find_boundary(const char *data, const char *end, const char *boundary)
{ size_t blen = strlen(boundary);
while ( data < end &&
!(strncmp(data, boundary, blen) == 0) )
data++;
if ( data < end )
{ while(data[-1] == '-')
data--;
return (char *)data;
}
return NULL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Find a named attribute in a mime header of a multipart form
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static char *
attribute_of_multipart_header(const char *name, char *header, char *endheader)
{ char *value;
size_t nlen = strlen(name);
while( header < endheader &&
!(header[nlen] == '=' && strncmp(header, name, nlen) == 0) )
header++;
if ( header < endheader )
{ header += nlen+1;
if ( header[0] == '"' )
{ char *end;
value = ++header;
if ( (end = strchr(value, '"')) )
{ *end = '\0';
return value;
}
} else
{ char *end;
value = header;
for(end=header; *end && isalnum(*end&0xff); end++)
;
*end = '\0';
return value;
}
}
return NULL;
}
static char *
looking_at_blank_lines(const char *line, int n)
{ while(n-- > 0)
{ if ( (line[0] == '\r' && line[1] == '\n') )
line += 2;
else if ( line[0] == '\n' )
line += 1;
else
return NULL;
}
return (char *)line;
}
char *
next_line(const char *in)
{ if ( (in = strchr(in, '\n')) )
return (char *)(in+1);
return NULL;
}
int
break_multipart(char *formdata, size_t len,
const char *boundary,
int (*func)(const char *name,
size_t namelen,
const char *value,
size_t valuelen,
const char *filename,
void *closure),
void *closure)
{ char *enddata = formdata+len;
while(formdata < enddata)
{ char *header;
char *name, *filename;
char *data = NULL;
char *end;
if ( !(formdata=find_boundary(formdata, enddata, boundary)) ||
!(formdata=next_line(formdata)) )
break;
header = formdata;
/* find the end of the header */
for( ; formdata < enddata; formdata++ )
{ char *end;
if ( (end = looking_at_blank_lines(formdata, 2)) )
{ formdata[0] = '\0';
formdata = data = end;
break;
}
}
if ( !data )
break;
if ( !(name = attribute_of_multipart_header("name", header, data)) )
{ term_t t = PL_new_term_ref();
PL_put_atom_chars(t, "name");
return pl_error(NULL, 0, NULL, ERR_EXISTENCE, "field", t);
}
filename = attribute_of_multipart_header("filename", header, data);
if ( !(formdata=find_boundary(data, enddata, boundary)) )
break;
end = formdata-1;
if ( end[-1] == '\r' )
end--;
end[0] = '\0';
if ( !(func)(name, strlen(name), data, end-data, filename, closure) )
return FALSE;
}
return TRUE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Get the raw data from the standard input or QUERY_STRING. If `lenp' is
provided, it is filled with the length of the contents. The input value
for lenp is the maximum acceptable content-length.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int
get_raw_form_data(char **data, size_t *lenp, int *must_free)
{ char *method;
char *s;
if ( (method = getenv("REQUEST_METHOD")) &&
strcmp(method, "POST") == 0 )
{ char *lenvar = getenv("CONTENT_LENGTH");
char *q;
long len;
if ( !lenvar )
{ term_t env = PL_new_term_ref();
PL_put_atom_chars(env, "CONTENT_LENGTH");
return pl_error(NULL, 0, NULL, ERR_EXISTENCE, "environment", env);
}
len = atol(lenvar);
if ( len < 0 )
{ term_t t = PL_new_term_ref();
if ( !PL_put_integer(t, len) )
return FALSE;
return pl_error(NULL, 0, "< 0", ERR_DOMAIN, t, "content_length");
}
if ( lenp )
{ if ( *lenp && (size_t)len > *lenp )
{ term_t t = PL_new_term_ref();
char msg[100];
if ( !PL_put_integer(t, len) )
return FALSE;
sprintf(msg, "> %ld", *lenp);
return pl_error(NULL, 0, msg, ERR_DOMAIN, t, "content_length");
}
*lenp = len;
}
q = s = malloc(len+1);
if ( !q )
return pl_error(NULL, 0, NULL, ERR_RESOURCE, "memory");
while(len > 0)
{ int done;
while( (done=read(fileno(stdin), q, len)) > 0 )
{ q+=done;
len-=done;
}
if ( done < 0 )
{ int e;
term_t obj;
no_data:
e = errno;
obj = PL_new_term_ref();
free(s);
PL_put_nil(obj);
return pl_error(NULL, 0, NULL, ERR_ERRNO, e, "read", "cgi_data", obj);
}
}
if ( len == 0 )
{ *q = '\0';
*data = s;
*must_free = TRUE;
return TRUE;
} else
goto no_data;
} else if ( (s = getenv("QUERY_STRING")) )
{ if ( lenp )
*lenp = strlen(s);
*data = s;
*must_free = FALSE;
return TRUE;
} else
{ term_t env = PL_new_term_ref();
PL_put_atom_chars(env, "QUERY_STRING");
return pl_error(NULL, 0, NULL, ERR_EXISTENCE, "environment", env);
}
}

View File

@ -1,57 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define MAXNAME 256
#define ERROR_NAME_TOO_LONG -1
#define ERROR_SYNTAX_ERROR -2
#define ERROR_NOMEM -3
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
typedef struct
{ char *ptr;
char *name;
} form_arg;
/* form.c */
int break_form_argument(const char *formdata,
int (*func)(const char *name,
size_t namelen,
const char *value,
size_t valuelen,
void *closure), void *closure);
int break_multipart(char *formdata, size_t len,
const char *boundary,
int (*func)(const char *name,
size_t namelen,
const char *value,
size_t valuelen,
const char *filename,
void *closure),
void *closure);
int get_raw_form_data(char **data, size_t *lenp, int *must_free);

View File

@ -1,238 +0,0 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
tranformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View File

@ -1,3 +0,0 @@
This software is released under the GPL, version 2 (see COPYING.GPL).
Additionally, compiling, linking, and/or using the OpenSSL toolkit in
conjunction with this software is allowed.

View File

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,67 +0,0 @@
From mrsam@courier-mta.com Mon May 23 03:56:05 2005
Received: from mail.courier-mta.com [216.254.115.84]
by smtp.science.uva.nl with ESMTP (sendmail 8.11.6p2/config 11.35).
id j4N1u1l31610; Mon, 23 May 2005 03:56:01 +0200
Received: from localhost (localhost [127.0.0.1])
(uid 8)
by commodore.email-scan.com with local; Sun, 22 May 2005 21:56:05 -0400
id 0000000000137668.0000000042913835.00006534
X-IMAP-Sender: mrsam@courier-mta.com
References: <200505222138.13486.wielemak@science.uva.nl>
Message-ID: <cone.1116813365.632006.24916.500@commodore.email-scan.com>
X-Mailer: http://www.courier-mta.org/cone/
From: Sam Varshavchik <mrsam@courier-mta.com>
To: Jan Wielemaker <wielemak@science.uva.nl>
X-PGP-KEY: http://www.courier-mta.org/KEYS.bin
Subject: Re: Use of maildrop rfc822 and rfc2047 libraries in SWI-Prolog
Date: Sun, 22 May 2005 21:56:05 -0400
Mime-Version: 1.0
Content-Type: multipart/signed;
boundary="=_mimegpg-commodore.email-scan.com-24916-1116813365-0003";
micalg=pgp-sha1;
protocol="application/pgp-signature"
X-Virus-Scanned: by amavisd-new
X-Spam-Status: No, hits=0.0, required=5.0, tests=BAYES_50
X-Spam-Rating: 0
X-UID: 13043
X-Length: 2555
This is a MIME GnuPG-signed message. If you see this text, it means that
your E-mail or Usenet software does not support MIME signed messages.
--=_mimegpg-commodore.email-scan.com-24916-1116813365-0003
Content-Type: text/plain; format=flowed; charset="US-ASCII"
Content-Disposition: inline
Content-Transfer-Encoding: 7bit
Jan Wielemaker writes:
> Now the trouble is that your libraries are GPL, while the core of
> SWI-Prolog and all its core packages are LGPL. In theory, loading
> the mime library, which causes your code to be loaded as a shared
> object, turns the entire process with whatever the user has added
> to it to GPL. This is undesirable.
>
> I would like to ask permission to either distribute these libraries
> under the LGPL or make a statement that allows use with SWI-Prolog
> without turning everything to GPL.
The current versions of librfc822 and librfc2047 may be distributed under
the terms of LGPL 2.1 only as part of, and in conjunction with SWI-Prolog.
--=_mimegpg-commodore.email-scan.com-24916-1116813365-0003
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iD8DBQBCkTg1x9p3GYHlUOIRAnbaAJ9atylLK74/CO/oZ2x4U0hZPhLYaACdH/Ub
ocEI7RDpO9vBq26cnyw1UFE=
=mXhm
-----END PGP SIGNATURE-----
--=_mimegpg-commodore.email-scan.com-24916-1116813365-0003--

View File

@ -1,16 +0,0 @@
This directory contains the subdirectories rfc822 and rfc2045 from the
maildrop system (version 1.5.3). They are included with the SWI-Prolog
package source to simplify building the package.
maildrop is written by:
Sam Varshavchik <mrsam@courier-mta.com>
Double Precision, Inc.
PO Box 637
Harriman, NY 10926-0637
Although initially distributed under GPL, Sam gave permission to
redistribute the library with SWI-Prolog under the LGPL. See file
LICENSE.MAIL in this directory.

View File

@ -1,44 +0,0 @@
################################################################
# Makefile for librfc2045.a
#
# Author: Jan Wielemaker (wielemak@science.uva.nl)
################################################################
CC=@CC@
CFLAGS=@MAILDROP_CFLAGS@ @DEFS@
LIBS=@LIBS@
AR=@AR@
RANLIB=@RANLIB@
srcdir=@srcdir@
OBJ= rfc2045.o rfc2045acchk.o rfc2045acprep.o \
rfc2045appendurl.o rfc2045cdecode.o rfc2045decode.o \
rfc2045enomem.o \
rfc2045_base64encode.o rfc2045_fromfd.o \
rfc2045find.o rfc2045mkboundary.o rfc2045rewrite.o \
rfc2045tryboundary.o rfc2045xdump.o
all: librfc2045.a
librfc2045.a: $(OBJ)
rm -f librfc2045.a
$(AR) r librfc2045.a $(OBJ)
$(RANLIB) librfc2045.a
#
# find out how to generate .o files from $(scrdir)
#
%.o: $(srcdir)/%.c
$(CC) -c $(CFLAGS) $< -o $@
################################################################
# Clean
################################################################
clean:
rm -f $(OBJ) *~ *.o *% a.out core config.log
distclean: clean
rm -f Makefile config.status config.h librfc2045.a
rm -f rfc2045charset.h stamp-h1
rm -rf autom4te.cache

View File

@ -1,35 +0,0 @@
# Destinations. Please edit
prefix=c:\Documents and Settings\jan
LIBDIR=$(prefix)\lib64
INCDIR=$(prefix)\include
CC=cl.exe
AR=lib.exe
CFLAGS=/MD /W3 /O2 /EHsc /DNDEBUG /D__WINDOWS__ /I.. /nologo /c
OUT=rfc2045.lib
OBJ= rfc2045.obj rfc2045acchk.obj rfc2045acprep.obj \
rfc2045appendurl.obj rfc2045cdecode.obj rfc2045decode.obj \
rfc2045enomem.obj \
rfc2045_base64encode.obj rfc2045_fromfd.obj \
rfc2045find.obj rfc2045mkboundary.obj rfc2045rewrite.obj \
rfc2045tryboundary.obj rfc2045xdump.obj
.c.obj:
@$(CC) $(CFLAGS) /Fo$@ $<
$(OUT): $(OBJ)
del $@
$(AR) /out:$@ /nologo $(OBJ)
install: $(OUT)
copy $(OUT) "$(LIBDIR)"
copy rfc2045.h "$(INCDIR)"
clean::
del *~ *.obj
distclean: clean
del $(OUT)

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +0,0 @@
dnl $Id$
dnl
dnl Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
dnl distribution information.
AC_INIT(rfc2045.c)
AC_PREREQ([2.50])
AC_CONFIG_HEADER(config.h)
AC_SUBST(AR)
dnl Checks for programs.
AC_PROG_CC
AC_CHECK_PROG(AR, ar, ar, ar)
AC_PROG_RANLIB
AC_USE_SYSTEM_EXTENSIONS
if test "$GCC" = yes ; then
CXXFLAGS="$CXXFLAGS -Wall"
CFLAGS="$CFLAGS -Wall"
fi
dnl Checks for libraries.
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(unistd.h sys/wait.h strings.h)
AC_CACHE_CHECK([for missing gethostname prototype],rfc2045_cv_SYS_GETHOSTNAME,
AC_TRY_COMPILE([
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
extern int gethostname(int,int);
],[
],rfc2045_cv_SYS_GETHOSTNAME=yes,rfc2045_cv_SYS_GETHOSTNAME=no
)
)
if test $rfc2045_cv_SYS_GETHOSTNAME = "no"
then
AC_DEFINE_UNQUOTED(HAS_GETHOSTNAME, 1,
[Define if gethostname() is provided])
fi
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_PID_T
dnl Checks for library functions.
AC_CHECK_FUNC(strncasecmp,,CFLAGS="$CFLAGS -Dstrncasecmp=strnicmp")
AC_CHECK_FUNC(strcasecmp,,CFLAGS="$CFLAGS -Dstrcasecmp=stricmp")
AC_ARG_WITH(package, [], package="$withval",
[
package="$PACKAGE"
ac_configure_args="$ac_configure_args --with-package=$PACKAGE"
])
AC_ARG_WITH(version, [], version="$withval",
[
version="$VERSION"
ac_configure_args="$ac_configure_args --with-version=$VERSION"
])
AC_DEFINE_UNQUOTED(RFC2045PKG,"$package",[Specify package])
AC_DEFINE_UNQUOTED(RFC2045VER,"$version",[Specify version])
AC_ARG_ENABLE(mimecharset,
[ --enable-mimecharset=charset Default MIME charset to set on new messages],
RFC2045CHARSET="$enableval", RFC2045CHARSET="us-ascii")
CFLAGS="$CFLAGS -I${srcdir}/.."
AC_SUBST(rfc822includedir)
AC_SUBST(RFC2045CHARSET)
AC_OUTPUT(Makefile rfc2045charset.h)

File diff suppressed because it is too large Load Diff

View File

@ -1,362 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>makemime - MIME utility</title>
<!-- $Id$ -->
<!-- SECTION 1 -->
<meta http-equiv="Content-Type" content="text/html">
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B"
alink="#FF0000">
<h1>makemime - MIME utility</h1>
<h2>SYNOPSIS</h2>
<code>makemime [options]</code>
<p><code>makemime @<i>file</i></code></p>
<h2>DESCRIPTION</h2>
<p>The <i>makemime</i> tool creates MIME-encoded messages of arbitrary
complexity. <i>makemime</i> reads one or more individual files, encodes them
appropriately, adds basic MIME headers, and adds additional headers specified
via command line options. The result is saved to another file or standard
output. Complex MIME-encoded messages are created by using options that direct
<i>makemime</i> to run additional instances of itself, as child processes. The
child processes create individual parts of a complex MIME message, then the
parent <i>makemime</i> process combines them together.</p>
<p>In simple cases, options for <i>makemime</i> are specified directly on the
command line. @<i>file</i> specifies that options will be read from a file.
"@&n" reads options from a pipe on file descriptor #n. "@-" is a shortcut for
"@&0", which reads options from standard input.</p>
<p>When options are read from a file or a pipe, each option must be on a line
by itself. If an option requires an argument, the argument must follow on the
next line.</p>
<p>For readability, leading whitespace on each line is deleted when options
are read from a file or a pipe. Empty lines are also ignored, as well as lines
that begin with the '#' character.</p>
<p>Options and their arguments may contain characters that are special
characters to the shell, such as '(' and ')'. These characters must be
backslashed when specified on the command line, to avoid their special meaning
to the shell. These characters MUST NOT be backslashed when options are read
from a file or a pipe. Similarly, the contents of most headers nearly always
include spaces. Therefore they must be quoted when specified on the command
line. Header contents MUST NOT be quoted when options come from a file or a
pipe.</p>
<p><i>makemime</i> reads the contents to be encoded into a MIME message from
other files. Those files can also be pipes. It is possible to supply both the
options and a file from the same pipe, by terminating the list of option with
a line containing the single character "-". The remainder of the pipe will be
available to be used as an input file (which must be explicitly specified via
some other option). Of course, only one input file can come from a single
pipe.</p>
<h3>MIME overview</h3>
<p>A MIME message consists of one or several MIME sections. MIME headers
specify how multiple MIME sections are to be interpreted as a whole (whether
they are attached together, or whether they are alternative representations of
the same object, or something even more esoteric). This manual page gives a
very brief, terse, overview of basic MIME concepts. The description is biased
towards describing the functionality of the <i>makemime</i> utility. The
complete description of MIME encoding is found in RFCs 2045 through 2048,
where a formal definition is found.</p>
<p>Each file in a MIME message is encoded as a single MIME section. A MIME
section consists of at least one header line, "Content-Type". The
"Content-Type" headers gives the type of the data contained in the file. Other
header lines may also be present. Their relative order does not matter. MIME
headers are followed by a blank line, then the contents of the file, encoded
appropriately. All MIME sections generated by <i>makemime</i> will always
contain another header, "Content-Transfer-Encoding". This header gives the
encoding method used for the file.</p>
<p>The encoding method defaults to "7bit" if this header is absent. 7bit
encoding is only suitable for plain text messages in the US-ASCII character
set. The "8bit" encoding method is used by plain text messages in other
character sets which contain high-bit characters, with their 8th bit set. An
alternative to 8bit encoding is "quoted-printable". The "base64" encoding
method is used for files containing binary data.</p>
<p>MIME sections that contain text messages have their "Content-Type" header
set to "text/plain"; or "text/html" for HTML messages. There are also several
other, rare, content types that can be used. MIME sections that contain other
kinds of data will use some other, appropriate Content-Type header, such as
"image/gif", or "audio/x-wav".</p>
<p>MIME sections that contain textual content may use the base64 encoding
method, they are not required to use 7bit, 8bit, or quoted-printable.
"text/pdf" sections, that contain PDF files, typically consist of binary data,
and must use base64 encoding. Consequently, MIME sections that typically
contain binary data, such as image/gif and audio/x-wav, are free to use other
encoding methods besides base64, as long as all the data can be represented by
printable characters (but, in practice, that never happens).</p>
<p>MIME sections may also contain other, optional, headers such as
"Content-Disposition", "Content-ID", and "Content-Name". Consult the
appropriate RFCs for the specific usage of these headers. These headers can be
added by <i>makemime</i> by using the -a option, as described below. These
headers play no part in creating the overall structure of a MIME-encoded
message, and <i>makemime</i> does not care much about these headers. It simply
includes them, and their content, upon request.</p>
<p>Multiple files are encoded into a single message by initially creating a
MIME section for each file, and then creating a single MIME section that
contains other MIME sections. A "multipart/mixed" MIME section contains a
collection of MIME sections that represent different objects, attached
together. A "multipart/alternative" MIME section contains a collection of MIME
sections which are alternative representations of the same object, such as an
HTML and a plain text version of the same message. Other "multipart" MIME
sections also exist, and their usage is defined by their respective RFCs.</p>
<h3>Creating a single MIME section</h3>
<pre> makemime -c "type" [-e "encoding"] [-o file] \
[-a "header: value"] [-a "header: value"] file</pre>
<p>The -c option reads <i>file</i>, encodes it appropriately, adds a
"Content-Type" and "Content-Transfer-Encoding" MIME headers, then writes the
result to standard output. <i>type</i> can be any valid MIME type, except for
multipart. <i>file</i> can be "-", which specifies standard input. <i>file</i>
can be "&n" to read the file from file descriptor #n.</p>
<p>The optional <i>encoding</i> argument should be specified. It's more
efficient to do so. <i>encoding</i> must be one of the following: 7bit, 8bit,
quoted-printable, or base64.</p>
<p>If <i>encoding</i> is not specified, <i>makemime</i> reads the <i>file</i>
twice - once to select the best encoding method, and the second time to encode
it. If <i>file</i> is a pipe <i>makemime</i> will be forced to create a
temporary file, which is less efficient if the <i>file</i> is large. However
letting <i>makemime</i> pick the encoding is probably more convenient if files
are relatively small.</p>
<p>By default the encoded MIME section is written to standard output. The -o
option writes the MIME section to a <i>file</i>. <i>file</i> can be "&n",
which writes the MIME section to a pipe on file descriptor #n.</p>
<p><i>makemime</i> does not generate any other headers. Particularly, the
"Mime-Version" header (and others) is required to send a MIME message via
E-mail. Additional headers are specified by the -a option, which may be used
multiple times to insert multiple headers. <i>makemime</i> doesn't do anything
with them except to insert the headers into the generated MIME section.</p>
<p>Note that "Mime-Version" is only required for the top level MIME section.
This header is not required for individual MIME sections that are later
combined into a multipart MIME collection.</p>
<p>Note that the -c option is required to be listed first, the remaining
options must follow the -c option.</p>
<h3>Creating a multipart MIME collection</h3>
<pre> makemime -m "type" [-e "encoding"] [-o file] \
[-a "header: value"] [-a "header: value"] file</pre>
<p>The -m option is identical in usage to the -c option, except for three
differences.</p>
<p><i>type</i> must be either "multipart/mixed", "multipart/alternative", or
some other MIME multipart content type. Additionally, "encoding" can only be
"7bit" or "8bit", and will default to "8bit" if not specified. Finally,
<i>file</i> must be a MIME-encoded section, NOT a regular file. Usually
<i>file</i> is also created by <i>makemime</i> (it can also be a pipe, like
the -c option), but it can be created via any other means.</p>
<p>The -m option creates an initial multipart MIME collection, that contains
only one MIME section, taken from <i>file</i>. The collection is written to
standard output, or the pipe or the file specified by the -o option. The -j
option is used to add additional MIME sections to this collection.</p>
<h3>Creating a multipart MIME section</h3>
<pre> makemime -j file1 [-o file] file2</pre>
<p>This option appends a MIME section to an existing MIME collection.
<i>file1</i> contains a MIME collection that's been created by the -m option.
<i>file2</i> must contain a MIME section that's been created by the -c option.
The MIME section in <i>file2</i> is appended after the last MIME section in
<i>file1</i>. The result is written to standard output or the file specified
by the -o option.</p>
<p><i>file1</i> and/or <i>file2</i> can be "&n", which reads the corresponding
file from a pipe on the indicated file descriptor. The -o option, as always,
can also specify a file descriptor.</p>
<p><i>file1</i> and <i>file2</i> should ideally be created by <i>makemime</i>
as well. It's also possible to use files created by other software, but with
some degree of care. <i>makemime</i> is not intended to be a MIME parser, but
a MIME generator. However some amount of MIME parsing is necessary to append a
MIME section to an existing MIME collection. <i>makemime</i>'s parsing does a
sufficient job to append a new section to a MIME collection, as long as the
MIME headers in the MIME collections are straightforward. Very convoluted MIME
headers may confuse <i>makemime</i>, and it may not be able to handle
them.</p>
<h3>Recursive MIME collections</h3>
<p>MIME collection may contain other MIME collections as well as MIME
sections. The -m and the -j option may use a multipart MIME collection in
place of a MIME section automatically, simply because a multipart MIME
collection is just a special type of a MIME section. The following example
encodes a text message that can be alternatively represented as HTML or plain
text, with some additional attachments:</p>
<p>1. Create a MIME collection containing a text/plain and a text/html MIME
section.</p>
<p>2. Create a MIME collection consisting of the MIME section generated in
step one, plus additional MIME sections containing other attachments.</p>
<p>For example:</p>
<pre> # Take two files containing the text and the html version of a message, and
# add MIME headers to them.
makemime -c "text/plain; charset=iso-8859-1" -o tmp1.txt msg.txt
makemime -c "text/html; charset=iso-8859-1" -o tmp1.html msg.html
# Combine the result into a multipart/alternative collection
makemime -m "multipart/alternative" -a "Content-Disposition: inline" \
-o tmp.ma1 tmp1.txt
makemime -j tmp.ma1 -o tmp.ma2 tmp1.html
# Add MIME headers to an image attachment.
makemime -c "image/gif" -a "Content-Disposition: attachment" \
-o tmp2.gif attachment.gif
# Create the final multipart/mixed collection
makemime -m "multipart/mixed" -a "Mime-Version: 1.0" \
-o tmp.mm1 tmp.ma2
makemime -j tmp.mm1 -o output.msg tmp2.gif</pre>
<p><i>output.msg</i> now contains the complete MIME collection. Just add the
subject, from, and to headers (can also be done by additional -a options, of
course), and send it on its way.</p>
<h3>Building complex MIME encodings</h3>
<p>There are several different ways to build complete MIME encodings from
multiple MIME sections. One way is to use temporary files to create MIME
sections, then combine them together into a single MIME collection. A slightly
more complicated approach involves setting up pipes between multiple makemime
processes, in order to avoid using temporary files.</p>
<p>This can be done manually, by hand. It is also possible to have
<i>makemime</i> do this automatically. <i>makemime</i> will set up these pipes
and run multiple instances of itself to create a single MIME collection, with
multiple attachments of arbitrary complexity.</p>
<p>Any file that's read by the -c, -m, and -j options (-o specifies a file to
create, and doesn't count) may be replaced by a single argument containing a
left parenthesis, additional options, then a single argument containing a
right parenthesis. A single invocation of <i>makemime</i> can only use one -c,
-m, or -j option. However, another -c, -m, or -j option may be specified
inside the left and the right parenthesis, and its output is used in place of
the file it replaced. In the previous example the third and the fourth
invocation of <i>makemime</i> can be replaced with the following command:</p>
<pre> makemime -j \( \
-m "multipart/alternative" \
-a "Content-Disposition: inline" tmp1.txt \
\) -o tmp.ma2 \
tmp1.html</pre>
<p>Note that the parenthesis must be backslashed, to avoid their special
meaning to the shell. An equivalent argument file would have the following
contents:</p>
<pre> -j
(
-m
multipart/alternative
-a
Content-Disposition: inline
tmp1.txt
)
-o
tmp.ma2
tmp1.html</pre>
<p>These constructs can be arbitrarily nested, and are limited by the amount
of available memory and resources. The entire sequence in the previous
section is equivalent to the following command:</p>
<pre> makemime -j \
\( \
-m "multipart/mixed" \
-a "Mime-Version: 1.0" \
\( \
-j \
\( \
-m "multipart/alternative" \
-a "Content-Disposition: inline" \
\( \
-c "text/plain; charset=iso-8859-1" \
msg.txt \
\) \
\) \
\( \
-c "text/html; charset=iso-8859-1" \
msg.html \
\) \
\) \
\) \
-o output.msg \
\( \
-c "image/gif" \
-a "Content-Disposition: attachment" \
attachment.gif \
\)</pre>
<p>An equivalent argument file would be:</p>
<pre> -j
(
-m
multipart/mixed
-a
Mime-Version: 1.0
(
-j
(
-m
multipart/alternative
-a
Content-Disposition: inline
(
-c
text/plain; charset=iso-8859-1
msg.txt
)
)
(
-c
text/html; charset=iso-8859-1
msg.html
)
)
)
-o
output.msg
(
-c
image/gif
-a
Content-Disposition: attachment
attachment.gif
)</pre>
<h2>SEE ALSO</h2>
<a href="maildrop.html">maildrop(1)</a>, <a
href="maildropfilter.html">maildropfilter(1)</a>, <a
href="reformail.html">reformail(1)</a>, <a
href="reformime.html">reformime(1)</a>, egrep(1), grep(1), <a
href="courier.html">courier(8)</a>, sendmail(8), <a
href="http://www.rfc-editor.org/rfc/rfc2045.txt">RFC 2045</a>, <a
href="http://www.rfc-editor.org/rfc/rfc2046.txt">RFC 2046</a>, <a
href="http://www.rfc-editor.org/rfc/rfc2047.txt">RFC 2047</a>, <a
href="http://www.rfc-editor.org/rfc/rfc2048.txt">RFC 2048</a>.</body>
</html>

View File

@ -1,962 +0,0 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdlib.h>
#include <ctype.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include "rfc2045.h"
#include "rfc822/rfc2047.h"
#include "rfc2045charset.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
//#include "numlib/numlib.h"
#if HAS_GETHOSTNAME
#else
int gethostname(const char *, size_t);
#endif
static const char rcsid[]="$Id$";
void rfc2045_error(const char *errmsg)
{
fprintf(stderr, "reformime: %s\n", errmsg);
exit(1);
}
static void do_print_structure(struct rfc2045 *p, struct rfc2045id *id, void *ptr)
{
p=p;
ptr=p;
while (id)
{
printf("%d%c", id->idnum, id->next ? '.':'\n');
id=id->next;
}
}
static int decode_to_file(const char *p, size_t n, void *ptr)
{
FILE *fp=(FILE *)ptr;
while (n)
{
--n;
if (putc(*p++, fp) == -1)
{
perror("write");
exit(1);
}
}
return (0);
}
void usage()
{
fprintf(stderr, "Usage: reformime [options]\n");
fprintf(stderr, " -d - parse a delivery status notification.\n");
fprintf(stderr, " -e - extract contents of MIME section.\n");
fprintf(stderr, " -x - extract MIME section to a file.\n");
fprintf(stderr, " -X - pipe MIME section to a program.\n");
fprintf(stderr, " -i - show MIME info.\n");
fprintf(stderr, " -s n.n.n.n - specify MIME section.\n");
fprintf(stderr, " -r - rewrite message, filling in missing MIME header.\n");
fprintf(stderr, " -r7 - also convert 8bit/raw encoding to quoted-printable, if possible.\n");
fprintf(stderr, " -r8 - also convert quoted-printable encoding to 8bit, if possible.\n");
fprintf(stderr, " -c charset - when rewriting, specify default charset.\n");
fprintf(stderr, " -m [file] [file]... - create a MIME message digest.\n");
exit(1);
}
static char *tempname(const char *tempdir)
{
char pidbuf[NUMBUFSIZE], timebuf[NUMBUFSIZE], hostnamebuf[256];
static unsigned counter=0;
time_t t;
char *p;
str_pid_t(getpid(), pidbuf);
time(&t);
str_time_t(t, timebuf);
hostnamebuf[sizeof(hostnamebuf)-1]=0;
if (gethostname(hostnamebuf, sizeof(hostnamebuf)))
hostnamebuf[0]=0;
p=malloc(strlen(tempdir)+strlen(pidbuf)+strlen(timebuf)+
strlen(hostnamebuf)+100);
if (!p) return (0);
sprintf(p, "%s/%s.%s-%u.%s", tempdir, timebuf, pidbuf, counter++,
hostnamebuf);
return (p);
}
struct rfc2045 *read_message()
{
char buf[BUFSIZ];
struct rfc2045 *p=rfc2045_alloc_ac();
FILE *tempfp=0;
if (fseek(stdin, 0L, SEEK_END) < 0 ||
fseek(stdin, 0L, SEEK_SET) < 0) /* Pipe, save to temp file */
{
tempfp=tmpfile();
}
while (fgets(buf, sizeof(buf), stdin))
{
int l=strlen(buf);
rfc2045_parse(p, buf, l);
if (tempfp && fwrite(buf, l, 1, tempfp) != 1)
{
perror("fwrite");
exit(1);
}
}
if (tempfp) /* Replace stdin */
{
close(0);
dup(fileno(tempfp));
fclose(tempfp);
}
return (p);
}
void print_structure(struct rfc2045 *p)
{
rfc2045_decode(p, &do_print_structure, 0);
}
static void notfound(const char *p)
{
fprintf(stderr, "reformime: MIME section %s not found.\n", p);
exit(1);
}
static void do_print_info(struct rfc2045 *s)
{
const char *content_type, *transfer_encoding, *charset;
off_t start, end, body;
const char *disposition;
const char *disposition_name;
const char *disposition_filename;
const char *content_name;
off_t nlines, nbodylines;
const char *p;
rfc2045_mimeinfo(s, &content_type, &transfer_encoding, &charset);
rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines);
rfc2045_dispositioninfo(s, &disposition, &disposition_name,
&disposition_filename);
content_name=rfc2045_contentname(s);
printf("content-type: %s\n", content_type);
if (content_name)
{
char *s=rfc2047_decode_simple(content_name);
if (!s)
{
perror("rfc2047_decode_simple");
exit(1);
}
printf("content-name: %s\n", s);
free(s);
}
printf("content-transfer-encoding: %s\n", transfer_encoding);
printf("charset: %s\n", charset);
if (disposition && *disposition)
printf("content-disposition: %s\n", disposition);
if (disposition_name && *disposition_name)
{
char *s=rfc2047_decode_simple(disposition_name);
if (!s)
{
perror("rfc2047_decode_simple");
exit(1);
}
printf("content-disposition-name: %s\n", s);
free(s);
}
if (disposition_filename && *disposition_filename)
{
char *s=rfc2047_decode_simple(disposition_filename);
if (!s)
{
perror("rfc2047_decode_simple");
exit(1);
}
printf("content-disposition-filename: %s\n", s);
free(s);
}
if (*(p=rfc2045_content_id(s)))
printf("content-id: <%s>\n", p);
if (*(p=rfc2045_content_description(s)))
{
char *s=rfc2047_decode_simple(p);
if (!s)
{
perror("rfc2047_decode_simple");
exit(1);
}
printf("content-description: %s\n", s);
free(s);
}
if (*(p=rfc2045_content_language(s)))
printf("content-language: %s\n", p);
if (*(p=rfc2045_content_md5(s)))
printf("content-md5: %s\n", p);
printf("starting-pos: %lu\n", (unsigned long)start);
printf("starting-pos-body: %lu\n", (unsigned long)body);
printf("ending-pos: %lu\n", (unsigned long)end);
printf("line-count: %lu\n", (unsigned long)nlines);
printf("body-line-count: %lu\n", (unsigned long)nbodylines);
}
static void do_print_info_multiple(struct rfc2045 *p, struct rfc2045id *id,
void *ptr)
{
printf("section: ");
do_print_structure(p, id, ptr);
do_print_info(p);
printf("\n");
}
void print_info(struct rfc2045 *p, const char *mimesection)
{
struct rfc2045 *s;
if (mimesection)
{
s=rfc2045_find(p, mimesection);
if (!s)
notfound(mimesection);
printf("section: %s\n", mimesection);
do_print_info(s);
return;
}
rfc2045_decode(p, &do_print_info_multiple, 0);
}
static void do_print_section(struct rfc2045 *s, FILE *fp)
{
off_t start, end, body;
off_t nlines;
off_t nbodylines;
rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines);
if (fseek(stdin, body, SEEK_SET) == -1)
{
perror("fseek");
exit(1);
}
rfc2045_cdecode_start(s, &decode_to_file, fp);
while (body < end)
{
char buf[BUFSIZ];
size_t n=sizeof(buf);
if ((off_t)n > end-body) n=end-body;
n=fread(buf, 1, n, stdin);
if (n == 0)
{
perror("fread");
exit(1);
}
rfc2045_cdecode(s, buf, n);
body += n;
}
rfc2045_cdecode_end(s);
}
void print_decode(struct rfc2045 *p, const char *mimesection)
{
struct rfc2045 *s;
if (!mimesection)
usage();
s=rfc2045_find(p, mimesection);
if (!s)
notfound(mimesection);
do_print_section(s, stdout);
}
void rewrite(struct rfc2045 *p, int rwmode)
{
rfc2045_ac_check(p, rwmode);
if (rfc2045_rewrite(p, fileno(stdin), fileno(stdout),
"reformime (" RFC2045PKG " " RFC2045VER ")"))
{
perror("reformime");
exit(1);
}
}
static char *get_suitable_filename(struct rfc2045 *r, const char *pfix,
int ignore_filename)
{
const char *disposition_s;
const char *disposition_name_s;
const char *disposition_filename_s;
char *filename_buf;
const char *content_name_s;
char *p, *q;
char *dyn_disp_name=0;
rfc2045_dispositioninfo(r, &disposition_s, &disposition_name_s,
&disposition_filename_s);
content_name_s=rfc2045_contentname(r);
if (!disposition_filename_s || !*disposition_filename_s)
disposition_filename_s=disposition_name_s;
if (!disposition_filename_s || !*disposition_filename_s)
disposition_filename_s=content_name_s;
filename_buf=rfc2047_decode_simple(disposition_filename_s);
if (!filename_buf)
{
perror("rfc2047_decode_simple");
exit(1);
}
if (strlen(filename_buf) > 32)
{
p=filename_buf;
q=filename_buf + strlen(filename_buf)-32;
while ( (*p++ = *q++) != 0)
;
}
disposition_filename_s=filename_buf;
if (ignore_filename)
{
char numbuf[NUMBUFSIZE];
static size_t counter=0;
const char *p=str_size_t(++counter, numbuf);
dyn_disp_name=malloc(strlen(disposition_filename_s)
+ strlen(p)+2);
if (!dyn_disp_name)
{
perror("malloc");
exit(1);
}
disposition_filename_s=strcat(strcat(strcpy(
dyn_disp_name, p), "-"),
disposition_filename_s);
}
else if (!disposition_filename_s || !*disposition_filename_s)
{
dyn_disp_name=tempname(".");
disposition_filename_s=dyn_disp_name+2; /* Skip over ./ */
}
p=malloc((pfix ? strlen(pfix):0)+strlen(disposition_filename_s)+1);
if (!p)
{
perror("malloc");
exit(1);
}
*p=0;
if (pfix) strcpy(p, pfix);
q=p+strlen(p);
for (strcpy(q, disposition_filename_s); *q; q++)
if (!isalnum(*q) && *q != '.' && *q != '-')
*q='_';
if (dyn_disp_name) free(dyn_disp_name);
if (!pfix)
{
const char *content_type_s;
const char *content_transfer_encoding_s;
const char *charset_s;
int c;
static char filenamebuf[256];
char *t;
FILE *tty;
if ((tty=fopen("/dev/tty", "r+")) == 0)
{
perror("/dev/tty");
exit(1);
}
rfc2045_mimeinfo(r, &content_type_s,
&content_transfer_encoding_s, &charset_s);
fprintf (tty, "Extract %s? ", content_type_s);
fflush(tty);
c=getc(tty);
if (c != '\n' && c != EOF)
{
int cc;
while ((cc=getc(tty)) != '\n' && cc != EOF)
;
}
if (c != 'y' && c != 'Y')
{
free(p);
fclose(tty);
free(filename_buf);
return (0);
}
fprintf (tty, "Filename [%s]: ", p);
fgets(filenamebuf, sizeof(filenamebuf)-1, tty);
fclose(tty);
t=strchr(filenamebuf, '\n');
if (t) *t=0;
else
{
fprintf(stderr, "Filename too long.\n");
exit(1);
}
if (filenamebuf[0])
{
free(p);
p=strdup(filenamebuf);
if (!p)
{
perror("malloc");
exit(1);
}
}
}
free(filename_buf);
return (p);
}
static void extract_file(struct rfc2045 *p,
const char *filename, int argc, char **argv)
{
char *f;
FILE *fp;
int ignore=0;
for (;;)
{
int fd;
f=get_suitable_filename(p, filename, ignore);
if (!f) return;
fd=open(f, O_WRONLY|O_CREAT|O_EXCL, 0666);
if (fd < 0)
{
if (errno == EEXIST)
{
printf("%s exists.\n", f);
free(f);
ignore=1;
continue;
}
perror(f);
exit(1);
}
fp=fdopen(fd, "w");
if (!fp)
{
perror("fdopen");
exit(1);
}
break;
}
do_print_section(p, fp);
if (fflush(fp) || ferror(fp))
{
perror("write");
exit(1);
}
fclose(fp);
free(f);
}
static void extract_pipe(struct rfc2045 *p,
const char *filename,
int argc, char **argv)
{
char *f=get_suitable_filename(p, "FILENAME=", 0);
int pipefd[2];
pid_t pid, p2;
FILE *fp;
int waitstat;
if (argc == 0)
{
fprintf(stderr, "reformime: Invalid -X option.\n");
exit(1);
}
if (pipe(pipefd))
{
perror("pipe");
exit(1);
}
if ((fp=fdopen(pipefd[1], "w")) == 0)
{
perror("fdopen");
exit(1);
}
while ((pid=fork()) == -1)
{
sleep(2);
}
if (pid == 0)
{
const char *content_type_s;
const char *content_transfer_encoding_s;
const char *charset_s;
if (!f) f="FILENAME=attachment.dat";
putenv(f);
rfc2045_mimeinfo(p, &content_type_s,
&content_transfer_encoding_s, &charset_s);
f=malloc(strlen(content_type_s)
+sizeof("CONTENT_TYPE="));
if (!f)
{
perror("malloc");
exit(1);
}
strcat(strcpy(f, "CONTENT_TYPE="), content_type_s);
putenv(f);
close(0);
dup(pipefd[0]);
close(pipefd[0]);
close(pipefd[1]);
execv(argv[0], argv);
perror("exec");
_exit(1);
}
close(pipefd[0]);
signal(SIGPIPE, SIG_IGN);
do_print_section(p, fp);
signal(SIGPIPE, SIG_DFL);
fclose(fp);
close(pipefd[1]);
while ((p2=wait(&waitstat)) != pid && p2 != -1)
;
free(f);
}
static void extract_section(struct rfc2045 *top_rfcp, const char *mimesection,
const char *extract_filename, int argc, char **argv,
void (*extract_func)(struct rfc2045 *, const char *,
int, char **))
{
if (mimesection)
{
top_rfcp=rfc2045_find(top_rfcp, mimesection);
if (!mimesection)
notfound(mimesection);
if (top_rfcp->firstpart)
{
fprintf(stderr, "reformime: MIME section %s is a compound section.\n", mimesection);
exit(1);
}
(*extract_func)(top_rfcp, extract_filename, argc, argv);
return;
}
/* Recursive */
if (top_rfcp->firstpart)
{
for (top_rfcp=top_rfcp->firstpart; top_rfcp;
top_rfcp=top_rfcp->next)
extract_section(top_rfcp, mimesection,
extract_filename, argc, argv, extract_func);
return;
}
if (!top_rfcp->isdummy)
(*extract_func)(top_rfcp, extract_filename, argc, argv);
}
static void print_dsn_recip(char *addr, char *action)
{
char *p, *q;
if (!action || !addr)
{
if (action) free(action);
if (addr) free(addr);
return;
}
for (p=action; *p; ++p)
*p=tolower((int)(unsigned char)*p);
for (p=addr; *p && isspace((int)(unsigned char)*p); ++p)
;
if (strncasecmp(p, "rfc822;", 7))
{
free(action);
free(addr);
return;
}
for (q=action; *q && isspace((int)(unsigned char)*q); ++q)
;
p += 7;
while (*p && isspace((int)(unsigned char)*p))
++p;
printf("%s %s\n", q, p);
free(action);
free(addr);
}
static void dsn(struct rfc2045 *p, int do_orig)
{
const char *content_type_s;
const char *content_transfer_encoding_s;
const char *charset_s;
off_t start_pos, end_pos, start_body;
off_t dummy;
const char *q;
char buf[BUFSIZ];
unsigned i;
int ch;
char *recip;
char *action;
char *orecip;
rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s,
&charset_s);
if (strcasecmp(content_type_s, "multipart/report") ||
(q=rfc2045_getattr(p->content_type_attr, "report-type")) == 0 ||
strcasecmp(q, "delivery-status") ||
!p->firstpart || !p->firstpart->next ||
!p->firstpart->next->next)
_exit(1);
p=p->firstpart->next->next;
rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s,
&charset_s);
rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy);
if (strcasecmp(content_type_s, "message/delivery-status") ||
fseek(stdin, start_body, SEEK_SET) == -1)
_exit(1);
i=0;
recip=0;
orecip=0;
action=0;
while (start_body < end_pos)
{
if ((ch=getchar()) == EOF) break;
++start_body;
if (i < sizeof(buf)-1)
buf[i++]= ch;
if (ch != '\n') continue;
ch=getchar();
if (ch != EOF) ungetc(ch, stdin);
if (ch != '\n' && isspace((int)(unsigned char)ch))
continue;
buf[i-1]=0;
if (buf[0] == 0)
{
if (orecip)
{
if (recip) free(recip);
recip=orecip;
orecip=0;
}
print_dsn_recip(recip, action);
recip=0;
action=0;
}
if (strncasecmp(buf, "Final-Recipient:", 16) == 0 &&
recip == 0)
{
recip=strdup(buf+16);
if (!recip)
{
perror("strdup");
exit(2);
}
}
if (strncasecmp(buf, "Original-Recipient:", 19) == 0 &&
orecip == 0 && do_orig)
{
orecip=strdup(buf+19);
if (!orecip)
{
perror("strdup");
exit(2);
}
}
if (strncasecmp(buf, "Action:", 7) == 0 && action == 0)
{
action=strdup(buf+7);
if (!action)
{
perror("strdup");
exit(2);
}
}
i=0;
}
if (orecip)
{
if (recip) free(recip);
recip=orecip;
orecip=0;
}
print_dsn_recip(recip, action);
}
static void mimedigest1(int, char **);
static char mimebuf[BUFSIZ];
static void mimedigest(int argc, char **argv)
{
char *p;
struct filelist { struct filelist *next; char *fn; } *first=0, *last=0;
unsigned pcnt=0;
char **l;
if (argc > 0)
{
mimedigest1(argc, argv);
return;
}
while (fgets(mimebuf, sizeof(mimebuf), stdin))
{
struct filelist *q;
if ((p=strchr(mimebuf, '\n')) != 0) *p=0;
q=malloc(sizeof(struct filelist));
if (!q || !(q->fn=strdup(mimebuf)))
{
perror("malloc");
exit(1);
}
if (last) last->next=q;
else first=q;
last=q;
q->next=0;
++pcnt;
}
if (pcnt == 0) return;
if ( (l=malloc(sizeof (char *) * pcnt)) == 0)
{
perror("malloc");
}
pcnt=0;
for (last=first; last; last=last->next)
l[pcnt++]=last->fn;
mimedigest1(pcnt, l);
}
static void mimedigest1(int argc, char **argv)
{
time_t t;
char boundarybuf[200];
unsigned boundarycnt=0;
int i;
FILE *fp;
time (&t);
/* Search for a suitable boundary */
do
{
int l;
sprintf(boundarybuf, "reformime_%lu_%u",
(unsigned long)t, ++boundarycnt);
l=strlen(boundarybuf);
for (i=0; i<argc; i++)
{
int err=0;
if ((fp=fopen(argv[i], "r")) == 0)
{
perror(argv[i]);
exit(1);
}
while (fgets(mimebuf, sizeof(mimebuf), fp))
{
if (mimebuf[0] != '-' || mimebuf[1] != '-')
continue;
if (strncasecmp(mimebuf+2, boundarybuf, l) == 0)
{
err=1;
break;
}
}
fclose(fp);
if (err) break;
}
} while (i < argc);
printf("Mime-Version:1.0\n"
"Content-Type: multipart/digest; boundary=\"%s\"\n\n%s",
boundarybuf, RFC2045MIMEMSG);
for (i=0; i<argc; i++)
{
if ((fp=fopen(argv[i], "r")) == 0)
{
perror(argv[i]);
exit(1);
}
printf("\n--%s\nContent-Type: message/rfc822\n\n",
boundarybuf);
while (fgets(mimebuf, sizeof(mimebuf), fp))
printf("%s", mimebuf);
fclose(fp);
}
printf("\n--%s--\n", boundarybuf);
}
int main(int argc, char **argv)
{
int argn;
char optc;
char *optarg;
char *mimesection=0;
int doinfo=0, dodecode=0, dorewrite=0, dodsn=0, domimedigest=0;
struct rfc2045 *p;
int rwmode=0;
void (*do_extract)(struct rfc2045 *, const char *, int, char **)=0;
const char *extract_filename=0;
for (argn=1; argn<argc; )
{
if (argv[argn][0] != '-') break;
optarg=0;
optc=argv[argn][1];
if (optc && argv[argn][2]) optarg=argv[argn]+2;
++argn;
switch (optc) {
case 'c':
if (!optarg && argn < argc)
optarg=argv[argn++];
if (optarg && *optarg)
rfc2045_setdefaultcharset(optarg);
break;
case 's':
if (!optarg && argn < argc)
optarg=argv[argn++];
if (optarg && *optarg) mimesection=optarg;
break;
case 'i':
doinfo=1;
break;
case 'e':
dodecode=1;
break;
case 'r':
dorewrite=1;
if (optarg && *optarg == '7')
rwmode=RFC2045_RW_7BIT;
if (optarg && *optarg == '8')
rwmode=RFC2045_RW_8BIT;
break;
case 'm':
domimedigest=1;
break;
case 'd':
dodsn=1;
break;
case 'D':
dodsn=2;
break;
case 'x':
do_extract=extract_file;
if (optarg)
extract_filename=optarg;
break;
case 'X':
do_extract=extract_pipe;
break;
case 'v':
printf("%s\n", rcsid);
exit(0);
default:
usage();
}
}
if (domimedigest)
{
mimedigest(argc-argn, argv+argn);
return (0);
}
p=read_message();
if (doinfo)
print_info(p, mimesection);
else if (dodecode)
print_decode(p, mimesection);
else if (dorewrite)
rewrite(p, rwmode);
else if (dodsn)
dsn(p, dodsn == 2);
else if (do_extract)
extract_section(p, mimesection, extract_filename,
argc-argn, argv+argn, do_extract);
else
print_structure(p);
rfc2045_free(p);
exit(0);
return (0);
}

View File

@ -1,212 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>reformime - MIME utility</title>
<!-- $Id$ -->
<!-- SECTION 1 -->
<meta http-equiv="Content-Type" content="text/html">
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B"
alink="#FF0000">
<h1>reformime - MIME utility</h1>
<h2>SYNOPSIS</h2>
<code>reformime [options] ...</code>
<h2>DESCRIPTION</h2>
<p><i>reformime</i> is a tool for manipulating MIME messages and
attachments.</p>
<p><i>reformime</i> expects to see an <a
href="http://www.rfc-editor.org/rfc/rfc2045.txt">RFC 2045</a>, message on
standard input.</p>
<p>If no options are given, <i>reformime</i> prints the MIME structure of the
message. The output consists of so-called "MIME reference tags", one per line.
For example, you might see the following output:</p>
<pre> 
    1
    1.1
    1.2</pre>
This tells you that the message contains two different MIME sections. The
first line of the MIME structure output will always contain "1", which refers
to the entire message, which happens to be a <code>multipart/mixed</code>
message. "1.1" refers to the first section of the multiparty message, which
happens to be a <code>text/plain</code> section. "1.2" refers to the second
section of the message, which happens to be an
<code>application/octet-stream</code> section. This is a typical situation.
<p>If the message is not a MIME message, or it does not contain any
attachments, you will see a rather boring</p>
<pre> 
    1</pre>
If, instead the first part of the message was itself a
<code>multipart/alternative</code> section, you might see the following
instead:
<pre> 
    1
    1.1
    1.1.1
    1.1.2
    1.2</pre>
<p>Arbitrarily complex MIME constructs are possible.</p>
<h2>OPTIONS</h2>
<ul>
<li><code>-d</code> - parse a delivery status notification MIME message (RFC
1894). reformime expects to see on standard input a MIME message that
consists of a delivery status notification, as defined by RFC 1894.
reformime reads the message and prints on standard output a list of
addresses and their corresponding delivery status, as specified in the
delivery status notification. Each line printed by reformime consists of a
delivery status, a space, and the address reformime will terminate with a
0 exit status. reformime produces no output and terminates with an exit
status of 1 if the standard input does not contain a delivery status
notification.<br>
<br>
</li>
<li><code>-D</code> - like the <code>-d</code> option, except that it lists
the "original" recipient address, if provided. See RFC 1894 for more
information.<br>
<br>
</li>
<li><code>-e</code> - extract the contents of the indicated MIME section,
and display it on standard output. The -s option is required when -e is
specified. If the indicated section uses either the <code>base64</code> or
<code>quoted-printable</code> encoding method, reformime automatically
decodes it. In this case you're better off redirecting the standard output
into a file.<br>
<br>
</li>
<li><code>-x</code> - extract the contents of the indicated MIME section to
a file.<br>
<br>
</li>
<li><code>-X</code> - pipe the contents of the indicated MIME section to a
program.<br>
<br>
</li>
<li><code>-i</code> - display MIME information for each section.
<code>reformime</code> will display the contents of the Content-Type:
header, any encoding used, and the character set. <code>reformime</code>
will also display at which byte offset in the message each section starts
and ends (and where the actual contents of the section start, skipping all
the headers).<br>
<br>
</li>
<li><code>-s section</code> - display MIME information for this section
only. section is a MIME specification tag. The -s option is required if -e
is also specified, and is optional with -i.<br>
<br>
</li>
<li><code>-r</code> - rewrite message, adding or standardizing RFC 2045 MIME
headers.<br>
<br>
</li>
<li><code>-r7</code> - also convert MIME sections with 8bit encoding to
quoted-printable encoding.<br>
<br>
</li>
<li><code>-r8</code> - also convert MIME sections with quoted-printable
encoding to 8bit encoding, where possible.<br>
<br>
<code></code></li>
<li><code>-m <i>file1 file2 ...</i></code> - create a MIME message
digest.</li>
</ul>
<h3>Extracting RFC 2045 MIME section(s) to file(s)</h3>
<p>The -x and -X options extract a specific MIME section to a file or to a
pipe to an external program. Use the -s option to identify the MIME section
to extract. If the -s option is not specified, every MIME section in the
message is extracted, one at a time. quoted-printable and base64 encoding are
automatically decoded.</p>
<ul>
<li><code>-x</code> - interactive extraction. <code>reformime</code> prints
the MIME content type of each section. Answer with 'y' or 'Y' to extract
the MIME section. Specify the filename at the next prompt.
<code>reformime</code> will prompt with a default filename. reformime
tries to choose the default filename based on the MIME headers, if
possible. If not, the default filename will be
<code>attachment1.dat</code> (if the -s option is not specified, the next
filename will be <code>attachment2.dat</code>, and so on).<br>
<br>
</li>
<li><code>-xPREFIX</code> - automatic extraction. <i>reformime</i> will
automatically extract one or more MIME sections, and save them to a file.
The filename will be formed by taking PREFIX, and appending the default
filename to it. Note that there may not be a space between "-x" and
"PREFIX". For example: "reformime -xfiles-" - this will save MIME sections
as <code>files-attachment1.dat</code>, then
<code>files-attachment2.dat</code>, etc. <code>reformime</code> will try
to append the filename specified in the MIME headers for each section.
<i>reformime</i> will replace all suspect characters with the underbar,
when using the filename specified in the MIME headers.<br>
<br>
</li>
<li><code>-X prog arg1 arg2 ...</code> - the -X option must be the last
option to <code>reformime</code>. <code>reformime</code> will run an
external program specified by "prog", and pipe the contents of the MIME
section to the program. reformime will set the environment variable
<code>CONTENT_TYPE</code> to the MIME content type. The environmetn
variable <code>FILENAME</code> will be set to the default filename of
reformime's liking. If the -s option is not specified, the program will be
executed one time for every MIME section in the message.</li>
</ul>
<p>NOTE: <i>reformime</i> will extract every MIME section in the message
unless the -s option is specified. Yes, even the <code>text/plain</code> MIME
part that usually precedes a binary attachment.</p>
<h3>Adding RFC 2045 MIME headers</h3>
<p>The <i>-r</i> option performs the following actions:</p>
<p>If there is no <code>Mime-Version:</code>, <code>Content-Type:</code>, or
<code>Content-Transfer-Encoding:</code> header, <code>reformime</code> will
add one.</p>
<p>If the <code>Content-Transfer-Encoding:</code> header contains
<code>8bit</code> or <code>raw</code>, but only seven-bit data is found,
the<code> Content-Transfer-Encoding</code> header is changed to
<code>7bit</code>.</p>
<p><i>-r7</i> does the same thing, but also converts 8bit transfer encoding
containing eight-bit characters to quoted-printable encoding.</p>
<p><i>-r8</i> does the same thing, but also converts quoted-printable encoded
sections to 8bit, except in some situations.</p>
<h3>Creating MIME message digests</h3>
<p>The <code>-m</code> option is followed by a list of files. Each file should
contain a single RFC 822 message. <code>reformime</code> prints, on standard
output, a MIME digest containing the indicated messages.</p>
<p>If <code>-m</code> is not followed by at least one file,
<code>reformime</code> reads standard input. Each line on standard input must
contain a single filename; blank lines are not allowed.</p>
<h2>BUGS</h2>
<p>-x and -X ignores the Content-Disposition: header.</p>
<h2>FILES</h2>
<p><code>$HOME/.tmp</code> - directory for temporary files. Automatically
created, if necessary.</p>
<h2>SEE ALSO</h2>
<a href="maildrop.html">maildrop(1)</a>, <a
href="maildropfilter.html">maildropfilter(1)</a>, <a
href="makemime.html">makemime(1)</a>, <a
href="reformail.html">reformail(1)</a>, egrep(1), grep(1), <a
href="courier.html">courier(8)</a>, sendmail(8), <a
href="http://www.rfc-editor.org/rfc/rfc1894.txt">RFC 1894</a>, <a
href="http://www.rfc-editor.org/rfc/rfc2045.txt">RFC 2045</a>.</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,188 +0,0 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#ifndef rfc2045_h
#define rfc2045_h
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RFC2045_ISMIME1(p) ((p) && atoi(p) == 1)
#define RFC2045_ISMIME1DEF(p) (!(p) || atoi(p) == 1)
struct rfc2045 {
struct rfc2045 *parent;
unsigned pindex;
struct rfc2045 *next;
off_t startpos, /* At which offset in msg this section starts */
endpos, /* Where it ends */
startbody, /* Where the body of the msg starts */
endbody; /* endpos - trailing CRLF terminator */
off_t nlines; /* Number of lines in message */
off_t nbodylines; /* Number of lines only in the body */
char *mime_version;
char *content_type;
struct rfc2045attr *content_type_attr; /* Content-Type: attributes */
char *content_disposition;
char *boundary;
struct rfc2045attr *content_disposition_attr;
char *content_transfer_encoding;
int content_8bit; /*
** Set if content_transfer_encoding is
** 8bit
*/
char *content_id;
char *content_description;
char *content_language;
char *content_md5;
char *content_base;
char *content_location;
struct rfc2045ac *rfc2045acptr;
int has8bitchars; /* For rewriting */
int haslongline; /* For rewriting */
unsigned rfcviolation; /* Boo-boos */
#define RFC2045_ERR8BITHEADER 1 /* 8 bit characters in headers */
#define RFC2045_ERR8BITCONTENT 2 /* 8 bit contents, but no 8bit
content-transfer-encoding */
#define RFC2045_ERR2COMPLEX 4 /* Too many nested contents */
unsigned numparts; /* # of parts allocated */
char *rw_transfer_encoding; /* For rewriting */
#define RFC2045_RW_7BIT 1
#define RFC2045_RW_8BIT 2
/* Subsections */
struct rfc2045 *firstpart, *lastpart;
/* Working area */
char *workbuf;
size_t workbufsize;
size_t workbuflen;
int workinheader;
int workclosed;
int isdummy;
int informdata; /* In a middle of a long form-data part */
char *header;
size_t headersize;
size_t headerlen;
int (*decode_func)(struct rfc2045 *, const char *, size_t);
void *misc_decode_ptr;
int (*udecode_func)(const char *, size_t, void *);
} ;
struct rfc2045attr {
struct rfc2045attr *next;
char *name;
char *value;
} ;
struct rfc2045 *rfc2045_alloc();
void rfc2045_parse(struct rfc2045 *, const char *, size_t);
void rfc2045_free(struct rfc2045 *);
const char *rfc2045_contentname(const struct rfc2045 *);
void rfc2045_mimeinfo(const struct rfc2045 *,
const char **,
const char **,
const char **);
const char *rfc2045_boundary(const struct rfc2045 *);
char *rfc2045_related_start(const struct rfc2045 *);
const char *rfc2045_content_id(const struct rfc2045 *);
const char *rfc2045_content_description(const struct rfc2045 *);
const char *rfc2045_content_language(const struct rfc2045 *);
const char *rfc2045_content_md5(const struct rfc2045 *);
void rfc2045_dispositioninfo(const struct rfc2045 *,
const char **,
const char **,
const char **);
void rfc2045_mimepos(const struct rfc2045 *, off_t *, off_t *, off_t *,
off_t *, off_t *);
unsigned rfc2045_mimepartcount(const struct rfc2045 *);
void rfc2045_xdump(struct rfc2045 *);
struct rfc2045id {
struct rfc2045id *next;
int idnum;
} ;
void rfc2045_decode(struct rfc2045 *,
void (*)(struct rfc2045 *, struct rfc2045id *, void *),
void *);
struct rfc2045 *rfc2045_find(struct rfc2045 *, const char *);
void rfc2045_cdecode_start(struct rfc2045 *,
int (*)(const char *, size_t, void *), void *);
int rfc2045_cdecode(struct rfc2045 *, const char *, size_t);
int rfc2045_cdecode_end(struct rfc2045 *);
void rfc2045_base64encode_start( void (*)(const char *, size_t));
void rfc2045_base64encode(const char *, size_t);
void rfc2045_base64encode_end();
const char *rfc2045_getdefaultcharset();
void rfc2045_setdefaultcharset(const char *);
struct rfc2045 *rfc2045_fromfd(int);
#define rfc2045_fromfp(f) (rfc2045_fromfd(fileno((f))))
extern void rfc2045_error(const char *);
struct rfc2045ac {
void (*start_section)(struct rfc2045 *);
void (*section_contents)(const char *, size_t);
void (*end_section)();
} ;
struct rfc2045 *rfc2045_alloc_ac();
int rfc2045_ac_check(struct rfc2045 *, int);
int rfc2045_rewrite(struct rfc2045 *, int, int, const char *);
int rfc2045_rewrite_func(struct rfc2045 *p, int,
int (*)(const char *, int, void *), void *,
const char *);
/* Internal functions */
int rfc2045_try_boundary(struct rfc2045 *, int, const char *);
char *rfc2045_mk_boundary(struct rfc2045 *, int);
const char *rfc2045_getattr(const struct rfc2045attr *, const char *);
void rfc2045_setattr(struct rfc2045attr **, const char *, const char *);
/* MIME content base/location */
char *rfc2045_content_base(struct rfc2045 *p);
/* This joins Content-Base: and Content-Location:, as best as I
** can figure it out.
*/
char *rfc2045_append_url(const char *, const char *);
/* Do this with two arbitrary URLs */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,323 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>rfc2045 - RFC 2045 (MIME) parsing library</title>
<!-- $Id$ -->
<!-- Copyright 2000 Double Precision, Inc. See COPYING for -->
<!-- distribution information. -->
<!-- SECTION 3X -->
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B"
alink="#FF0000">
<h1>rfc2045 - RFC 2045 (MIME) parsing library</h1>
<h2>SYNOPSIS</h2>
<p><code>#include &lt;rfc2045.h></code></p>
<p><code>cc ... -lrfc2045 -lrfc822</code></p>
<h2>DESCRIPTION</h2>
<p>The rfc2045 library is used to parse and work with MIME-formatted messages.
The rfc2045 library is used to:</p>
<p>1) Parse the structure of a MIME formatted message</p>
<p>2) Examine the contents of each MIME section</p>
<p>3) Optionally rewrite and reformat the message.</p>
<h2>Creating an rfc2045 structure</h2>
<pre>#include &lt;rfc2045.h>
struct rfc2045 *ptr=rfc2045_alloc();
void rfc2045_parse(struct rfc2045 *ptr, const char *txt, size_t cnt);
struct rfc2045 *ptr=rfc2045_fromfd(int fd);
struct rfc2045 *ptr=rfc2045_fromfp(FILE *fp);
void rfc2045_free(struct rfc2045 *ptr);
void rfc2045_error(const char *errmsg)
{
perror(errmsg);
exit(0);
}</pre>
<p>The <i>rfc2045</i> structure is created from an existing message. The
function rfc2045_alloc() allocates the structure, then rfc2045_parse() is
called to initialize the structure based on the contents of the message.
<i>txt</i> points to the contents of the message, and <i>cnt</i> contains the
number of bytes in the message.</p>
<p>Large messages can be parsed by calling rfc2045_parse() multiple number of
times, each time passing a portion of the overall message. There is no need to
call a separate function after the entire message has been parsed -- the
<i>rfc2045</i> structure is created dynamically, on the fly.</p>
<p>rfc2045_alloc() returns NULL if there was insufficient memory to allocate
the structure. The rfc2045_parse() also allocates memory, internally, however
no error indication is return in the event of a memory allocation failure.
Instead, the function rfc2045_error() is called, with <i>errmsg</i> set to
"Out of memory". rfc2045_error() is also called by <i>rfc2045_alloc()</i> also
calls rfc2045_error(), prior to returning a NULL pointer.</p>
<p>The rfc2045_error() function is not included in the rfc2045 library, it
must be defined by the application to report the error in some appropriate
way. All functions below will use rfc2045_error() to report an error condition
(currently only insufficient memory is reported), in addition to returning any
kind of an error indicator. Some functions do not return an error indicator,
so rfc2045_error() is the only reliable way to detect a failure.</p>
<p>The rfc2045_fromfd() function initializes an <i>rfc2045</i> structure from
a file descriptor. It is equivalent to calling rfc2045_alloc(), then reading
the contents of the given file descriptor, and calling rfc2045_parse(). The
rfc2045_fromfp() function initializes an <i>rfc2045</i> structure from a
FILE.</p>
<p>After the <i>rfc2045</i> structure is initialized, the functions described
below may be used to access and work with the contents of the structure. When
the <i>rfc2045</i> structure is no longer needed, the function rfc2045_free()
deallocates and destroys the structure.</p>
<h2>Structure of a MIME message</h2>
<pre>struct rfc2045 {
struct rfc2045 *parent;
struct rfc2045 *firstpart;
struct rfc2045 *next;
int isdummy;
int rfcviolation;
} ;</pre>
<p>The <i>rfc2045</i> has many fields, only some are publicly documented. A
MIME message is represented by a recursive tree of linked <i>rfc2045</i>
structures. Each instance of the <i>rfc2045</i> structure represents a single
MIME section of a MIME message.</p>
<p>The top-level structure representing the entire message is created by the
rfc2045_alloc() function. The remaining structures are created dynamically by
rfc2045_parse(). Any <i>rfc2045</i> structure, except ones whose
<i>isdummy</i> flag is set, may be used as an argument to any function
described in the following chapters.</p>
<p>The <i>rfcviolation</i> field in the top-level <i>rfc2045</i> is set to
indicate any errors encountered while parsing the MIME message.
<i>rfcviolation</i> is a bitmask of the following flags:</p>
<ul>
<li><code>RFC2045_ERR8BITHEADER</code> - illegal 8-bit characters in MIME
headers.<br>
<br>
</li>
<li><code>RFC2045_ERR8BITCONTENT</code> - illegal 8-bit contents of a MIME
section that has a 7bit transfer encoding.<br>
<br>
</li>
<li><code>RFC2045_ERR2COMPLEX</code> - the message has too many MIME
sections, this is a potential denial-of-service attack.</li>
</ul>
<p>In each <i>rfc2045</i> structure representing a multipart MIME section (or
one containing message/rfc822 content), the <i>firstpart</i> pointer points to
the first MIME section in the multipart MIME section (or the included
"message/rfc822" MIME section). If there are more than one MIME sections in a
multipart MIME section <i>firstpart->next</i> gets you the second MIME
section, <i>firstpart->next->next</i> gets you the third MIME section, and so
on. <i>parent</i> points to the parent MIME section, which is NULL for the
top-level MIME section.</p>
<p>Not all MIME sections are created equal. In a multipart MIME section,
there is an initial, unused, "filler" section before the first MIME delimiter
(see RFC 2045 for more information). This filler section typically contains a
terse message saying that this is a MIME-formatted message, or something
similar of that kind. This is not considered to be a "real" MIME section, and
all MIME-aware software must ignore those. These filler sections are
designated by setting the "isdummy" flag to non-zero. All <i>rfc2045</i>
structures that have "isdummy" set must be completely ignored, and skipped
over, when traversing the <i>rfc2045</i> tree.</p>
<h2>Basic MIME information</h2>
<pre>const char *content_type, *content_transfer_encoding,
*content_character_set;
void rfc2045_mimeinfo(const struct rfc2045 *ptr,
&content_type, &content_transfer_encoding,
&content_character_set);
off_t start_pos, end_pos, start_body, nlines, nbodylines;
void rfc2045_mimepos(const struct rfc2045 *ptr,
&start_pos, &end_pos, &start_body, &nlines,
&nbodylines);</pre>
<p>The rfc2045_mimeinfo() function returns the content type, encoding method,
and the character set of a given MIME section. Where a MIME section does not
specify any property, rfc2045_mimeinfo() automatically supplies a default
value. The character set is only meaningful for MIME sections containing a
text content type, however it is still defaulted for other sections. It is
not permissible to supply a NULL pointer for any argument to
rfc2045_mimeinfo().</p>
<p>The rfc2045_mimepos() function is used to locate the position of the given
MIME section in the original message. It is not permissible to supply a NULL
pointer for any argument to rfc2045_mimepos(). All arguments must be
used.</p>
<p><i>start_pos</i> and <i>end_pos</i> point to the starting and the ending
offset, from the beginning of the message, of this MIME section. <i>nlines</i>
is initialized to the number of lines of text in this MIME section. The
starting offset points to the start of MIME headers in this section.
<i>start_body</i> is initialized to point to the starting offset of the actual
contents of this MIME section, and <i>nbodylines</i> is set to the number of
lines of actual content in this MIME section.</p>
<pre>const char *id=rfc2045_content_id(
const struct rfc2045 *ptr);
const char *desc=rfc2045_content_description(
const struct rfc2045 *ptr);
const char *lang=rfc2045_content_language(
const struct rfc2045 *ptr);
const char *md5=rfc2045_content_md5(
const struct rfc2045 *ptr);</pre>
<p>These functions return the contents of the corresponding MIME headers. If
these headers do not exist, these functions return an empty string, "", NOT a
null pointer.</p>
<pre>char *id=rfc2045_related_start(const struct rfc2045 *ptr);</pre>
<p>This function returns the <i>start</i> parameter of the Content-Type:
header, which is used by multipart/related content. This function returns a
dynamically-allocated buffer, which must be free(3)-ed after use (a null
pointer is returned if there was insufficient memory for the buffer, and
rfc2045_error() is called).</p>
<pre>const char *disposition, *name, *filename;
void rfc2045_dispositioninfo(const struct rfc2045 *ptr,
&disposition, &name, &filename);</pre>
<p>rfc2045_dispositioninfo() returns the disposition specifications of a MIME
section. For MIME sections that do not specify the type of disposition
(inline or attachment), the name or the filename of the attachment, the
corresponding pointer is initialized to NULL.</p>
<pre>char *url=rfc2045_content_base(struct rfc2045 *ptr);
char *url=rfc2045_append_url(const char *base, const char *url);</pre>
<p>These functions are used to work with multipart/related MIME messages. The
rfc2045_content_base() returns the contents of either the Content-Base: or the
Content-Location: header. If both are present, they are logically combined.
The rfc2045_append_url() function combines two URLs, <i>base</i> and
<i>url</i>, and returns the absolute URL that results from the
combination.</p>
<p>Both functions return a pointer to a dynamically-allocated buffer that must
be free(3)-ed after it is no longer needed. Both functions return NULL if
there was no sufficient memory to allocate the buffer. rfc2045_content_base()
returns an empty string in the event that there are no Content-Base: or
Content-Location: headers. Either argument to rfc2045_append_url() may be a
NULL, or an empty string.</p>
<h2>Decoding a MIME section</h2>
<pre>void rfc2045_cdecode_start(struct rfc2045 *ptr,
int (*callback_func)(const char *, size_t, void *),
void *callback_arg);
int rfc2045_cdecode(struct rfc2045 *ptr, const char *stuff,
size_t nstuff);
int rfc2045_cdecode_end(struct rfc2045 *ptr);</pre>
<p>These functions are used to return the raw contents of the given MIME
section, transparently decoding quoted-printable or base64-encoded content.
Because the rfc2045 library does not require the message to be read from a
file (it can be stored in a memory buffer), the application is responsible for
reading the contents of the message and calling rfc2045_cdecode().</p>
<p>The rfc2045_cdecode_start() function is used to begin the process of
decoding the given MIME section. After calling rfc2045_cdecode_start(), the
application must the repeatedly call rfc2045_cdecode() with the contents of
the MIME message between the offsets given by the <i>start_body</i> and
<i>end_pos</i> return values from rfc2045_mimepos() function. The
rfc2045_cdecode() function can be called repeatedly, if necessary, for
successive portions of the MIME section. After the last MIME section, the
rfc2045_cdecode_end() function is called to finish decoding the MIME
section.</p>
<p>rfc2045_cdecode() and rfc2045_cdecode_end() repeatedly call the
callback_func() function, with the decoded contents of the MIME section. The
first argument to callback_func() is a pointer to a portion of the decoded
content, the second argument is the number of bytes in this portion. The
third argument is <i>callback_arg</i>.</p>
<p>callback_func() is required to return zero, to continue decoding. If
callback_func() returns non-zero, the decoding immediately stops and
rfc2045_cdecode() or rfc2045_cdecode_end() will terminate with callback_func's
return code.</p>
<h2>Rewriting MIME messages</h2>
<p>The rfc2045 library contains functions that can be used to rewrite a MIME
message in order to convert 8-bit data to 7-bit encoding method, or to convert
7-bit encoded data to full 8-bit data, if possible.</p>
<pre>struct rfc2045 *ptr=rfc2045_alloc_ac();
int necessary=rfc2045_ac_check(struct rfc2045 *ptr, int mode);
int error=rfc2045_rewrite(struct rfc2045 *ptr,
int fdin,
int fdout,
const char *appname);
int rfc2045_rewrite_func(struct rfc2045 *p, int fdin,
int (*funcout)(const char *, int, void *), void *funcout_arg,
const char *appname);</pre>
<p>When rewriting will be used, the rfc2045_alloc_ac() function must be used
to create the initial <i>rfc2045</i> structure. This function allocates some
additional structures that are used in rewriting. The rfc2045_parse() function
is used to parse the message, as usual. The rfc2045_free() function will also
be used normally to destroy the <i>rfc2045</i> structure, when all is said and
done.</p>
<p>The rfc2045_ac_check() function must be called to determine whether
rewriting is necessary. <i>mode</i> must be set to one of the following
values:</p>
<ul>
<li><code>RFC2045_RW_7BIT</code> - we want to generate 7-bit content. If the
original message contains any 8-bit content it will be converted to 7-bit
content using quoted-printable encoding.</li>
<li><code>RFC2045_RW_8BIT</code> - we want to generate 8-bit content. If the
original message contains any 7-bit quoted-printable content it should be
rewritten as 8-bit content.</li>
</ul>
<p>The rfc2045_ac_check() function returns non-zero if there's any content in
the MIME message that should be converted, OR if there are any missing MIME
headers. rfc2045_ac_check() returns zero if there's no need to rewrite the
message. However it might still be worthwhile to rewrite the message anyway.
There are some instances where it is desirable to provide defaults for some
missing MIME headers, but they are too trivial to require the message to be
rewritten. One such case would be a missing Content-Transfer-Encoding: header
for a multipart section.</p>
<p>Either the rfc2045_rewrite() or the rfc2045_rewrite_func() function is used
to rewrite the message. The only difference is that rfc2045_rewrite() writes
the new message to a given file descriptor, <i>fdout</i>, while
rfc2045_rewrite_func() repeatedly calls the <i>funcout</i> function. Both
function read the original message from <i>fdin</i>. <i>funcout</i> receives
to a portion of the MIME message, the number of bytes in the specified
portion, and <i>funcout_arg</i>. When either function rewrites a MIME section,
an informational header gets appended, noting that the message was converted
by <i>appname</i>.</p>
<h2>SEE ALSO</h2>
<a href="rfc822.html">rfc822(3)</a>, <a
href="reformime.html">reformime(1)</a>, <a
href="reformail.html">reformail(1)</a>.</body>
</html>

View File

@ -1,76 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#include "rfc2045.h"
static unsigned char base64buf[57];
/* When encoded this becomes 76 characters */
static int base64cnt;
static void (*output_func)(const char *, size_t);
void rfc2045_base64encode_start( void (*func)(const char *, size_t))
{
output_func=func;
base64cnt=0;
}
void rfc2045_base64encode(const char *buf, size_t n)
{
while (n)
{
size_t i;
if (base64cnt == sizeof(base64buf))
{
rfc2045_base64encode_end();
base64cnt=0;
}
i=n;
if (i > sizeof(base64buf) - base64cnt)
i=sizeof(base64buf) - base64cnt;
memcpy(base64buf + base64cnt, buf, i);
base64cnt += i;
buf += i;
n -= i;
}
}
static const char base64tab[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
void rfc2045_base64encode_end()
{
int a=0,b=0,c=0;
int i, j;
int d, e, f, g;
char output_buf[ sizeof(base64buf) / 3 * 4+1];
if (base64cnt == 0) return;
for (j=i=0; i<base64cnt; i += 3)
{
a=base64buf[i];
b= i+1 < base64cnt ? base64buf[i+1]:0;
c= i+2 < base64cnt ? base64buf[i+2]:0;
d=base64tab[ a >> 2 ];
e=base64tab[ ((a & 3 ) << 4) | (b >> 4)];
f=base64tab[ ((b & 15) << 2) | (c >> 6)];
g=base64tab[ c & 63 ];
if (i + 1 >= base64cnt) f='=';
if (i + 2 >= base64cnt) g='=';
output_buf[j++]=d;
output_buf[j++]=e;
output_buf[j++]=f;
output_buf[j++]=g;
}
output_buf[j++]='\n';
(*output_func)(output_buf, j);
}

View File

@ -1,46 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include "rfc2045.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __WINDOWS__
#include <io.h>
#define read _read
#define lseek _lseek
#endif
/* Convert a message to the RFC2045 structure */
struct rfc2045 *rfc2045_fromfd(int fd)
{
struct rfc2045 *rfc;
char buf[BUFSIZ];
int n;
off_t orig_pos;
if ((orig_pos=lseek(fd, 0L, SEEK_CUR)) == (off_t)-1) return (NULL);
if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) return (NULL);
if ((rfc=rfc2045_alloc()) == 0) return (NULL);
while ((n=read(fd, buf, sizeof(buf))) > 0)
rfc2045_parse(rfc, buf, n);
if (lseek(fd, orig_pos, SEEK_SET) == (off_t)-1)
{
rfc2045_free(rfc);
rfc=0;
}
return (rfc);
}

View File

@ -1,146 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "rfc2045.h"
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#ifdef __WINDOWS__
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
/* $Id$ */
extern void rfc2045_enomem();
int rfc2045_ac_check(struct rfc2045 *p, int rwmode)
{
int flag=0; /* Flag - rewriting suggested */
struct rfc2045 *c;
int hasnon7bit=p->has8bitchars;
/* hasnon7bit: 8bit chars in this section or subsections */
const char *te;
int is8bitte;
for (c=p->firstpart; c; c=c->next)
if (!c->isdummy)
{
if (rfc2045_ac_check(c, rwmode)) flag=1;
if (strcmp(c->content_transfer_encoding, "7bit") &&
strcmp(c->content_transfer_encoding, "quoted-printable"))
hasnon7bit=1;
if (c->has8bitchars)
p->has8bitchars=1;
}
if (RFC2045_ISMIME1DEF(p->mime_version) && !p->content_type)
{
if ((p->content_type=strdup("text/plain")) == 0)
rfc2045_enomem();
if (p->mime_version)
{
flag=1;
}
}
if (RFC2045_ISMIME1DEF(p->mime_version)
&& !rfc2045_getattr(p->content_type_attr, "charset")
&& strncasecmp(p->content_type, "text/", 5) == 0)
{
rfc2045_setattr(&p->content_type_attr, "charset",
rfc2045_getdefaultcharset());
if (p->mime_version
&& p->firstpart == 0 /* sam - don't trigger rewrites on changes to multipart headers */
)
{
flag=1;
}
}
if (RFC2045_ISMIME1DEF(p->mime_version)
&& !p->content_transfer_encoding)
{
if ((p->content_transfer_encoding=strdup(
hasnon7bit ? "8bit":"7bit")) == 0)
rfc2045_enomem();
if (p->mime_version
&& p->firstpart == 0 /* sam - don't trigger rewrites on changes to multipart headers */
)
{
flag=1;
}
}
#if 0
if (RFC2045_ISMIME1DEF(p->mime_version)
&& strncmp(p->content_type, "text/", 5) == 0 && !hasnon7bit
&& strcmp(p->content_transfer_encoding, "7bit"))
{
if (p->mime_version)
{
flag=1;
}
}
#endif
if (RFC2045_ISMIME1DEF(p->mime_version))
{
/* Check for conversions */
te=p->content_transfer_encoding;
is8bitte=strcasecmp(te, "base64") &&
strcasecmp(te, "quoted-printable") &&
strcasecmp(te, "7bit"); /* 8 bit contents */
if (is8bitte && !p->has8bitchars && !p->haslongline)
{
if (p->rw_transfer_encoding)
free(p->rw_transfer_encoding);
if ((p->rw_transfer_encoding=strdup("7bit")) == 0)
rfc2045_enomem();
flag=1;
is8bitte=0;
}
if (rwmode == RFC2045_RW_7BIT && (is8bitte || p->haslongline))
{
if (p->rw_transfer_encoding)
free(p->rw_transfer_encoding);
if ((p->rw_transfer_encoding=strdup("quoted-printable"))
== 0)
rfc2045_enomem();
flag=1;
}
else if (rwmode == RFC2045_RW_8BIT &&
strcasecmp(te, "quoted-printable") == 0 &&
!p->haslongline)
{
if (p->rw_transfer_encoding)
free(p->rw_transfer_encoding);
if ((p->rw_transfer_encoding=strdup(hasnon7bit
? "8bit":"7bit")) == 0)
rfc2045_enomem();
flag=1;
}
}
if (!p->mime_version)
{
if ((p->mime_version=strdup("1.0")) == 0)
rfc2045_enomem();
}
return (flag);
}

View File

@ -1,107 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
#include "rfc2045.h"
#include <ctype.h>
#include <string.h>
/* $Id$ */
static void start_rwprep(struct rfc2045 *);
static void do_rwprep(const char *, size_t);
static void end_rwprep();
static struct rfc2045ac rfc2045acprep={
&start_rwprep,
&do_rwprep,
&end_rwprep};
static struct rfc2045 *currwp;
static int curlinepos=0;
typedef enum {
raw,
quotedprint,
qpseeneq,
qpseeneqh,
base64} state_t;
static state_t curstate;
static int statechar;
#define h2nyb(c) ( (c) >= 'a' && (c) <= 'f' ? (c)-('a'-10): \
(c) >= 'A' && (c) <= 'F' ? (c)-('A'-10): (c)-'0')
struct rfc2045 *rfc2045_alloc_ac()
{
struct rfc2045 *p=rfc2045_alloc();
if (p) p->rfc2045acptr= &rfc2045acprep;
currwp=0;
return (p);
}
static void start_rwprep(struct rfc2045 *p)
{
currwp=p;
curlinepos=0;
curstate=raw;
if (p->content_transfer_encoding)
{
if (strcmp(p->content_transfer_encoding,
"quoted-printable") == 0)
curstate=quotedprint;
else if (strcmp(p->content_transfer_encoding, "base64") == 0)
curstate=base64;
}
}
static void do_rwprep(const char * p, size_t n)
{
if (!currwp) return;
for ( ; n; --n, ++p)
switch (curstate) {
case quotedprint:
if (*p == '=')
{
curstate=qpseeneq;
continue;
}
/* FALLTHRU */
case raw:
if (*p == '\r' || *p == '\n')
curlinepos=0;
else if (++curlinepos > 500)
currwp->haslongline=1;
if ((unsigned char)*p >= 127)
currwp->has8bitchars=1;
break;
case qpseeneq:
if (*p == '\n')
{
curstate=quotedprint;
continue;
}
if (isspace((int)(unsigned char)*p)) continue; /* Ignore WSP */
statechar=*p;
curstate=qpseeneqh;
continue;
case qpseeneqh:
curstate=quotedprint;
if ( (unsigned char)
( (h2nyb(statechar) << 4) + h2nyb(*p) ) >= 127
) currwp->has8bitchars=1;
if (++curlinepos > 500)
currwp->haslongline=1;
continue;
case base64:
break;
}
}
static void end_rwprep()
{
}

View File

@ -1,131 +0,0 @@
/*
** Copyright 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#include <ctype.h>
#include "rfc2045.h"
extern void rfc2045_enomem();
/*
** ---------------------------------------------------------------------
** Attempt to parse Content-Base: and Content-Location:, and return the
** "base" of all the relative URLs in the section.
** ---------------------------------------------------------------------
*/
static void get_method_path(const char *p,
const char **method,
unsigned *methodl,
const char **path)
{
unsigned i;
for (i=0; p && p[i]; i++)
{
if (p[i] == ':')
{
*method=p;
*methodl= ++i;
*path=p+i;
return;
}
if (!isalpha( (int)(unsigned char)p[i]))
break;
}
*method=0;
*methodl=0;
*path=p;
}
char *rfc2045_append_url(const char *base, const char *loc)
{
const char *base_method;
unsigned base_method_l;
const char *base_path;
const char *loc_method;
unsigned loc_method_l;
const char *loc_path;
char *buf, *q;
get_method_path(base, &base_method, &base_method_l, &base_path);
get_method_path(loc, &loc_method, &loc_method_l, &loc_path);
if (loc_method_l)
{
buf=malloc(strlen(loc)+1);
if (!buf)
rfc2045_enomem();
else
strcpy(buf, loc);
return (buf);
}
loc_method=base_method;
loc_method_l=base_method_l;
if (!base_path) base_path="";
if (!loc_path) loc_path="";
buf=malloc(loc_method_l + strlen(base_path)+strlen(loc_path) + 3);
if (!buf)
{
rfc2045_enomem();
return (0);
}
if (loc_method_l)
memcpy(buf, loc_method, loc_method_l);
buf[loc_method_l]=0;
q=buf + loc_method_l;
strcat(strcpy(q, base_path), "/");
if ( loc_path[0] == '/')
{
char *r;
if (loc_path[1] == '/')
/* Location is absolute */
{
*q=0;
}
/* Relative to top of base */
else if ( q[0] == '/' && q[1] == '/' &&
(r=strchr(q+2, '/')) != 0)
{
*r=0;
}
else
*q=0; /* No sys in base, just start with / */
}
strcat(q, loc_path);
return (buf);
}
char *rfc2045_content_base(struct rfc2045 *p)
{
return (rfc2045_append_url(p->content_base, p->content_location));
}

View File

@ -1,201 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
#include "rfc2045.h"
#include <ctype.h>
#include <string.h>
/* $Id$ */
extern void rfc2045_add_buf( char **, size_t *, size_t *,
const char *, size_t);
extern void rfc2045_add_workbuf(struct rfc2045 *, const char *, size_t);
extern void rfc2045_add_workbufch(struct rfc2045 *, int);
static int decode_raw(struct rfc2045 *p, const char *s, size_t l)
{
if (s && l) return ((*p->udecode_func)(s,l,p->misc_decode_ptr));
return (0);
}
static const char xdigit[]="0123456789ABCDEF";
static int do_decode_qp(struct rfc2045 *p)
{
char *a, *b, *c, *end;
int d;
end=p->workbuf + p->workbuflen;
for (a=b=p->workbuf; a < end; )
{
if (*a != '=')
{
*b++ = *a++;
continue;
}
++a;
if (!*a || a >= end || isspace((int)(unsigned char)*a))
break;
if ((c=strchr(xdigit, *a)) == 0) continue;
d= (c-xdigit)*16;
++a;
if (!*a || a >= end)
break;
if ((c=strchr(xdigit, *a)) == 0) continue;
d += c-xdigit;
++a;
*b++=d;
}
p->workbuflen= b-p->workbuf;
d=(*p->udecode_func)(p->workbuf, p->workbuflen, p->misc_decode_ptr);
p->workbuflen=0;
return (d);
}
static unsigned char decode64tab[256];
static int decode64tab_init=0;
/* When we have enough base64-encoded data in the buffer, decode it. */
static int do_decode_base64(struct rfc2045 *p)
{
size_t i, j;
char a,b,c;
size_t k;
int rc;
if (!decode64tab_init)
{
for (i=0; i<256; i++) decode64tab[i]=100;
for (i=0; i<64; i++)
decode64tab[ (int)
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]) ]=i;
decode64tab[ (int)'=' ] = 99;
}
/* Remove everything except base64encoded data */
for (i=j=0; i<p->workbuflen; i++)
if (decode64tab[(int)(unsigned char)p->workbuf[i]] < 100)
p->workbuf[j++]=p->workbuf[i];
p->workbuflen=j;
/* Decode the data, in 4-byte pieces */
i=j / 4;
i=i*4;
k=0;
for (j=0; j<i; j += 4)
{
int w=decode64tab[(int)(unsigned char)p->workbuf[j]];
int x=decode64tab[(int)(unsigned char)p->workbuf[j+1]];
int y=decode64tab[(int)(unsigned char)p->workbuf[j+2]];
int z=decode64tab[(int)(unsigned char)p->workbuf[j+3]];
a= (w << 2) | (x >> 4);
b= (x << 4) | (y >> 2);
c= (y << 6) | z;
p->workbuf[k++]=a;
if ( p->workbuf[j+2] != '=')
p->workbuf[k++]=b;
if ( p->workbuf[j+3] != '=')
p->workbuf[k++]=c;
}
rc=(*p->udecode_func)(p->workbuf, k, p->misc_decode_ptr);
/* Anything left? Move it to the start of the buffer */
k=0;
while (j < p->workbuflen)
p->workbuf[k++]=p->workbuf[j++];
p->workbuflen=k;
return (0);
}
static int decode_qp(struct rfc2045 *p, const char *s, size_t l)
{
size_t start,i;
int rc;
if (!s)
return (do_decode_qp(p));
for (start=0; start<l; )
{
for (i=start; i<l; i++)
{
if (s[i] != '\n') continue;
rfc2045_add_workbuf(p, s+start, i-start);
rfc2045_add_workbufch(p, '\n');
if ((rc=do_decode_qp(p)) != 0) return (rc);
start= ++i;
break;
}
rfc2045_add_workbuf(p, s+start, i-start);
if (p->workbuflen > 1024)
{
char buf[10];
int i;
for (i=p->workbuflen - 5; i<p->workbuflen; i++)
if (p->workbuf[i] == '=') break;
if (i < p->workbuflen)
{
int j=p->workbuflen-i;
memcpy(buf, p->workbuf+i, j);
buf[j]=0;
p->workbuflen=i;
}
else buf[0]=0;
if ((rc=do_decode_qp(p)) != 0) return (rc);
rfc2045_add_workbuf(p, buf, strlen(buf));
}
start=i;
}
return (0);
}
static int decode_base64(struct rfc2045 *p, const char *s, size_t l)
{
if (!s)
return (do_decode_base64(p));
rfc2045_add_workbuf(p, s, l);
if (p->workbuflen > 256)
return (do_decode_base64(p));
return (0);
}
void rfc2045_cdecode_start(struct rfc2045 *p,
int (*u)(const char *, size_t, void *), void *miscptr)
{
p->misc_decode_ptr=miscptr;
p->udecode_func=u;
p->decode_func= &decode_raw;
p->workbuflen=0;
if (p->content_transfer_encoding)
{
if (strcmp(p->content_transfer_encoding,
"quoted-printable") == 0)
p->decode_func= &decode_qp;
else if (strcmp(p->content_transfer_encoding, "base64") == 0)
p->decode_func= &decode_base64;
}
}
int rfc2045_cdecode_end(struct rfc2045 *p)
{
return ((*p->decode_func)(p, NULL, 0));
}
int rfc2045_cdecode(struct rfc2045 *p, const char *s, size_t l)
{
if (s && l) return ((*p->decode_func)(p, s, l));
return (0);
}

View File

@ -1,10 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
/* $Id$ */
#define RFC2045CHARSET "@RFC2045CHARSET@"
#define RFC2045MIMEMSG "This is a MIME-formatted message. If you see this text it means that your\nE-mail software does not support MIME-formatted messages.\n"

View File

@ -1,41 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#include "rfc2045.h"
static void decode(struct rfc2045id *topid,
struct rfc2045id **childidptr,
struct rfc2045 *r,
void (*func)(struct rfc2045 *, struct rfc2045id *, void *),
void *ptr)
{
struct rfc2045id nextid;
*childidptr=0;
(*func)(r, topid, ptr);
*childidptr=&nextid;
nextid.idnum=1;
if (r->content_type && strncmp(r->content_type, "multipart/", 10) == 0)
nextid.idnum=0;
for (r=r->firstpart; r; r=r->next)
{
if (nextid.idnum)
decode(topid, &nextid.next, r, func, ptr);
++nextid.idnum;
}
}
void rfc2045_decode(struct rfc2045 *p,
void (*func)(struct rfc2045 *, struct rfc2045id *, void *),
void *ptr)
{
struct rfc2045id topid;
topid.idnum=1;
decode(&topid, &topid.next, p, func, ptr);
}

View File

@ -1,9 +0,0 @@
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "rfc2045.h"
void rfc2045_enomem()
{
rfc2045_error("Out of memory.");
}

View File

@ -1,50 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#include "rfc2045.h"
#include <ctype.h>
struct rfc2045findstruct {
const char *partnum;
struct rfc2045 *ptr;
} ;
static void do_decode(struct rfc2045 *p, struct rfc2045id *id, void *ptr)
{
struct rfc2045findstruct *fs=(struct rfc2045findstruct *)ptr;
const char *partnum=fs->partnum;
unsigned n;
while (id)
{
if (!isdigit((int)(unsigned char)*partnum)) return;
n=0;
while (isdigit((int)(unsigned char)*partnum))
n=n*10 + *partnum++ - '0';
if (*partnum)
{
if (*partnum != '.') return;
++partnum;
}
if (n != (unsigned)id->idnum) return;
id=id->next;
}
if ( *partnum == '\0') fs->ptr=p;
}
struct rfc2045 *rfc2045_find(struct rfc2045 *p, const char *str)
{
struct rfc2045findstruct fs;
fs.partnum=str;
fs.ptr=0;
rfc2045_decode(p, &do_decode, &fs);
return (fs.ptr);
}

View File

@ -1,82 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "rfc2045.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef __WINDOWS__
#define NUMBUFSIZE 60
#define HAS_GETHOSTNAME 1
#include <windows.h>
#else
#define NUMBUFSIZE 60
#endif
/* $Id$ */
#if HAS_GETHOSTNAME
#else
extern int gethostname(char *, size_t);
#endif
extern void rfc2045_enomem();
char *rfc2045_mk_boundary(struct rfc2045 *s, int fd)
{
char pidbuf[NUMBUFSIZE];
char timebuf[NUMBUFSIZE];
char cntbuf[60];
int cnt=0;
time_t mytime;
#ifndef __WINDOWS__
char hostnamebuf[256];
pid_t mypid;
#endif
char *p;
int rc;
time(&mytime);
#ifdef __WINDOWS__
sprintf(pidbuf, "%ld", GetCurrentThreadId());
sprintf(timebuf, "%ld", (long)mytime);
#else
hostnamebuf[sizeof(hostnamebuf)-1]=0;
if (gethostname(hostnamebuf, sizeof(hostnamebuf)-1))
hostnamebuf[0]=0;
mypid=getpid();
sprintf(pidbuf, "%d", mypid);
sprintf(timebuf, "%ld", mytime);
#endif
for (;;)
{
sprintf(cntbuf, "%d", ++cnt);
p=malloc(strlen(pidbuf)+strlen(timebuf)+
strlen(cntbuf)+10);
if (!p)
{
rfc2045_enomem();
return (NULL);
}
sprintf(p, "=_%s-%s-%s", pidbuf, timebuf, cntbuf);
if ((rc=rfc2045_try_boundary(s, fd, p)) == 0)
break;
free(p);
if (rc < 0)
return (NULL);
}
return (p);
}

View File

@ -1,471 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "rfc2045.h"
#include "rfc2045charset.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef __WINDOWS__
#define strcasecmp stricmp
#define strncasecmp strnicmp
#if (_MSC_VER < 1300)
#define write _write
#endif
#include <io.h>
#endif
/* $Id$ */
static char *rw_boundary_root;
static int rw_boundary_cnt;
static const char *rw_appname;
static FILE *fdin;
static int fdout;
static int (*fdout_func)(const char *, int, void *);
static void *fdout_arg;
static char fdout_buf[512];
static char *fdout_ptr;
static size_t fdout_left;
/* Quoted printable encoding */
static void qpe_start();
static int qpe_do(const char *, size_t, void *);
static void qpe_end();
static int conv_err;
static int fdout_flush()
{
int n=fdout_ptr-fdout_buf;
int i=0;
char *p=fdout_buf;
while (n)
{
i=fdout_func ? (*fdout_func)(p, n, fdout_arg):
write(fdout, p, n);
if (i <= 0) return (-1);
p += i;
n -= i;
}
fdout_ptr=fdout_buf;
fdout_left=sizeof(fdout_buf);
return (0);
}
static int fdout_add(const char *p, size_t cnt)
{
while (cnt)
{
if (cnt < fdout_left)
{
memcpy(fdout_ptr, p, cnt);
fdout_ptr += cnt;
fdout_left -= cnt;
return (0);
}
if (fdout_left == 0)
{
if (fdout_flush()) return (-1);
continue;
}
memcpy(fdout_ptr, p, fdout_left);
p += fdout_left;
cnt -= fdout_left;
fdout_ptr += fdout_left;
fdout_left=0;
}
return (0);
}
static int do_8bit(const char *p, size_t cnt, void *ptr)
{
if (fdout_add(p, cnt))
conv_err=1;
return (0);
}
static int fdout_autoconverted(const char *oldte, const char *newte)
{
if (fdout_add("X-Mime-Autoconverted: from ", 27) ||
fdout_add(oldte, strlen(oldte)) ||
fdout_add(" to ", 4) ||
fdout_add(newte, strlen(newte)) ||
(rw_appname && (fdout_add(" by ", 4) ||
fdout_add(rw_appname, strlen(rw_appname)))) ||
fdout_add("\n", 1)) return (-1);
return (0);
}
static int fdout_value(const char *);
static int fdout_attr(const struct rfc2045attr *a)
{
if (fdout_add(a->name, strlen(a->name))) return (-1);
if (a->value && (fdout_add("=", 1) || fdout_value(a->value)))
return (-1);
return (0);
}
static int fdout_value(const char *v)
{
size_t i,j;
for (i=0; v[i]; i++)
{
if ( !isalnum((int)(unsigned char)v[i]) && v[i] != '-')
{
if (fdout_add("\"", 1)) return (-1);
for (j=i=0; v[i]; i++)
if (v[i] == '\\' || v[i] == '"')
{
if (fdout_add(v+j, i-j) ||
fdout_add("\\", 1))
return (-1);
j=i;
}
if (fdout_add(v+j, i-j) || fdout_add("\"", 1))
return (-1);
return (0);
}
}
return (fdout_add(v, i));
}
#define TE(p) ((p)->rw_transfer_encoding ? \
(p)->rw_transfer_encoding: (p)->content_transfer_encoding)
static int rwmime(struct rfc2045 *p)
{
static char mimever[]="Mime-Version: 1.0\n";
const char *te;
struct rfc2045attr *a;
if (!p->parent)
if (fdout_add(mimever, sizeof(mimever)-1)) return (-1);
if (p->content_type)
{
if (fdout_add("Content-Type: ", 14) ||
fdout_add(p->content_type, strlen(p->content_type)))
return (-1);
for (a=p->content_type_attr; a; a=a->next)
{
if (!a->name || strcmp(a->name, "boundary") == 0)
continue;
if ( fdout_add("; ", 2) ||
fdout_attr(a)) return (-1);
}
}
if (p->firstpart
&& p->firstpart->next /* ADDED 8/30/99, see below */)
{
char buf[80];
++rw_boundary_cnt;
sprintf(buf, "-%d", rw_boundary_cnt);
if ( fdout_add("; boundary=\"", 12) ||
fdout_add(rw_boundary_root, strlen(rw_boundary_root)) ||
fdout_add(buf, strlen(buf)) ||
fdout_add("\"", 1)) return (-1);
}
if (fdout_add("\n", 1)) return (-1);
/* Show content transfer encoding for top section, or if it's
** different than the parent.
*/
te=TE(p);
if (te && (!p->parent || strcmp(te, TE(p->parent))))
{
if (fdout_add("Content-Transfer-Encoding: ", 27) ||
fdout_add(te, strlen(te)) ||
fdout_add("\n", 1)) return (-1);
}
return (0);
}
static int dorw(struct rfc2045 *p)
{
/* WTF STATIC??? */ int seen_mime=0;
char buf[256];
int c;
int bcnt;
if (fseek(fdin, p->startpos, SEEK_SET) == -1) return (-1);
if (p->parent)
{
seen_mime=1;
if (rwmime(p)) return (-1);
}
while (fgets(buf, sizeof(buf), fdin))
{
if (buf[0] == '\n') break;
if (RFC2045_ISMIME1DEF(p->mime_version) &&
strncasecmp(buf, "mime-version:", 13) == 0 &&
!seen_mime)
{
seen_mime=1;
rwmime(p);
if (strchr(buf, '\n') == NULL)
while ((c=getc(fdin)) >= 0 && c != '\n')
;
while ((c=getc(fdin)) >= 0 && c != '\n' && isspace(c))
while ((c=getc(fdin)) >= 0 && c != '\n')
;
if (c >= 0) ungetc(c, fdin);
continue;
}
if (!RFC2045_ISMIME1DEF(p->mime_version) || (
strncasecmp(buf, "mime-version:", 13) &&
strncasecmp(buf, "content-type:", 13) &&
strncasecmp(buf, "content-transfer-encoding:", 26))
)
{
do
{
do
{
if (fdout_add(buf, strlen(buf)))
return (-1);
} while (strchr(buf, '\n') == NULL &&
fgets(buf, sizeof(buf), fdin));
c=getc(fdin);
if (c >= 0) ungetc(c, fdin);
} while (c >= 0 && c != '\n' && isspace(c) &&
fgets(buf, sizeof(buf), fdin));
}
else
while ( (c=getc(fdin)) >= 0 &&
(ungetc(c, fdin), c) != '\n' && isspace(c))
{
while (fgets(buf, sizeof(buf), fdin) &&
strchr(buf, '\n') == NULL)
;
}
}
if (RFC2045_ISMIME1DEF(p->mime_version))
{
if (!seen_mime)
if (rwmime(p)) return (-1);
if (!p->firstpart && p->rw_transfer_encoding)
if (fdout_autoconverted(p->content_transfer_encoding,
p->rw_transfer_encoding)) return (-1);
}
if (fdout_add("\n", 1)) return (-1);
if (fseek(fdin, p->startbody, SEEK_SET) == -1) return (-1);
/* For non-multipart section, just print the body */
if (!p->firstpart)
{
off_t ps=p->startbody;
int convmode=0;
if (p->rw_transfer_encoding)
{
if ( strcasecmp(p->rw_transfer_encoding,
"quoted-printable") == 0)
convmode=RFC2045_RW_7BIT;
else
convmode=RFC2045_RW_8BIT;
}
conv_err=0;
if (convmode == RFC2045_RW_7BIT)
{
qpe_start();
rfc2045_cdecode_start(p, &qpe_do, 0);
}
if (convmode == RFC2045_RW_8BIT)
{
rfc2045_cdecode_start(p, &do_8bit, 0);
}
while (ps < p->endbody)
{
int n;
if (p->endbody - ps > sizeof(buf))
n=sizeof(buf);
else n=p->endbody-ps;
n=fread(buf, 1, n, fdin);
if (n <= 0) return (-1);
if (convmode)
rfc2045_cdecode(p, buf, n);
else if (fdout_add(buf, n)) conv_err=1;
ps += n;
if (conv_err) break;
}
if (convmode == RFC2045_RW_7BIT)
{
rfc2045_cdecode_end(p);
qpe_end();
}
if (convmode == RFC2045_RW_8BIT)
{
rfc2045_cdecode_end(p);
}
if (conv_err) return (-1);
return (0);
}
bcnt=rw_boundary_cnt;
/* Sam 8/30/99 fix - handle message/rfc822:
--boundary
Content-Type: message/rfc822
--><-- we're here, DON'T add RFC2045MIMEMSG and rest of crap here
*/
if (p->firstpart->next == 0)
{
int rc;
p->firstpart->parent=0;
rc=dorw(p->firstpart);
p->firstpart->parent=p;
return (rc);
}
if (fdout_add(RFC2045MIMEMSG, sizeof(RFC2045MIMEMSG)-1))
return (-1);
for (p=p->firstpart; p; p=p->next)
{
if (p->isdummy) continue;
sprintf(buf, "\n--%s-%d\n", rw_boundary_root, bcnt);
if (fdout_add(buf, strlen(buf))) return (-1);
if (dorw(p) != 0) return(-1);
}
sprintf(buf, "\n--%s-%d--\n", rw_boundary_root, bcnt);
if (fdout_add(buf, strlen(buf))) return (-1);
return (0);
}
static int rfc2045_rewrite_common(struct rfc2045 *, int, const char *);
int rfc2045_rewrite(struct rfc2045 *p, int fdin_arg, int fdout_arg,
const char *appname)
{
fdout=fdout_arg;
fdout_func=0;
return (rfc2045_rewrite_common(p, fdin_arg, appname));
}
int rfc2045_rewrite_func(struct rfc2045 *p, int fdin_arg,
int (*funcarg)(const char *, int, void *), void *funcargarg,
const char *appname)
{
fdout= -1;
fdout_func=funcarg;
fdout_arg=funcargarg;
return (rfc2045_rewrite_common(p, fdin_arg, appname));
}
static int rfc2045_rewrite_common(struct rfc2045 *p,
int fdin_arg, const char *appname)
{
int rc;
int fd=dup(fdin_arg);
if (fd < 0) return (-1);
rw_appname=appname;
fdin=fdopen(fd, "r");
if (!fdin)
{
close(fd);
return (-1);
}
fdout_ptr=fdout_buf;
fdout_left=sizeof(fdout_buf);
rw_boundary_root=rfc2045_mk_boundary(p, fd);
if (rw_boundary_root == 0)
rc= -1;
else
{
rw_boundary_cnt=1;
rc=dorw(p);
free(rw_boundary_root);
}
if (rc == 0 && fdout_ptr > fdout_buf)
rc=fdout_flush();
fclose(fdin);
return (rc);
}
static int qpe_pos;
static void qpe_start()
{
qpe_pos=0;
}
static int qpe_do(const char *p, size_t i, void *ptr)
{
size_t j,k;
if (conv_err) return (0);
for (j=k=0; j<i; j++)
{
if (p[j] == '\n')
{
if (fdout_add(p+k, j+1-k)) conv_err=1;
k=j+1;
qpe_pos=0;
continue;
}
if (qpe_pos >= 72)
{
if (fdout_add(p+k, j-k) ||
fdout_add("=\n", 2)) conv_err=1;
k=j;
qpe_pos=0;
}
if (p[j] < 32 || p[j] >= 127 || p[j] == '=')
{
char buf[3];
static char xdigit[16]="0123456789ABCDEF";
unsigned n= (unsigned char)p[j];
buf[0]='=';
buf[1]=xdigit[ n / 16];
buf[2]=xdigit[ n % 16];
if (fdout_add(p+k, j-k) ||
fdout_add(buf, 3)) conv_err=1;
qpe_pos += 2;
k=j+1;
}
++qpe_pos;
}
if (fdout_add(p+k, j-k)) conv_err=1;
return (0);
}
static void qpe_end()
{
}

View File

@ -1,125 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "rfc2045.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef __WINDOWS__
#define strncasecmp strnicmp
#include <io.h>
#define read _read
#define lseek _lseek
#endif
/* $Id$ */
extern void rfc2045_add_buf( char **, size_t *, size_t *,
const char *, size_t);
static const char *boundary_chk_val;
static size_t boundary_chk_val_len;
static char *boundary_chk_buf;
static size_t boundary_chk_bufsize, boundary_chk_buflen;
static int boundary_chk_flag;
static void boundary_chk_add(const char *p, size_t l)
{
if (boundary_chk_buflen < boundary_chk_val_len+20)
rfc2045_add_buf( &boundary_chk_buf,
&boundary_chk_bufsize,
&boundary_chk_buflen, p, l);
}
static int boundary_chk(const char *p, size_t l, void *ptr)
{
static size_t i, j;
for (j=i=0; i<l; i++)
{
if (p[i] == '\n')
{
boundary_chk_add(p+j, i-j);
if (boundary_chk_buflen >= boundary_chk_val_len+2 &&
boundary_chk_buf[0] == '-' &&
boundary_chk_buf[1] == '-' &&
strncasecmp(boundary_chk_val,
boundary_chk_buf+2,
boundary_chk_val_len) == 0)
boundary_chk_flag=1;
boundary_chk_buflen=0;
j=i+1;
}
}
boundary_chk_add(p+j, l-j);
return (0);
}
static int try_boundary(struct rfc2045 *p, int fd)
{
int rc;
char buf[512];
int n, cnt;
off_t ps;
if (p->firstpart)
{
for (p=p->firstpart; p; p=p->next)
if ((rc=try_boundary(p, fd)) != 0)
return (rc);
return (0);
}
if (p->content_transfer_encoding &&
strcmp(p->content_transfer_encoding, "base64") == 0)
return (0);
boundary_chk_flag=0;
boundary_chk_buflen=0;
if (lseek(fd, p->startbody, SEEK_SET) == -1) return (-1);
rfc2045_cdecode_start(p, boundary_chk, 0);
ps=p->startbody;
while (ps < p->endbody)
{
if (p->endbody - ps < sizeof(buf))
cnt=p->endbody-ps;
else cnt=sizeof(buf);
n=read(fd, buf, cnt);
if (n <= 0) return (-1);
rfc2045_cdecode(p, buf, n);
ps += n;
if (boundary_chk_flag) break;
}
rfc2045_cdecode_end(p);
if (boundary_chk_buflen)
boundary_chk("\n", 1, 0); /* Flush out partial line */
return (boundary_chk_flag);
}
int rfc2045_try_boundary(struct rfc2045 *p, int fd, const char *boundary)
{
int n;
boundary_chk_val_len=strlen(boundary_chk_val=boundary);
boundary_chk_buf=0;
boundary_chk_bufsize=0;
n=try_boundary(p, fd);
if (boundary_chk_buf) free(boundary_chk_buf);
return (n);
}

View File

@ -1,48 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
** distribution information.
*/
/*
** $Id$
*/
#include <stdio.h>
#include "rfc2045.h"
#define DUMP(s,n) if ( (s) ) { printf("%*s%s: %s\n", level*4, "", n, (s)); }
/* Extended RFC2045 dump */
static void dodump(struct rfc2045 *p, int level)
{
if (!p->isdummy)
{
printf("%*sMessage start %ld, end %ld, startbody %ld, endbody %ld.\n", level*4,
"", (long)p->startpos, (long)p->endpos,
(long)p->startbody, (long)p->endbody);
DUMP(p->mime_version, "Mime-Version")
DUMP(p->content_type, "Content-Type")
DUMP(rfc2045_getattr(p->content_type_attr, "charset"),
"Charset")
DUMP(p->content_transfer_encoding, "Transfer Encoding")
DUMP(rfc2045_getattr(p->content_type_attr, "boundary"),
"Boundary")
DUMP(p->content_disposition, "Content Disposition")
DUMP(rfc2045_getattr(p->content_disposition_attr, "name"),
"Disposition Name")
DUMP(rfc2045_getattr(p->content_disposition_attr, "filename"),
"Disposition Filename")
}
for (p=p->firstpart; p; p=p->next)
{
printf("%*s{\n", level*4, "");
dodump(p, level+1);
printf("%*s}\n", level*4, "");
}
}
void rfc2045_xdump(struct rfc2045 *p)
{
dodump(p, 0);
}

View File

@ -1,33 +0,0 @@
[Aug 18 2009]
* CLEANUP: Bug#413: Complete 'make distclean'. Feliks Kluzniak
[Mar 19 2009]
* CLEANUP: Removed all trailing whitespace from all source-files.
This avoids many GIT (merge) warnings.
[Sep 11 2008]
* PORT: Add AC_PREREQ to configure.h for systems that auto-select autoconf
versions. After tip by Ulrich Neumerkel.
[Aug 11 2008]
* INSTALL: Remove all configure files from the git repository
Mon Apr 5 00:58:37 EDT 1999
* Yes, I've decided to start a Change Log. librfc822 now has a life of its
own, so it might as well have it.
* Courier needs tokens in a link list, not an array. Rewrote most token
handling code.
* Fixed some issues with handling of () comments.
* Changed *pr* functions to pass along a caller-provided void, also for
courier. librfc822 should now be threadable (like, who cares...)
* Added a testsuite

View File

@ -1,42 +0,0 @@
################################################################
# Makefile for librfc822.a
#
# Author: Jan Wielemaker (wielemak@science.uva.nl)
################################################################
CC=@CC@
CFLAGS=@MAILDROP_CFLAGS@ @DEFS@
LIBS=@LIBS@
AR=@AR@
RANLIB=@RANLIB@
srcdir=@srcdir@
OBJ= rfc822.o rfc822_getaddr.o rfc822_getaddrs.o \
rfc822_mkdate.o rfc822_parsedt.o rfc2047u.o \
rfc2047.o imapsubj.o imaprefs.o
all: librfc822.a
librfc822.a: $(OBJ)
rm -f librfc822.a
$(AR) r librfc822.a $(OBJ)
$(RANLIB) librfc822.a
#
# find out how to generate .o files from $(scrdir)
#
%.o: $(srcdir)/%.c
$(CC) -c $(CFLAGS) $< -o $@
################################################################
# Clean
################################################################
clean:
rm -f $(OBJ) *~ *.o *% a.out core config.log
distclean: clean
rm -f Makefile config.status config.h librfc822.a
rm -rf autom4te.cache
rm -f stamp-h1

View File

@ -1,32 +0,0 @@
# Destinations. Please edit
prefix=c:\Documents and Settings\jan
LIBDIR=$(prefix)\lib64
INCDIR=$(prefix)\include
CC=cl.exe
AR=lib.exe
CFLAGS=/MD /W3 /O2 /EHsc /DNDEBUG /D__WINDOWS__ /I.. /nologo /c
OUT=rfc822.lib
OBJ= rfc822.obj rfc822_getaddr.obj rfc822_getaddrs.obj \
rfc822_mkdate.obj rfc822_parsedt.obj rfc2047u.obj \
rfc2047.obj imapsubj.obj imaprefs.obj
.c.obj:
@$(CC) $(CFLAGS) /Fo$@ $<
$(OUT): $(OBJ)
del $@
$(AR) /out:$@ /nologo $(OBJ)
install: $(OUT)
copy $(OUT) "$(LIBDIR)"
copy rfc822.h "$(INCDIR)"
clean::
del *~ *.obj
distclean: clean
del $(OUT)

File diff suppressed because it is too large Load Diff

View File

@ -1,105 +0,0 @@
dnl Process this file with autoconf to produce a configure script.
dnl $Id$
dnl
dnl Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
dnl distribution information.
AC_INIT(rfc822.c)
AC_PREREQ([2.50])
AC_CONFIG_HEADER(config.h)
AC_SUBST(AR)
dnl Checks for programs.
AC_PROG_CC
AC_CHECK_PROG(AR, ar, ar, ar)
AC_PROG_RANLIB
AC_USE_SYSTEM_EXTENSIONS
if test "$GCC" = yes ; then
CXXFLAGS="$CXXFLAGS -Wall"
CFLAGS="$CFLAGS -Wall"
fi
dnl Checks for libraries.
dnl Checks for header files.
AC_HEADER_STDC
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
AC_STRUCT_TM
dnl Checks for library functions.
AC_CHECK_FUNCS(strcasecmp strncasecmp)
AC_CACHE_CHECK([how to calculate alternate timezone],librfc822_cv_SYS_TIMEZONE,
AC_TRY_COMPILE([
#include <time.h>
],[
int main()
{
time_t t=altzone;
int offset = -timezone;
return (0);
}
], librfc822_cv_SYS_TIMEZONE=altzone,
AC_TRY_COMPILE([
#include <time.h>
],[
int main()
{
int n=daylight;
int offset = -timezone;
return (0);
}
], librfc822_cv_SYS_TIMEZONE=daylight,
AC_TRY_COMPILE([
#include <time.h>
extern struct tm dummy;
],[
int main()
{
long n=dummy.tm_gmtoff;
return (0);
}
] ,librfc822_cv_SYS_TIMEZONE=tm_gmtoff,
librfc822_cv_SYS_TIMEZONE=unknown
)
)
)
)
case $librfc822_cv_SYS_TIMEZONE in
tm_gmtoff)
AC_DEFINE_UNQUOTED(USE_TIME_GMTOFF,1,
[Whether time offset is specified via the tm_gmtoff member])
;;
altzone)
AC_DEFINE_UNQUOTED(USE_TIME_ALTZONE,1,
[Whether daylight savings time offset is set via the altzone variable])
;;
daylight)
AC_DEFINE_UNQUOTED(USE_TIME_DAYLIGHT,1,
[Whether daylight savings time offset is set via the tm_isdst member])
;;
*)
AC_MSG_WARN(Cannot figure out how to calculate the alternate timezone, will use GMT)
;;
esac
if test -d ../unicode
then
AC_DEFINE_UNQUOTED(HAVE_LIBUNICODE,1,[Whether we have libunicode.a])
fi
AC_OUTPUT(Makefile)

View File

@ -1,921 +0,0 @@
/*
** Copyright 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#ifndef __WINDOWS__
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "rfc822.h"
#include "imaprefs.h"
static void swapmsgdata(struct imap_refmsg *a, struct imap_refmsg *b)
{
char *cp;
char c;
time_t t;
unsigned long ul;
#define swap(a,b,tmp) (tmp)=(a); (a)=(b); (b)=(tmp);
swap(a->msgid, b->msgid, cp);
swap(a->isdummy, b->isdummy, c);
swap(a->flag2, b->flag2, c);
swap(a->timestamp, b->timestamp, t);
swap(a->seqnum, b->seqnum, ul);
#undef swap
}
struct imap_refmsgtable *rfc822_threadalloc()
{
struct imap_refmsgtable *p;
p=(struct imap_refmsgtable *)malloc(sizeof(struct imap_refmsgtable));
if (p)
memset(p, 0, sizeof(*p));
return (p);
}
void rfc822_threadfree(struct imap_refmsgtable *p)
{
int i;
struct imap_refmsghash *h;
struct imap_subjlookup *s;
struct imap_refmsg *m;
for (i=0; i<sizeof(p->hashtable)/sizeof(p->hashtable[0]); i++)
while ((h=p->hashtable[i]) != 0)
{
p->hashtable[i]=h->nexthash;
free(h);
}
for (i=0; i<sizeof(p->subjtable)/sizeof(p->subjtable[0]); i++)
while ((s=p->subjtable[i]) != 0)
{
p->subjtable[i]=s->nextsubj;
free(s->subj);
free(s);
}
while ((m=p->firstmsg) != 0)
{
p->firstmsg=m->next;
if (m->subj)
free(m->subj);
free(m);
}
free(p);
}
static int hashmsgid(const char *msgid)
{
unsigned long hashno=0;
while (*msgid)
{
unsigned long n= (hashno << 1);
#define HMIDS (((struct imap_refmsgtable *)0)->hashtable)
#define HHMIDSS ( sizeof(HMIDS) / sizeof( HMIDS[0] ))
if (hashno & HHMIDSS )
n ^= 1;
hashno= n ^ (unsigned char)*msgid++;
}
return (hashno % HHMIDSS);
}
struct imap_refmsg *rfc822_threadallocmsg(struct imap_refmsgtable *mt,
const char *msgid)
{
int n=hashmsgid(msgid);
struct imap_refmsg *msgp= (struct imap_refmsg *)
malloc(sizeof(struct imap_refmsg)+1+strlen(msgid));
struct imap_refmsghash *h, **hp;
if (!msgp) return (0);
memset(msgp, 0, sizeof(*msgp));
strcpy ((msgp->msgid=(char *)(msgp+1)), msgid);
h=(struct imap_refmsghash *)malloc(sizeof(struct imap_refmsghash));
if (!h)
{
free(msgp);
return (0);
}
for (hp= &mt->hashtable[n]; *hp; hp= & (*hp)->nexthash)
{
if (strcmp( (*hp)->msg->msgid, msgp->msgid) > 0)
break;
}
h->nexthash= *hp;
*hp=h;
h->msg=msgp;
msgp->last=mt->lastmsg;
if (mt->lastmsg)
mt->lastmsg->next=msgp;
else
mt->firstmsg=msgp;
mt->lastmsg=msgp;
return (msgp);
}
struct imap_refmsg *rfc822_threadsearchmsg(struct imap_refmsgtable *mt,
const char *msgid)
{
int n=hashmsgid(msgid);
struct imap_refmsghash *h;
for (h= mt->hashtable[n]; h; h= h->nexthash)
{
int rc=strcmp(h->msg->msgid, msgid);
if (rc == 0) return (h->msg);
if (rc > 0)
break;
}
return (0);
}
static int findsubj(struct imap_refmsgtable *mt, const char *s, int *isrefwd,
int create, struct imap_subjlookup **ptr)
{
char *ss=rfc822_coresubj(s, isrefwd);
int n;
struct imap_subjlookup **h;
struct imap_subjlookup *newsubj;
if (!ss) return (-1);
n=hashmsgid(ss);
for (h= &mt->subjtable[n]; *h; h= &(*h)->nextsubj)
{
int rc=strcmp((*h)->subj, ss);
if (rc == 0)
{
free(ss);
*ptr= *h;
return (0);
}
if (rc > 0)
break;
}
if (!create)
{
free(ss);
*ptr=0;
return (0);
}
newsubj=malloc(sizeof(struct imap_subjlookup));
if (!newsubj)
{
free(ss);
return (-1);
}
memset(newsubj, 0, sizeof(*newsubj));
newsubj->subj=ss;
newsubj->nextsubj= *h;
newsubj->msgisrefwd= *isrefwd;
*h=newsubj;
*ptr=newsubj;
return (0);
}
static void linkparent(struct imap_refmsg *msg, struct imap_refmsg *lastmsg)
{
msg->parent=lastmsg;
msg->prevsib=lastmsg->lastchild;
if (msg->prevsib)
msg->prevsib->nextsib=msg;
else
lastmsg->firstchild=msg;
lastmsg->lastchild=msg;
msg->nextsib=0;
}
static void breakparent(struct imap_refmsg *m)
{
if (!m->parent) return;
if (m->prevsib) m->prevsib->nextsib=m->nextsib;
else m->parent->firstchild=m->nextsib;
if (m->nextsib) m->nextsib->prevsib=m->prevsib;
else m->parent->lastchild=m->prevsib;
m->parent=0;
}
static struct imap_refmsg *dorefcreate(struct imap_refmsgtable *mt,
const char *newmsgid,
struct rfc822a *a)
/* a - references header */
{
struct imap_refmsg *lastmsg=0, *m;
struct imap_refmsg *msg;
int n;
/*
(A) Using the Message-IDs in the message's references, link
the corresponding messages together as parent/child. Make
the first reference the parent of the second (and the second
a child of the first), the second the parent of the third
(and the third a child of the second), etc. The following
rules govern the creation of these links:
If no reference message can be found with a given
Message-ID, create a dummy message with this ID. Use
this dummy message for all subsequent references to this
ID.
*/
for (n=0; n<a->naddrs; n++)
{
char *msgid=rfc822_getaddr(a, n);
msg=*msgid ? rfc822_threadsearchmsg(mt, msgid ? msgid:""):0;
if (!msg)
{
msg=rfc822_threadallocmsg(mt, msgid ? msgid:"");
if (!msg)
{
if (msgid)
free(msgid);
return (0);
}
msg->isdummy=1;
}
if (msgid)
free(msgid);
/*
If a reference message already has a parent, don't change
the existing link.
*/
if (lastmsg == 0 || msg->parent)
{
lastmsg=msg;
continue;
}
/*
Do not create a parent/child link if creating that link
would introduce a loop. For example, before making
message A the parent of B, make sure that A is not a
descendent of B.
*/
for (m=lastmsg; m; m=m->parent)
if (strcmp(m->msgid, msg->msgid) == 0)
break;
if (m)
{
lastmsg=msg;
continue;
}
linkparent(msg, lastmsg);
lastmsg=msg;
}
/*
(B) Create a parent/child link between the last reference
(or NIL if there are no references) and the current message.
If the current message has a parent already, break the
current parent/child link before creating the new one. Note
that if this message has no references, that it will now
have no parent.
NOTE: The parent/child links MUST be kept consistent with
one another at ALL times.
*/
msg=*newmsgid ? rfc822_threadsearchmsg(mt, newmsgid):0;
/*
If a message does not contain a Message-ID header line,
or the Message-ID header line does not contain a valid
Message ID, then assign a unique Message ID to this
message.
Implementation note: empty msgid, plus dupe check below,
implements that.
*/
if (msg && msg->isdummy)
{
msg->isdummy=0;
if (msg->parent)
breakparent(msg);
}
else
{
#if 1
/*
** If two or more messages have the same Message ID, assign
** a unique Message ID to each of the duplicates.
**
** Implementation note: just unlink the existing message from
** it's parents/children.
*/
if (msg)
{
while (msg->firstchild)
breakparent(msg->firstchild);
breakparent(msg);
newmsgid="";
/* Create new entry with an empty msgid, if any more
** msgids come, they'll hit the dupe check again.
*/
}
#endif
msg=rfc822_threadallocmsg(mt, newmsgid);
if (!msg) return (0);
}
if (lastmsg)
{
for (m=lastmsg; m; m=m->parent)
if (strcmp(m->msgid, msg->msgid) == 0)
break;
if (!m)
linkparent(msg, lastmsg);
}
return (msg);
}
struct imap_refmsg *rfc822_threadmsg(struct imap_refmsgtable *mt,
const char *msgidhdr,
const char *refhdr,
const char *subjheader,
const char *dateheader,
unsigned long seqnum)
{
struct rfc822t *t;
struct rfc822a *a;
struct imap_refmsg *m;
char *msgid_s;
t=rfc822t_alloc(msgidhdr ? msgidhdr:"", 0);
if (!t)
return (0);
a=rfc822a_alloc(t);
if (!a)
{
rfc822t_free(t);
return (0);
}
msgid_s=a->naddrs > 0 ? rfc822_getaddr(a, 0):strdup("");
rfc822a_free(a);
rfc822t_free(t);
if (!msgid_s)
return (0);
t=rfc822t_alloc(refhdr ? refhdr:"", 0);
if (!t)
{
free(msgid_s);
return (0);
}
a=rfc822a_alloc(t);
if (!a)
{
rfc822t_free(t);
free(msgid_s);
return (0);
}
m=dorefcreate(mt, msgid_s, a);
rfc822a_free(a);
rfc822t_free(t);
free(msgid_s);
if (!m)
return (0);
if (subjheader && (m->subj=strdup(subjheader)) == 0)
return (0); /* Cleanup in rfc822_threadfree() */
m->timestamp=dateheader ? rfc822_parsedt(dateheader):0;
m->seqnum=seqnum;
return (m);
}
/*
(2) Gather together all of the messages that have no parents
and make them all children (siblings of one another) of a dummy
parent (the "root"). These messages constitute first messages
of the threads created thus far.
*/
struct imap_refmsg *rfc822_threadgetroot(struct imap_refmsgtable *mt)
{
struct imap_refmsg *root, *m;
if (mt->rootptr)
return (mt->rootptr);
root=rfc822_threadallocmsg(mt, "(root)");
if (!root) return (0);
root->parent=root; /* Temporary */
root->isdummy=1;
for (m=mt->firstmsg; m; m=m->next)
if (!m->parent)
{
if (m->isdummy && m->firstchild == 0)
continue; /* Can happen in reference creation */
linkparent(m, root);
}
root->parent=NULL;
return (mt->rootptr=root);
}
/*
**
** (3) Prune dummy messages from the thread tree. Traverse each
** thread under the root, and for each message:
*/
void rfc822_threadprune(struct imap_refmsgtable *mt)
{
struct imap_refmsg *msg;
for (msg=mt->firstmsg; msg; msg=msg->next)
{
struct imap_refmsg *saveparent, *m;
if (!msg->parent)
continue; // The root, need it later.
if (!msg->isdummy)
continue;
/*
**
** If it is a dummy message with NO children, delete it.
*/
if (msg->firstchild == 0)
{
breakparent(msg);
/*
** Don't free the node, it'll be done on msgtable
** purge.
*/
continue;
}
/*
** If it is a dummy message with children, delete it, but
** promote its children to the current level. In other words,
** splice them in with the dummy's siblings.
**
** Do not promote the children if doing so would make them
** children of the root, unless there is only one child.
*/
if (msg->firstchild->nextsib &&
msg->parent->parent)
continue;
saveparent=msg->parent;
breakparent(msg);
while ((m=msg->firstchild) != 0)
{
breakparent(m);
linkparent(m, saveparent);
}
}
}
/*
** (4) Gather together messages under the root that have the same
** extracted subject text.
**
** (A) Create a table for associating extracted subjects with
** messages.
**
** (B) Populate the subject table with one message per
** extracted subject. For each message under the root:
*/
int rfc822_threadsortsubj(struct imap_refmsgtable *mt,
struct imap_refmsg *root)
{
struct imap_refmsg *toproot, *p;
for (toproot=root->firstchild; toproot; toproot=toproot->nextsib)
{
const char *subj;
struct imap_subjlookup *subjtop;
int isrefwd;
/*
** (i) Find the subject of this thread by extracting the
** base subject from the current message, or its first child
** if the current message is a dummy.
*/
p=toproot;
if (p->isdummy)
p=p->firstchild;
subj=p->subj ? p->subj:"";
/*
** (ii) If the extracted subject is empty, skip this
** message.
*/
if (*subj == 0)
continue;
/*
** (iii) Lookup the message associated with this extracted
** subject in the table.
*/
if (findsubj(mt, subj, &isrefwd, 1, &subjtop))
return (-1);
/*
**
** (iv) If there is no message in the table with this
** subject, add the current message and the extracted
** subject to the subject table.
*/
if (subjtop->msg == 0)
{
subjtop->msg=toproot;
subjtop->msgisrefwd=isrefwd;
continue;
}
/*
** Otherwise, replace the message in the table with the
** current message if the message in the table is not a
** dummy AND either of the following criteria are true:
*/
if (!subjtop->msg->isdummy)
{
/*
** The current message is a dummy
**
*/
if (toproot->isdummy)
{
subjtop->msg=toproot;
subjtop->msgisrefwd=isrefwd;
continue;
}
/*
** The message in the table is a reply or forward (its
** original subject contains a subj-refwd part and/or a
** "(fwd)" subj-trailer) and the current message is
not.
*/
if (subjtop->msgisrefwd && !isrefwd)
{
subjtop->msg=toproot;
subjtop->msgisrefwd=isrefwd;
}
}
}
return (0);
}
/*
** (C) Merge threads with the same subject. For each message
** under the root:
*/
int rfc822_threadmergesubj(struct imap_refmsgtable *mt,
struct imap_refmsg *root)
{
struct imap_refmsg *toproot, *p, *q, *nextroot;
char *str;
for (toproot=root->firstchild; toproot; toproot=nextroot)
{
const char *subj;
struct imap_subjlookup *subjtop;
int isrefwd;
nextroot=toproot->nextsib;
/*
** (i) Find the subject of this thread as in step 4.B.i
** above.
*/
p=toproot;
if (p->isdummy)
p=p->firstchild;
subj=p->subj ? p->subj:"";
/*
** (ii) If the extracted subject is empty, skip this
** message.
*/
if (*subj == 0)
continue;
/*
** (iii) Lookup the message associated with this extracted
** subject in the table.
*/
if (findsubj(mt, subj, &isrefwd, 0, &subjtop) || subjtop == 0)
return (-1);
/*
** (iv) If the message in the table is the current message,
** skip it.
*/
/* NOTE - ptr comparison IS NOT LEGAL */
subjtop->msg->flag2=1;
if (toproot->flag2)
{
toproot->flag2=0;
continue;
}
subjtop->msg->flag2=0;
/*
** Otherwise, merge the current message with the one in the
** table using the following rules:
**
** If both messages are dummies, append the current
** message's children to the children of the message in
** the table (the children of both messages become
** siblings), and then delete the current message.
*/
if (subjtop->msg->isdummy && toproot->isdummy)
{
while ((p=toproot->firstchild) != 0)
{
breakparent(p);
linkparent(p, subjtop->msg);
}
breakparent(toproot);
continue;
}
/*
** If the message in the table is a dummy and the current
** message is not, make the current message a child of
** the message in the table (a sibling of it's children).
*/
if (subjtop->msg->isdummy)
{
breakparent(toproot);
linkparent(toproot, subjtop->msg);
continue;
}
/*
** If the current message is a reply or forward and the
** message in the table is not, make the current message
** a child of the message in the table (a sibling of it's
** children).
*/
if (isrefwd)
{
p=subjtop->msg;
if (p->isdummy)
p=p->firstchild;
subj=p->subj ? p->subj:"";
str=rfc822_coresubj(subj, &isrefwd);
if (!str)
return (-1);
free(str); /* Don't really care */
if (!isrefwd)
{
breakparent(toproot);
linkparent(toproot, subjtop->msg);
continue;
}
}
/*
** Otherwise, create a new dummy container and make both
** messages children of the dummy, and replace the
** message in the table with the dummy message.
*/
/* What we do is create a new message, then move the
** contents of subjtop->msg (including its children)
** to the new message, then make the new message a child
** of subjtop->msg, and mark subjtop->msg as a dummy msg.
*/
q=rfc822_threadallocmsg(mt, "(dummy)");
if (!q)
return (-1);
q->isdummy=1;
swapmsgdata(q, subjtop->msg);
while ((p=subjtop->msg->firstchild) != 0)
{
breakparent(p);
linkparent(p, q);
}
linkparent(q, subjtop->msg);
breakparent(toproot);
linkparent(toproot, subjtop->msg);
}
return (0);
}
/*
** (5) Traverse the messages under the root and sort each set of
** siblings by date. Traverse the messages in such a way that the
** "youngest" set of siblings are sorted first, and the "oldest"
** set of siblings are sorted last (grandchildren are sorted
** before children, etc). In the case of an exact match on date,
** use the order in which the messages appear in the mailbox (that
** is, by sequence number) to determine the order. In the case of
** a dummy message (which can only occur with top-level siblings),
** use its first child for sorting.
*/
static int cmp_msgs(const void *a, const void *b)
{
struct imap_refmsg *ma=*(struct imap_refmsg **)a;
struct imap_refmsg *mb=*(struct imap_refmsg **)b;
time_t ta, tb;
unsigned long na, nb;
while (ma && ma->isdummy)
ma=ma->firstchild;
while (mb && mb->isdummy)
mb=mb->firstchild;
ta=tb=0;
na=nb=0;
if (ma)
{
ta=ma->timestamp;
na=ma->seqnum;
}
if (mb)
{
tb=mb->timestamp;
nb=mb->seqnum;
}
return (ta < tb ? -1: ta > tb ? 1:
na < nb ? -1: na > nb ? 1:0);
}
struct imap_threadsortinfo {
struct imap_refmsgtable *mt;
struct imap_refmsg **sort_table;
size_t sort_table_cnt;
} ;
static int dothreadsort(struct imap_threadsortinfo *,
struct imap_refmsg *);
int rfc822_threadsortbydate(struct imap_refmsgtable *mt)
{
struct imap_threadsortinfo itsi;
int rc;
itsi.mt=mt;
itsi.sort_table=0;
itsi.sort_table_cnt=0;
rc=dothreadsort(&itsi, mt->rootptr);
if (itsi.sort_table)
free(itsi.sort_table);
return (rc);
}
static int dothreadsort(struct imap_threadsortinfo *itsi,
struct imap_refmsg *p)
{
struct imap_refmsg *q;
size_t i, n;
for (q=p->firstchild; q; q=q->nextsib)
dothreadsort(itsi, q);
n=0;
for (q=p->firstchild; q; q=q->nextsib)
++n;
if (n > itsi->sort_table_cnt)
{
struct imap_refmsg **new_array=(struct imap_refmsg **)
(itsi->sort_table ?
realloc(itsi->sort_table,
sizeof(struct imap_refmsg *)*n)
:malloc(sizeof(struct imap_refmsg *)*n));
if (!new_array)
return (-1);
itsi->sort_table=new_array;
itsi->sort_table_cnt=n;
}
n=0;
while ((q=p->firstchild) != 0)
{
breakparent(q);
itsi->sort_table[n++]=q;
}
qsort(itsi->sort_table, n, sizeof(struct imap_refmsg *), cmp_msgs);
for (i=0; i<n; i++)
linkparent(itsi->sort_table[i], p);
return (0);
}
struct imap_refmsg *rfc822_thread(struct imap_refmsgtable *mt)
{
if (!mt->rootptr)
{
rfc822_threadprune(mt);
if ((mt->rootptr=rfc822_threadgetroot(mt)) == 0)
return (0);
if (rfc822_threadsortsubj(mt, mt->rootptr) ||
rfc822_threadmergesubj(mt, mt->rootptr) ||
rfc822_threadsortbydate(mt))
{
mt->rootptr=0;
return (0);
}
}
return (mt->rootptr);
}

View File

@ -1,97 +0,0 @@
/*
** $Id$
*/
#ifndef imaprefs_h
#define imaprefs_h
/*
** Copyright 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
** Implement REFERENCES threading.
*/
/* The data structures */
struct imap_refmsg {
struct imap_refmsg *next, *last; /* Link list of all msgs */
struct imap_refmsg *parent; /* my parent */
struct imap_refmsg *firstchild, *lastchild; /* Children link list */
struct imap_refmsg *prevsib, *nextsib; /* Link list of siblings */
char isdummy; /* this is a dummy node (for now) */
char flag2; /* Additional flag */
char *msgid; /* msgid of this message */
char *subj; /* dynalloced subject of this msg */
time_t timestamp; /* Timestamp */
unsigned long seqnum; /* Sequence number */
} ;
struct imap_refmsgtable {
struct imap_refmsg *firstmsg, *lastmsg; /* Link list of all msgs */
/* hash table message id lookup */
struct imap_refmsghash *hashtable[512];
struct imap_subjlookup *subjtable[512];
struct imap_refmsg *rootptr; /* The root */
} ;
struct imap_refmsgtable *rfc822_threadalloc(void);
void rfc822_threadfree(struct imap_refmsgtable *);
struct imap_refmsg *rfc822_threadmsg(struct imap_refmsgtable *mt,
const char *msgidhdr,
const char *refhdr,
const char *subjheader,
const char *dateheader,
unsigned long seqnum);
struct imap_refmsg *rfc822_thread(struct imap_refmsgtable *mt);
/* INTERNAL FUNCTIONS FOLLOW */
struct imap_refmsghash {
struct imap_refmsghash *nexthash;
struct imap_refmsg *msg;
} ;
struct imap_subjlookup {
struct imap_subjlookup *nextsubj;
char *subj;
struct imap_refmsg *msg;
int msgisrefwd;
} ;
struct imap_refmsg *rfc822_threadallocmsg(struct imap_refmsgtable *mt,
const char *msgid);
void rfc822_threadprune(struct imap_refmsgtable *mt);
struct imap_refmsg *rfc822_threadgetroot(struct imap_refmsgtable *mt);
struct imap_refmsg *rfc822_threadsearchmsg(struct imap_refmsgtable *mt,
const char *msgid);
int rfc822_threadsortsubj(struct imap_refmsgtable *mt,
struct imap_refmsg *root);
int rfc822_threadmergesubj(struct imap_refmsgtable *mt,
struct imap_refmsg *root);
int rfc822_threadsortbydate(struct imap_refmsgtable *mt);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,254 +0,0 @@
/*
** Copyright 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "rfc822.h"
#ifndef __WINDOWS__
#include "config.h"
#endif
#if HAVE_STRCASECMP
#else
#define strcasecmp stricmp
#endif
#if HAVE_STRNCASECMP
#else
#define strncasecmp strnicmp
#endif
/* Remove artifacts from the subject header */
static void stripsubj(char *s, int *hasrefwd)
{
char *p;
char *q;
for (p=q=s; *p; p++)
{
if (!isspace((int)(unsigned char)*p))
{
*q++=*p;
continue;
}
while (p[1] && isspace((int)(unsigned char)p[1]))
{
++p;
}
*q++=' ';
}
*q=0;
for (;;)
{
/*
**
** (2) Remove all trailing text of the subject that matches
** the subj-trailer ABNF, repeat until no more matches are
** possible.
**
** subj-trailer = "(fwd)" / WSP
*/
for (p=s; *p; p++)
;
while (p > s)
{
if ( isspace((int)(unsigned char)p[-1]))
{
--p;
continue;
}
if (p-s >= 5 && strncasecmp(p-5, "(FWD)", 5) == 0)
{
p -= 5;
*hasrefwd=1;
continue;
}
break;
}
*p=0;
for (p=s; *p; )
{
int isrefwd=0;
for (;;)
{
int needcolon=1;
/*
**
** (3) Remove all prefix text of the subject
** that matches the subj-leader ABNF.
**
** subj-leader = (*subj-blob subj-refwd) / WSP
**
** subj-blob = "[" *BLOBCHAR "]" *WSP
**
** subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":"
**
** BLOBCHAR = %x01-5a / %x5c / %x5e-7f
** ; any CHAR except '[' and ']'
**
** THIS IS A BUG: whitespace should also be excluded from BLOBCHAR
*/
if (isspace((int)(unsigned char)*p))
{
++p;
continue;
}
if (strncasecmp(p, "RE", 2) == 0)
{
q=p+2;
isrefwd=1;
}
else if (strncasecmp(p, "FWD", 3) == 0)
{
q=p+3;
isrefwd=1;
}
else if (strncasecmp(p, "FW", 2) == 0)
{
q=p+2;
isrefwd=1;
}
else if (*p == '[')
{
q=p;
needcolon=0;
}
else
break;
if (*q == '[')
{
++q;
while (*q && *q != '[' && *q != ']'
&& *q != ' ')
++q;
if (*q != ']') break;
++q;
}
if (needcolon && *q++ != ':') break;
p=q;
}
/*
** (4) If there is prefix text of the subject that
** matches the subj-blob ABNF, and removing that
** prefix leaves a non-empty subj-base, then remove
** the prefix text.
**
** subj-base = NONWSP *([*WSP] NONWSP)
** ; can be a subj-blob
*/
if (*p == '[')
{
for (q=p; *q; q++)
if (*q == '[' || *q == ' '
|| *q == ']')
break;
if (*q == ']')
{
++q;
while (*q && isspace((int)(unsigned
char)*q))
++q;
if (*q)
{
p=q;
if (isrefwd)
*hasrefwd=1;
continue;
}
}
}
if (isrefwd)
*hasrefwd=1;
break;
}
/*
**
** (6) If the resulting text begins with the subj-fwd-hdr ABNF
** and ends with the subj-fwd-trl ABNF, remove the
** subj-fwd-hdr and subj-fwd-trl and repeat from step (2).
**
** subj-fwd-hdr = "[fwd:"
**
** subj-fwd-trl = "]"
*/
if (strncasecmp(p, "[FWD:", 5) == 0)
{
q=strrchr(p, ']');
if (q && q[1] == 0)
{
*q=0;
p += 5;
q=s;
while ( (*q++ = *p++) != 0)
;
*hasrefwd=1;
continue;
}
}
break;
}
q=s;
while ( (*q++ = *p++) != 0)
;
}
char *rfc822_coresubj(const char *s, int *hasrefwd)
{
char *q=strdup(s), *r;
int dummy;
if (!hasrefwd)
hasrefwd= &dummy;
*hasrefwd=0;
if (!q) return (0);
for (r=q; *r; r++)
if ((*r & 0x80) == 0) /* Just US-ASCII casing, thanks */
*r=toupper((int)(unsigned char)*r);
stripsubj(q, hasrefwd);
return (q);
}
char *rfc822_coresubj_nouc(const char *s, int *hasrefwd)
{
char *q=strdup(s);
int dummy;
if (!hasrefwd)
hasrefwd= &dummy;
*hasrefwd=0;
if (!q) return (0);
stripsubj(q, hasrefwd);
return (q);
}

View File

@ -1,351 +0,0 @@
/*
** Copyright 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "rfc822.h"
#include "imaprefs.h"
static void test1()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
char buf[20];
struct imap_refmsg *p;
strcpy(buf, "a@b");
p=rfc822_threadallocmsg(mt, buf);
strcpy(buf, "c@d");
p=rfc822_threadallocmsg(mt, buf);
printf("%s\n", (rfc822_threadsearchmsg(mt, "a@b")
? "found":"not found"));
printf("%s\n", (rfc822_threadsearchmsg(mt, "c@d")
? "found":"not found"));
printf("%s\n", (rfc822_threadsearchmsg(mt, "e@f")
? "found":"not found"));
rfc822_threadfree(mt);
}
static void prtree(struct imap_refmsg *m)
{
printf("<%s>", m->msgid ? m->msgid:"");
if (m->isdummy)
{
printf(" (dummy)");
}
printf(".parent=");
if (m->parent)
printf("<%s>", m->parent->msgid ? m->parent->msgid:"");
else
printf("ROOT");
printf("\n");
for (m=m->firstchild; m; m=m->nextsib)
prtree(m);
}
static void prpc(struct imap_refmsgtable *mt)
{
struct imap_refmsg *root=rfc822_threadgetroot(mt), *m;
if (!root)
return;
for (m=root->firstchild; m; m=m->nextsib)
prtree(m);
printf("\n\n");
}
static void test2()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<1>", NULL,
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<2>",
"<1>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<4>",
"<1> <2> <3>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
prpc(mt);
rfc822_threadfree(mt);
}
static void test3()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<4>",
"<2> <1> <3>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<3>",
"<1> <2>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<2>",
"<1>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<1>", NULL,
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
prpc(mt);
rfc822_threadfree(mt);
}
static void test4()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<1>", NULL,
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<2>", "<1>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<4>", "<1> <2> <3>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
prpc(mt);
rfc822_threadprune(mt);
prpc(mt);
rfc822_threadfree(mt);
}
static void test5()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<4>", "<1> <2> <3>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<3>", NULL,
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
prpc(mt);
rfc822_threadprune(mt);
prpc(mt);
rfc822_threadfree(mt);
}
static void prsubj(struct imap_refmsgtable *p)
{
struct imap_subjlookup *s;
int i;
for (i=0; i<sizeof(p->subjtable)/sizeof(p->subjtable[0]); i++)
for (s=p->subjtable[i]; s; s=s->nextsubj)
printf("subject(%s)=<%s>\n", s->subj,
s->msg->msgid ? s->msg->msgid:"");
printf("\n\n");
}
static void test6()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<message1>", NULL,
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message10>", NULL,
"subject 2",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message3>", "<message2>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message11>", NULL,
"Re: subject 4",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message12>", NULL,
"subject 4",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message13>", NULL,
"subject 5",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message14>", NULL,
"re: subject 5",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadprune(mt);
rfc822_threadsortsubj(mt, rfc822_threadgetroot(mt));
prpc(mt);
prsubj(mt);
rfc822_threadfree(mt);
}
static void test7()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<message1>", "<message1-dummy>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message2>", "<message2-dummy>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadprune(mt);
rfc822_threadsortsubj(mt, rfc822_threadgetroot(mt));
prpc(mt);
prsubj(mt);
rfc822_threadmergesubj(mt, rfc822_threadgetroot(mt));
prpc(mt);
rfc822_threadfree(mt);
}
static void test8()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<message4>", NULL,
"subject 2",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message2>", NULL,
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message1>", "<message1-dummy>",
"subject 1",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message3>", NULL,
"Re: subject 2",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message10>", NULL,
"subject 10",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message11>", NULL,
"subject 10",
"Thu, 29 Jun 2000 14:41:58 -0700", 1);
rfc822_threadprune(mt);
rfc822_threadsortsubj(mt, rfc822_threadgetroot(mt));
prpc(mt);
prsubj(mt);
rfc822_threadmergesubj(mt, rfc822_threadgetroot(mt));
prpc(mt);
rfc822_threadfree(mt);
}
static void test9()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<message1>", NULL,
"subject 1",
"Thu, 20 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message2>", NULL,
"subject 1",
"Thu, 19 Jun 2000 14:41:58 -0700", 2);
rfc822_threadmsg(mt, "<message3>", NULL,
"subject 1",
"Thu, 21 Jun 2000 14:41:58 -0700", 3);
rfc822_threadmsg(mt, "<message4>", "<message2>",
"subject 2",
"Thu, 21 Jun 2000 14:41:58 -0700", 6);
rfc822_threadmsg(mt, "<message5>", "<message2>",
"subject 2",
"Thu, 21 Jun 2000 14:41:58 -0700", 5);
rfc822_threadmsg(mt, "<message6>", "<message2>",
"subject 2",
"Thu, 20 Jun 2000 14:41:58 -0700", 4);
rfc822_threadprune(mt);
rfc822_threadsortsubj(mt, rfc822_threadgetroot(mt));
rfc822_threadmergesubj(mt, rfc822_threadgetroot(mt));
rfc822_threadsortbydate(mt);
prpc(mt);
rfc822_threadfree(mt);
}
static void test10()
{
struct imap_refmsgtable *mt=rfc822_threadalloc();
rfc822_threadmsg(mt, "<message1>", NULL,
"subject 1",
"Thu, 20 Jun 2000 14:41:58 -0700", 1);
rfc822_threadmsg(mt, "<message4>", "<message1>",
"subject 2",
"Thu, 21 Jun 2000 14:41:58 -0700", 6);
rfc822_threadmsg(mt, "<message1>", NULL,
"subject 2",
"Thu, 21 Jun 2000 14:41:58 -0700", 5);
rfc822_threadmsg(mt, "<message4>", "<message1>",
"subject 2",
"Thu, 21 Jun 2000 14:41:58 -0700", 6);
rfc822_threadprune(mt);
rfc822_threadsortsubj(mt, rfc822_threadgetroot(mt));
rfc822_threadmergesubj(mt, rfc822_threadgetroot(mt));
rfc822_threadsortbydate(mt);
prpc(mt);
rfc822_threadfree(mt);
}
int main(int argc, char **argv)
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
test10();
return (0);
}

View File

@ -1,106 +0,0 @@
found
found
not found
<1>.parent=<(root)>
<2>.parent=<1>
<3> (dummy).parent=<2>
<4>.parent=<3>
<2>.parent=<(root)>
<3>.parent=<2>
<4>.parent=<3>
<1>.parent=<(root)>
<1>.parent=<(root)>
<2>.parent=<1>
<3> (dummy).parent=<2>
<4>.parent=<3>
<1>.parent=<(root)>
<2>.parent=<1>
<4>.parent=<2>
<1> (dummy).parent=<(root)>
<2> (dummy).parent=<1>
<3>.parent=<(root)>
<4>.parent=<3>
<3>.parent=<(root)>
<4>.parent=<3>
<message1>.parent=<(root)>
<message10>.parent=<(root)>
<message2> (dummy).parent=<(root)>
<message3>.parent=<message2>
<message11>.parent=<(root)>
<message12>.parent=<(root)>
<message13>.parent=<(root)>
<message14>.parent=<(root)>
subject(SUBJECT 1)=<message2>
subject(SUBJECT 2)=<message10>
subject(SUBJECT 5)=<message13>
subject(SUBJECT 4)=<message12>
<message1-dummy> (dummy).parent=<(root)>
<message1>.parent=<message1-dummy>
<message2-dummy> (dummy).parent=<(root)>
<message2>.parent=<message2-dummy>
subject(SUBJECT 1)=<message1-dummy>
<message1-dummy> (dummy).parent=<(root)>
<message1>.parent=<message1-dummy>
<message2>.parent=<message1-dummy>
<message4>.parent=<(root)>
<message2>.parent=<(root)>
<message1-dummy> (dummy).parent=<(root)>
<message1>.parent=<message1-dummy>
<message3>.parent=<(root)>
<message10>.parent=<(root)>
<message11>.parent=<(root)>
subject(SUBJECT 10)=<message10>
subject(SUBJECT 1)=<message1-dummy>
subject(SUBJECT 2)=<message4>
<message4>.parent=<(root)>
<message3>.parent=<message4>
<message1-dummy> (dummy).parent=<(root)>
<message1>.parent=<message1-dummy>
<message2>.parent=<message1-dummy>
<(dummy)> (dummy).parent=<(root)>
<message10>.parent=<(dummy)>
<message11>.parent=<(dummy)>
<(dummy)> (dummy).parent=<(root)>
<message2>.parent=<(dummy)>
<message6>.parent=<message2>
<message5>.parent=<message2>
<message4>.parent=<message2>
<message1>.parent=<(dummy)>
<message3>.parent=<(dummy)>
<message1>.parent=<(root)>
<>.parent=<message1>
<(dummy)> (dummy).parent=<(root)>
<>.parent=<(dummy)>
<message4>.parent=<(dummy)>

View File

@ -1,541 +0,0 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "rfc822.h"
#include "rfc2047.h"
static const char rcsid[]="$Id$";
static const char xdigit[]="0123456789ABCDEF";
static char *rfc2047_search_quote(const char **ptr)
{
const char *p= *ptr;
char *s;
while (**ptr && **ptr != '?')
++ *ptr;
if ((s=malloc( *ptr - p + 1)) == 0)
return (0);
memcpy(s, p, *ptr-p);
s[*ptr - p]=0;
return (s);
}
static int nyb(int c)
{
const char *p;
c=toupper( (int)(unsigned char)c );
p=strchr(xdigit, c);
return (p ? p-xdigit:0);
}
static unsigned char decode64tab[256];
static int decode64tab_init=0;
static size_t decodebase64(char *ptr, size_t cnt)
{
size_t i, j;
char a,b,c;
size_t k;
if (!decode64tab_init)
{
for (i=0; i<256; i++) decode64tab[i]=0;
for (i=0; i<64; i++)
decode64tab[ (int)
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i])]=i;
decode64tab[ (int)'=' ] = 99;
}
i=cnt / 4;
i=i*4;
k=0;
for (j=0; j<i; j += 4)
{
int w=decode64tab[(int)(unsigned char)ptr[j]];
int x=decode64tab[(int)(unsigned char)ptr[j+1]];
int y=decode64tab[(int)(unsigned char)ptr[j+2]];
int z=decode64tab[(int)(unsigned char)ptr[j+3]];
a= (w << 2) | (x >> 4);
b= (x << 4) | (y >> 2);
c= (y << 6) | z;
ptr[k++]=a;
if ( ptr[j+2] != '=')
ptr[k++]=b;
if ( ptr[j+3] != '=')
ptr[k++]=c;
}
return (k);
}
/*
** This is the main rfc2047 decoding function. It receives rfc2047-encoded
** text, and a callback function. The callback function is repeatedly
** called, each time receiving a piece of decoded text. The decoded
** info includes a text fragment - string, string length arg - followed
** by the character set, followed by a context pointer that is received
** from the caller. If the callback function returns non-zero, rfc2047
** decoding terminates, returning the result code. Otherwise,
** rfc2047_decode returns 0 after a successfull decoding (-1 if malloc
** failed).
*/
int rfc2047_decode(const char *text, int (*func)(const char *, int,
const char *, void *),
void *arg)
{
int rc;
int had_last_word=0;
const char *p;
char *chset;
char *encoding;
char *enctext;
while (text && *text)
{
if (text[0] != '=' || text[1] != '?')
{
p=text;
while (*text)
{
if (text[0] == '=' && text[1] == '?')
break;
if (!isspace((int)(unsigned char)*text))
had_last_word=0;
++text;
}
if (text > p && !had_last_word)
{
rc=(*func)(p, text-p, 0, arg);
if (rc) return (rc);
}
continue;
}
text += 2;
if ((chset=rfc2047_search_quote( &text )) == 0)
return (-1);
if (*text) ++text;
if ((encoding=rfc2047_search_quote( &text )) == 0)
{
free(chset);
return (-1);
}
if (*text) ++text;
if ((enctext=rfc2047_search_quote( &text )) == 0)
{
free(encoding);
free(chset);
return (-1);
}
if (*text == '?' && text[1] == '=')
text += 2;
if (strcmp(encoding, "Q") == 0 || strcmp(encoding, "q") == 0)
{
char *q, *r;
for (q=r=enctext; *q; )
{
int c;
if (*q == '=' && q[1] && q[2])
{
*r++ = (char)(
nyb(q[1])*16+nyb(q[2]));
q += 3;
continue;
}
c=*q++;
if (c == '_')
c=' ';
*r++ = c ;
}
*r=0;
}
else if (strcmp(encoding, "B") == 0 || strcmp(encoding, "b")==0)
{
enctext[decodebase64(enctext, strlen(enctext))]=0;
}
rc=(*func)(enctext, strlen(enctext), chset, arg);
free(enctext);
free(chset);
free(encoding);
if (rc) return (rc);
had_last_word=1; /* Ignore blanks between enc words */
}
return (0);
}
/*
** rfc2047_decode_simple just strips out the rfc2047 decoding, throwing away
** the character set. This is done by calling rfc2047_decode twice, once
** to count the number of characters in the decoded text, the second time to
** actually do it.
*/
struct simple_info {
char *string;
int index;
const char *mychset;
} ;
static int count_simple(const char *txt, int len, const char *chset,
void *arg)
{
struct simple_info *iarg= (struct simple_info *)arg;
iarg->index += len;
return (0);
}
static int save_simple(const char *txt, int len, const char *chset,
void *arg)
{
struct simple_info *iarg= (struct simple_info *)arg;
memcpy(iarg->string+iarg->index, txt, len);
iarg->index += len;
return (0);
}
char *rfc2047_decode_simple(const char *text)
{
struct simple_info info;
info.index=1;
if (rfc2047_decode(text, &count_simple, &info))
return (0);
if ((info.string=malloc(info.index)) == 0) return (0);
info.index=0;
if (rfc2047_decode(text, &save_simple, &info))
{
free(info.string);
return (0);
}
info.string[info.index]=0;
return (info.string);
}
/*
** rfc2047_decode_enhanced is like simply, but prefixes the character set
** name before the text, in brackets.
*/
static int do_enhanced(const char *txt, int len, const char *chset,
void *arg,
int (*func)(const char *, int, const char *, void *)
)
{
int rc=0;
struct simple_info *info=(struct simple_info *)arg;
if (chset && info->mychset && strcmp(chset, info->mychset) == 0)
chset=0;
if (chset)
{
rc= (*func)(" [", 2, 0, arg);
if (rc == 0)
rc= (*func)(chset, strlen(chset), 0, arg);
if (rc == 0)
rc= (*func)("] ", 2, 0, arg);
}
if (rc == 0)
rc= (*func)(txt, len, 0, arg);
return (rc);
}
static int count_enhanced(const char *txt, int len, const char *chset,
void *arg)
{
return (do_enhanced(txt, len, chset, arg, &count_simple));
}
static int save_enhanced(const char *txt, int len, const char *chset,
void *arg)
{
return (do_enhanced(txt, len, chset, arg, &save_simple));
}
char *rfc2047_decode_enhanced(const char *text, const char *mychset)
{
struct simple_info info;
info.mychset=mychset;
info.index=1;
if (rfc2047_decode(text, &count_enhanced, &info))
return (0);
if ((info.string=malloc(info.index)) == 0) return (0);
info.index=0;
if (rfc2047_decode(text, &save_enhanced, &info))
{
free(info.string);
return (0);
}
info.string[info.index]=0;
return (info.string);
}
void rfc2047_print(const struct rfc822a *a,
const char *charset,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *ptr)
{
rfc822_print_common(a, &rfc2047_decode_enhanced, charset,
print_func, print_separator, ptr);
}
static char *a_rfc2047_encode_str(const char *str, const char *charset);
static void rfc2047_encode_header_do(const struct rfc822a *a,
const char *charset,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *ptr)
{
rfc822_print_common(a, &a_rfc2047_encode_str, charset,
print_func, print_separator, ptr);
}
/*
** When MIMEifying names from an RFC822 list of addresses, strip quotes
** before MIMEifying them, and add them afterwards.
*/
static char *a_rfc2047_encode_str(const char *str, const char *charset)
{
size_t l=strlen(str);
char *p, *s;
if (*str != '"' || str[l-1] != '"')
return (rfc2047_encode_str(str, charset));
p=malloc(l);
if (!p) return (0);
memcpy(p, str+1, l-2);
p[l-2]=0;
s=rfc2047_encode_str(p, charset);
free(p);
if (!s) return (0);
p=malloc(strlen(s)+3);
if (!p)
{
free(s);
return (0);
}
p[0]='"';
strcpy(p+1, s);
strcat(p, "\"");
free(s);
return (p);
}
static void count(char c, void *p);
static void counts(const char *c, void *p);
static void save(char c, void *p);
static void saves(const char *c, void *p);
char *rfc2047_encode_header(const struct rfc822a *a,
const char *charset)
{
size_t l;
char *s, *p;
l=1;
rfc2047_encode_header_do(a, charset, &count, &counts, &l);
if ((s=malloc(l)) == 0) return (0);
p=s;
rfc2047_encode_header_do(a, charset, &save, &saves, &p);
*p=0;
return (s);
}
static void count(char c, void *p)
{
++*(size_t *)p;
}
static void counts(const char *c, void *p)
{
while (*c) count(*c++, p);
}
static void save(char c, void *p)
{
**(char **)p=c;
++*(char **)p;
}
static void saves(const char *c, void *p)
{
while (*c) save(*c++, p);
}
int rfc2047_encode_callback(const char *str, const char *charset,
int (*func)(const char *, size_t, void *), void *arg)
{
int rc;
while (*str)
{
size_t i, c;
for (i=0; str[i]; i++)
if ((str[i] & 0x80) || str[i] == '"')
break;
if (str[i] == 0)
return ( i ? (*func)(str, i, arg):0);
/* Find start of word */
while (i)
{
--i;
if (isspace((int)(unsigned char)str[i]))
{
++i;
break;
}
}
if (i)
{
rc= (*func)(str, i, arg);
if (rc) return (rc);
str += i;
}
/*
** Figure out when to stop MIME decoding. Consecutive
** MIME-encoded words are MIME-encoded together.
*/
i=0;
for (;;)
{
for ( ; str[i]; i++)
if (isspace((int)(unsigned char)str[i]))
break;
if (str[i] == 0)
break;
for (c=i; str[c] && isspace((int)(unsigned char)str[c]);
++c)
;
for (; str[c]; c++)
if (isspace((int)(unsigned char)str[c]) ||
(str[c] & 0x80) || str[c] == '"')
break;
if (str[c] == 0 || isspace((int)(unsigned char)str[c]))
break;
i=c;
}
/* Output mimeified text, insert spaces at 70+ character
** boundaries for line wrapping.
*/
c=0;
while (i)
{
if (c == 0)
{
if ( (rc=(*func)("=?", 2, arg)) != 0 ||
(rc=(*func)(charset, strlen(charset),
arg)) != 0 ||
(rc=(*func)("?Q?", 3, arg)) != 0)
return (rc);
c += strlen(charset)+5;
}
if ((*str & 0x80) || *str == '"')
{
char buf[3];
buf[0]='=';
buf[1]=xdigit[ ( *str >> 4) & 0x0F ];
buf[2]=xdigit[ *str & 0x0F ];
if ( (rc=(*func)(buf, 3, arg)) != 0)
return (rc);
c += 3;
++str;
--i;
}
else
{
size_t j;
for (j=0; j < i && !(str[j] & 0x80) &&
str[j] != '"'; j++)
if (j + c >= 70)
break;
if ( (rc=(*func)(str, j, arg)) != 0)
return (rc);
c += j;
str += j;
i -= j;
}
if (i == 0 || c >= 70)
{
if ( (rc=(*func)("?= ", i ? 3:2, arg)) != 0)
return (rc);
c=0;
}
}
}
return (0);
}
static int count_char(const char *c, size_t l, void *p)
{
size_t *i=(size_t *)p;
*i += l;
return (0);
}
static int save_char(const char *c, size_t l, void *p)
{
char **s=(char **)p;
memcpy(*s, c, l);
*s += l;
return (0);
}
char *rfc2047_encode_str(const char *str, const char *charset)
{
size_t i=1;
char *s, *p;
(void)rfc2047_encode_callback(str, charset, &count_char, &i);
if ((s=malloc(i)) == 0) return (0);
p=s;
(void)rfc2047_encode_callback(str, charset, &save_char, &p);
*p=0;
return (s);
}

View File

@ -1,83 +0,0 @@
#ifndef rfc2047_h
#define rfc2047_h
/*
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
#ifdef __cplusplus
extern "C" {
#endif
static const char rfc2047_h_rcsid[]="$Id$";
extern int rfc2047_decode(const char *text,
int (*func)(const char *, int, const char *, void *),
void *arg);
extern char *rfc2047_decode_simple(const char *text);
extern char *rfc2047_decode_enhanced(const char *text, const char *mychset);
/*
** If libunicode.a is available, like rfc2047_decode_enhanced, but attempt to
** convert to my preferred charset.
*/
struct unicode_info;
extern char *rfc2047_decode_unicode(const char *text,
const struct unicode_info *mychset,
int options);
#define RFC2047_DECODE_DISCARD 1
/* options: Discard unknown charsets from decoded string. */
#define RFC2047_DECODE_ABORT 2
/* options: Abort if we encounter an unknown charset, errno=EINVAL */
/*
** rfc2047_print is like rfc822_print, except that it converts RFC 2047
** MIME encoding to 8 bit text.
*/
struct rfc822a;
void rfc2047_print(const struct rfc822a *a,
const char *charset,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *);
/*
** And now, let's encode something with RFC 2047. Encode the following
** string in the indicated character set, into a malloced buffer. Returns 0
** if malloc failed.
*/
char *rfc2047_encode_str(const char *str, const char *charset);
/*
** If you can live with the encoded text being generated on the fly, use
** rfc2047_encode_callback, which calls a callback function, instead of
** dynamically allocating memory.
*/
int rfc2047_encode_callback(const char *str, const char *charset,
int (*func)(const char *, size_t, void *), void *arg);
/*
** rfc2047_encode_header allocates a buffer, and MIME-encodes an RFC822 header
**
*/
char *rfc2047_encode_header(const struct rfc822a *a,
const char *charset);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,109 +0,0 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "rfc822.h"
#include "rfc2047.h"
static const char rcsid[]="$Id$";
#if HAVE_LIBUNICODE
#include "../unicode/unicode.h"
struct decode_unicode_s {
const struct unicode_info *mychset;
int options;
char *bufptr;
size_t bufsize;
} ;
static void save_unicode_text(const char *p, int l, struct decode_unicode_s *s)
{
if (s->bufptr)
memcpy(s->bufptr+s->bufsize, p, l);
s->bufsize += l;
}
static int save_unicode(const char *txt, int len, const char *chset,
void *arg)
{
struct decode_unicode_s *p=(struct decode_unicode_s *)arg;
char *txts=malloc(len+1);
char *s;
if (!txts)
return (-1);
memcpy(txts, txt, len);
txts[len]=0;
if (!chset)
chset=unicode_ISO8859_1.chset;
s=unicode_convert_fromchset(txts, chset, p->mychset);
free(txts);
if (s)
{
save_unicode_text(s, strlen(s), p);
free(s);
return (0);
}
if (p->options & RFC2047_DECODE_ABORT)
{
errno=EINVAL;
return (-1);
}
if (p->options & RFC2047_DECODE_DISCARD)
return (0);
save_unicode_text(" [", 2, p);
save_unicode_text(chset, strlen(chset), p);
save_unicode_text("] ", 2, p);
save_unicode_text(txt, len, p);
return (0);
}
char *rfc2047_decode_unicode(const char *text,
const struct unicode_info *mychset,
int options)
{
struct decode_unicode_s s;
char *p=0;
s.mychset=mychset;
s.options=0;
s.bufptr=0;
s.bufsize=1;
if (rfc2047_decode(text, &save_unicode, &s))
return (0);
s.bufptr=p=malloc(s.bufsize);
if (!s.bufptr)
return (0);
s.bufsize=0;
if (rfc2047_decode(text, &save_unicode, &s))
{
free(p);
return (0);
}
save_unicode_text("", 1, (void *)&s);
return (p);
}
#endif

View File

@ -1,721 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "rfc822.h"
static void tokenize(const char *p, struct rfc822token *tokp, int *toklen,
void (*err_func)(const char *, int))
{
const char *addr=p;
int i=0;
int inbracket=0;
*toklen=0;
while (*p)
{
if (isspace((int)(unsigned char)*p))
{
p++;
i++;
continue;
}
switch (*p) {
int level;
case '(':
if (tokp)
{
tokp->token='(';
tokp->ptr=p;
tokp->len=0;
}
level=0;
for (;;)
{
if (!*p)
{
if (err_func) (*err_func)(addr, i);
if (tokp) tokp->token='"';
++*toklen;
return;
}
if (*p == '(')
++level;
if (*p == ')' && --level == 0)
{
p++;
i++;
if (tokp) tokp->len++;
break;
}
if (*p == '\\' && p[1])
{
p++;
i++;
if (tokp) tokp->len++;
}
i++;
if (tokp) tokp->len++;
p++;
}
if (tokp) ++tokp;
++*toklen;
continue;
case '"':
p++;
i++;
if (tokp)
{
tokp->token='"';
tokp->ptr=p;
}
while (*p != '"')
{
if (!*p)
{
if (err_func) (*err_func)(addr, i);
++*toklen;
return;
}
if (*p == '\\' && p[1])
{
if (tokp) tokp->len++;
p++;
i++;
}
if (tokp) tokp->len++;
p++;
i++;
}
++*toklen;
if (tokp) ++tokp;
p++;
i++;
continue;
case '\\':
case ')':
if (err_func) (*err_func)(addr, i);
++p;
++i;
continue;
case '<':
case '>':
case '@':
case ',':
case ';':
case ':':
case '.':
case '[':
case ']':
case '%':
case '!':
case '?':
case '=':
case '/':
if ( (*p == '<' && inbracket) ||
(*p == '>' && !inbracket))
{
if (err_func) (*err_func)(addr, i);
++p;
++i;
continue;
}
if (*p == '<')
inbracket=1;
if (*p == '>')
inbracket=0;
if (tokp)
{
tokp->token= *p;
tokp->ptr=p;
tokp->len=1;
++tokp;
}
++*toklen;
if (*p == '<' && p[1] == '>')
/* Fake a null address */
{
if (tokp)
{
tokp->token=0;
tokp->ptr="";
tokp->len=0;
++tokp;
}
++*toklen;
}
++p;
++i;
continue;
default:
if (tokp)
{
tokp->token=0;
tokp->ptr=p;
tokp->len=0;
}
while (*p && !isspace((int)(unsigned char)*p) && strchr(
"<>@,;:.[]()%!\"\\?=/", *p) == 0)
{
if (tokp) ++tokp->len;
++p;
++i;
}
if (i == 0) /* Idiot check */
{
if (err_func) (*err_func)(addr, i);
if (tokp)
{
tokp->token='"';
tokp->ptr=p;
tokp->len=1;
++tokp;
}
++*toklen;
++p;
++i;
continue;
}
if (tokp) ++tokp;
++*toklen;
}
}
}
static void parseaddr(struct rfc822token *tokens, int ntokens,
struct rfc822addr *addrs, int *naddrs)
{
int flag, j, k;
struct rfc822token save_token;
*naddrs=0;
while (ntokens)
{
int i;
/* atoms (token=0) or quoted strings, followed by a : token
is a list name. */
for (i=0; i<ntokens; i++)
if (tokens[i].token && tokens[i].token != '"')
break;
if (i < ntokens && tokens[i].token == ':')
{
++i;
if (addrs)
{
addrs->tokens=0;
addrs->name=i ? tokens:0;
for (j=1; j<i; j++)
addrs->name[j-1].next=addrs->name+j;
if (i)
addrs->name[i-1].next=0;
addrs++;
}
++*naddrs;
tokens += i;
ntokens -= i;
continue; /* Group=phrase ":" */
}
/* Spurious commas are skipped, ;s are recorded */
if (tokens->token == ',' || tokens->token == ';')
{
if (tokens->token == ';')
{
if (addrs)
{
addrs->tokens=0;
addrs->name=tokens;
addrs->name->next=0;
addrs++;
}
++*naddrs;
}
++tokens;
--ntokens;
continue;
}
/* If we can find a '<' before the next comma or semicolon,
we have new style RFC path address */
for (i=0; i<ntokens && tokens[i].token != ';' &&
tokens[i].token != ',' &&
tokens[i].token != '<'; i++)
;
if (i < ntokens && tokens[i].token == '<')
{
int j;
/* Ok -- what to do with the stuff before '>'???
If it consists exclusively of atoms, leave them alone.
Else, make them all a quoted string. */
for (j=0; j<i && (tokens[j].token == 0 ||
tokens[j].token == '('); j++)
;
if (j == i)
{
if (addrs)
{
addrs->name= i ? tokens:0;
for (k=1; k<i; k++)
addrs->name[k-1].next=addrs->name+k;
if (i)
addrs->name[i-1].next=0;
}
}
else /* Intentionally corrupt the original toks */
{
if (addrs)
{
tokens->len= tokens[i-1].ptr
+ tokens[i-1].len
- tokens->ptr;
/* We know that all the ptrs point
to parts of the same string. */
tokens->token='"';
/* Quoted string. */
addrs->name=tokens;
addrs->name->next=0;
}
}
/* Any comments in the name part are changed to quotes */
if (addrs)
{
struct rfc822token *t;
for (t=addrs->name; t; t=t->next)
if (t->token == '(')
t->token='"';
}
/* Now that's done and over with, see what can
be done with the <...> part. */
++i;
tokens += i;
ntokens -= i;
for (i=0; i<ntokens && tokens[i].token != '>'; i++)
;
if (addrs)
{
addrs->tokens=i ? tokens:0;
for (k=1; k<i; k++)
addrs->tokens[k-1].next=addrs->tokens+k;
if (i)
addrs->tokens[i-1].next=0;
++addrs;
}
++*naddrs;
tokens += i;
ntokens -= i;
if (ntokens) /* Skip the '>' token */
{
--ntokens;
++tokens;
}
continue;
}
/* Ok - old style address. Assume the worst */
/* Try to figure out where the address ends. It ends upon:
a comma, semicolon, or two consecutive atoms. */
flag=0;
for (i=0; i<ntokens && tokens[i].token != ',' &&
tokens[i].token != ';'; i++)
{
if (tokens[i].token == '(') continue;
/* Ignore comments */
if (tokens[i].token == 0 || tokens[i].token == '"')
/* Atom */
{
if (flag) break;
flag=1;
}
else flag=0;
}
if (i == 0) /* Must be spurious comma, or something */
{
++tokens;
--ntokens;
continue;
}
if (addrs)
{
addrs->name=0;
}
/* Ok, now get rid of embedded comments in the address.
Consider the last comment to be the real name */
if (addrs)
{
save_token.ptr=0;
save_token.len=0;
for (j=k=0; j<i; j++)
{
if (tokens[j].token == '(')
{
save_token=tokens[j];
continue;
}
tokens[k]=tokens[j];
k++;
}
if (save_token.ptr)
{
tokens[i-1]=save_token;
addrs->name=tokens+i-1;
addrs->name->next=0;
}
addrs->tokens=k ? tokens:NULL;
for (j=1; j<k; j++)
addrs->tokens[j-1].next=addrs->tokens+j;
if (k)
addrs->tokens[k-1].next=0;
++addrs;
}
++*naddrs;
tokens += i;
ntokens -= i;
}
}
static void print_token(const struct rfc822token *token,
void (*print_func)(char, void *), void *ptr)
{
const char *p;
int n;
if (token->token == 0 || token->token == '(')
{
for (n=token->len, p=token->ptr; n; --n, ++p)
(*print_func)(*p, ptr);
return;
}
if (token->token != '"')
{
(*print_func)(token->token, ptr);
return;
}
(*print_func)('"', ptr);
n=token->len;
p=token->ptr;
while (n)
{
if (*p == '"' || (*p == '\\' && n == 1)) (*print_func)('\\', ptr);
if (*p == '\\' && n > 1)
{
(*print_func)('\\', ptr);
++p;
--n;
}
(*print_func)(*p++, ptr);
--n;
}
(*print_func)('"', ptr);
}
void rfc822tok_print(const struct rfc822token *token,
void (*print_func)(char, void *), void *ptr)
{
int prev_isatom=0;
int isatom;
while (token)
{
isatom=rfc822_is_atom(token->token);
if (prev_isatom && isatom)
(*print_func)(' ', ptr);
print_token(token, print_func, ptr);
prev_isatom=isatom;
token=token->next;
}
}
void rfc822_print(const struct rfc822a *rfcp, void (*print_func)(char, void *),
void (*print_separator)(const char *s, void *), void *ptr)
{
rfc822_print_common(rfcp, 0, 0, print_func, print_separator, ptr);
}
void rfc822_print_common(const struct rfc822a *rfcp,
char *(*decode_func)(const char *, const char *), const char *chset,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *ptr)
{
const struct rfc822addr *addrs=rfcp->addrs;
int naddrs=rfcp->naddrs;
while (naddrs)
{
if (addrs->tokens == 0)
{
rfc822tok_print(addrs->name, print_func, ptr);
++addrs;
--naddrs;
if (addrs[-1].name && naddrs)
{
struct rfc822token *t;
for (t=addrs[-1].name; t && t->next; t=t->next)
;
if (t && (t->token == ':' || t->token == ';'))
(*print_separator)(" ", ptr);
}
continue;
}
else if (addrs->name && addrs->name->token == '(')
{ /* old style */
char *p;
rfc822tok_print(addrs->tokens, print_func, ptr);
(*print_func)(' ', ptr);
if (decode_func && (p=rfc822_gettok(addrs->name))!=0)
{
char *q= (*decode_func)(p, chset);
char *r;
for (r=q; r && *r; r++)
(*print_func)( (int)(unsigned char)*r,
ptr);
if (q) free(q);
free(p);
}
else rfc822tok_print(addrs->name, print_func, ptr);
}
else
{
int print_braces=0;
char *p;
if (addrs->name)
{
if (decode_func &&
(p=rfc822_gettok(addrs->name)) != 0)
{
char *q= (*decode_func)(p, chset);
char *r;
for (r=q; r && *r; r++)
(*print_func)(
(int)(unsigned char)*r,
ptr);
if (q) free(q);
free(p);
}
else rfc822tok_print(addrs->name,
print_func, ptr);
(*print_func)(' ', ptr);
print_braces=1;
}
else
{
struct rfc822token *p;
for (p=addrs->tokens; p && p->next; p=p->next)
if (rfc822_is_atom(p->token) &&
rfc822_is_atom(p->next->token))
print_braces=1;
}
if (print_braces)
(*print_func)('<', ptr);
rfc822tok_print(addrs->tokens, print_func, ptr);
if (print_braces)
{
(*print_func)('>', ptr);
}
}
++addrs;
--naddrs;
if (naddrs)
if (addrs->tokens || (addrs->name &&
rfc822_is_atom(addrs->name->token)))
(*print_separator)(", ", ptr);
}
}
void rfc822t_free(struct rfc822t *p)
{
if (p->tokens) free(p->tokens);
free(p);
}
void rfc822a_free(struct rfc822a *p)
{
if (p->addrs) free(p->addrs);
free(p);
}
void rfc822_deladdr(struct rfc822a *rfcp, int index)
{
int i;
if (index < 0 || index >= rfcp->naddrs) return;
for (i=index+1; i<rfcp->naddrs; i++)
rfcp->addrs[i-1]=rfcp->addrs[i];
if (--rfcp->naddrs == 0)
{
free(rfcp->addrs);
rfcp->addrs=0;
}
}
struct rfc822t *rfc822t_alloc(const char *addr,
void (*err_func)(const char *, int))
{
struct rfc822t *p=(struct rfc822t *)malloc(sizeof(struct rfc822t));
if (!p) return (NULL);
memset(p, 0, sizeof(*p));
tokenize(addr, NULL, &p->ntokens, err_func);
p->tokens=p->ntokens ? (struct rfc822token *)
calloc(p->ntokens, sizeof(struct rfc822token)):0;
if (p->ntokens && !p->tokens)
{
rfc822t_free(p);
return (NULL);
}
tokenize(addr, p->tokens, &p->ntokens, NULL);
return (p);
}
struct rfc822a *rfc822a_alloc(struct rfc822t *t)
{
struct rfc822a *p=(struct rfc822a *)malloc(sizeof(struct rfc822a));
if (!p) return (NULL);
memset(p, 0, sizeof(*p));
parseaddr(t->tokens, t->ntokens, NULL, &p->naddrs);
p->addrs=p->naddrs ? (struct rfc822addr *)
calloc(p->naddrs, sizeof(struct rfc822addr)):0;
if (p->naddrs && !p->addrs)
{
rfc822a_free(p);
return (NULL);
}
parseaddr(t->tokens, t->ntokens, p->addrs, &p->naddrs);
return (p);
}
void rfc822_praddr(const struct rfc822a *rfcp, int index,
void (*print_func)(char, void *), void *ptr)
{
const struct rfc822addr *addrs;
if (index < 0 || index >= rfcp->naddrs) return;
addrs=rfcp->addrs+index;
if (addrs->tokens)
{
rfc822tok_print(addrs->tokens, print_func, ptr);
(*print_func)('\n', ptr);
}
}
void rfc822_addrlist(const struct rfc822a *rfcp,
void (*print_func)(char, void *), void *ptr)
{
int i;
for (i=0; i<rfcp->naddrs; i++)
rfc822_praddr(rfcp, i, print_func, ptr);
}
void rfc822_prname(const struct rfc822a *rfcp, int index,
void (*print_func)(char, void *), void *ptr)
{
const struct rfc822addr *addrs;
if (index < 0 || index >= rfcp->naddrs) return;
addrs=rfcp->addrs+index;
if (!addrs->tokens) return;
rfc822_prname_orlist(rfcp, index, print_func, ptr);
}
void rfc822_prname_orlist(const struct rfc822a *rfcp, int index,
void (*print_func)(char, void *), void *ptr)
{
const struct rfc822addr *addrs;
if (index < 0 || index >= rfcp->naddrs) return;
addrs=rfcp->addrs+index;
if (addrs->name)
{
struct rfc822token *i;
int n;
int prev_isatom=0;
int isatom=0;
for (i=addrs->name; i; i=i->next, prev_isatom=isatom)
{
isatom=rfc822_is_atom(i->token);
if (isatom && prev_isatom)
(*print_func)(' ', ptr);
if (i->token != '(')
{
print_token(i, print_func, ptr);
continue;
}
for (n=2; n<i->len; n++)
(*print_func)(i->ptr[n-1], ptr);
}
} else
rfc822tok_print(addrs->tokens, print_func, ptr);
(*print_func)('\n', ptr);
}
void rfc822_namelist(const struct rfc822a *rfcp,
void (*print_func)(char, void *), void *ptr)
{
int i;
for (i=0; i<rfcp->naddrs; i++)
rfc822_prname(rfcp, i, print_func, ptr);
}

View File

@ -1,170 +0,0 @@
/*
** $Id$
*/
#ifndef rfc822_h
#define rfc822_h
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
** The text string we want to parse is first tokenized into an array of
** struct rfc822token records. 'ptr' points into the original text
** string, and 'len' has how many characters from 'ptr' belongs to this
** token.
*/
struct rfc822token {
struct rfc822token *next; /* Unused by librfc822, for use by
** clients */
int token;
/*
Values for token:
'(' - comment
'"' - quoted string
'<', '>', '@', ',', ';', ':', '.', '[', ']', '%', '!', '=', '?', '/' - RFC atoms.
0 - atom
*/
#define rfc822_is_atom(p) ( (p) == 0 || (p) == '"' || (p) == '(' )
const char *ptr; /* Pointer to value for the token. */
int len; /* Length of token value */
} ;
/*
** After the struct rfc822token array is built, it is used to create
** the rfc822addr array, which is the array of addresses (plus
** syntactical fluff) extracted from those text strings. Each rfc822addr
** record has several possible interpretation:
**
** tokens is NULL - syntactical fluff, look in name/nname for tokens
** representing the syntactical fluff ( which is semicolons
** and list name:
**
** tokens is not NULL - actual address. The tokens representing the actual
** address is in tokens/ntokens. If there are comments in
** the address that are possible "real name" for the address
** they are saved in name/nname (name may be null if there
** is none).
** If nname is 1, and name points to a comment token,
** the address was specified in old-style format. Otherwise
** the address was specified in new-style route-addr format.
**
** The tokens and name pointers are set to point to the original rfc822token
** array.
*/
struct rfc822addr {
struct rfc822token *tokens;
struct rfc822token *name;
} ;
/***************************************************************************
**
** rfc822 tokens
**
***************************************************************************/
struct rfc822t {
struct rfc822token *tokens;
int ntokens;
} ;
struct rfc822t *rfc822t_alloc(const char *p,
void (*err_func)(const char *, int)); /* Parse addresses */
void rfc822t_free(struct rfc822t *); /* Free rfc822 structure */
void rfc822tok_print(const struct rfc822token *, void (*)(char, void *), void *);
/* Print the tokens */
/***************************************************************************
**
** rfc822 addresses
**
***************************************************************************/
struct rfc822a {
struct rfc822addr *addrs;
int naddrs;
} ;
struct rfc822a *rfc822a_alloc(struct rfc822t *);
void rfc822a_free(struct rfc822a *); /* Free rfc822 structure */
void rfc822_deladdr(struct rfc822a *, int);
/* rfc822_print "unparses" the rfc822 structure. Each rfc822addr is "printed"
(via the attached function). NOTE: instead of separating addresses by
commas, the print_separator function is called.
*/
void rfc822_print(const struct rfc822a *a,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *);
/* rfc822_print_common is an internal function */
void rfc822_print_common(const struct rfc822a *a,
char *(*decode_func)(const char *, const char *),
const char *chset,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *);
/* Another unparser, except that only the raw addresses are extracted,
and each address is followed by a newline character */
void rfc822_addrlist(const struct rfc822a *, void (*print_func)(char, void *),
void *);
/* Now, just the comments. If comments not given, the address. */
void rfc822_namelist(const struct rfc822a *, void (*print_func)(char, void *),
void *);
/* Unparse an individual name/addr from a list of addresses. If the given
index points to some syntactical fluff, this is a noop */
void rfc822_prname(const struct rfc822a *, int, void (*)(char, void *), void *);
void rfc822_praddr(const struct rfc822a *, int, void (*)(char, void *), void *);
/* Like rfc822_prname, except that we'll also print the legacy format
** of a list designation.
*/
void rfc822_prname_orlist(const struct rfc822a *, int,
void (*)(char, void *), void *);
/* Extra functions */
char *rfc822_gettok(const struct rfc822token *);
char *rfc822_getaddr(const struct rfc822a *, int);
char *rfc822_getname(const struct rfc822a *, int);
char *rfc822_getname_orlist(const struct rfc822a *, int);
char *rfc822_getaddrs(const struct rfc822a *);
char *rfc822_getaddrs_wrap(const struct rfc822a *, int);
void rfc822_mkdate_buf(time_t, char *);
const char *rfc822_mkdate(time_t);
time_t rfc822_parsedt(const char *);
char *rfc822_coresubj(const char *, int *);
char *rfc822_coresubj_nouc(const char *, int *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,391 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<title>rfc822 - RFC 822 parsing library</title>
<!-- $Id$ -->
<!-- Copyright 2000 Double Precision, Inc. See COPYING for -->
<!-- distribution information. -->
<!-- SECTION 3X -->
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B"
alink="#FF0000">
<h1>rfc822 - RFC 822 parsing library</h1>
<h2>SYNOPSIS</h2>
<p><code>#include &lt;rfc822.h&gt;</code></p>
<p><code>#include &lt;rfc2047.h&gt;</code></p>
<p><code>cc ... -lrfc822</code></p>
<h2>DESCRIPTION</h2>
<p>The rfc822 library provides functions for parsing E-mail headers in the RFC
822 format. This library also includes some functions to help with encoding
and decoding 8-bit text, as defined by RFC 2047.</p>
<p>The format used by E-mail headers to encode sender and recipient
information is defined by RFC 822. The format allows the actual E-mail
address and the sender/recipient name to be expressed together, for example:
<code>John Smith &lt;jsmith@example.com&gt;</code></p>
<p>The main purposes of the rfc822 library is to:</p>
<p>1) Parse a text string containing a list of RFC 822-formatted address into
its logical components: names and E-mail addresses.</p>
<p>2) Access those individual components.</p>
<p>3) Allow some limited modifications of the parsed structure, and then
convert it back into a text string.</p>
<h3>Tokenizing an E-mail header</h3>
<pre>struct rfc822t *tokens=rfc822t_alloc(const char *header,
void (*err_func)(const char *, int));
void rfc822t_free(tokens);</pre>
<p>The rfc822t_alloc() function accepts an E-mail <i>header</i>, and parses it
into individual tokens. This function allocates and returns a pointer to a
<i>rfc822t</i> structure, which is later used by the <i>rfc822a_alloc</i>
function to extract individual addresses from these tokens.</p>
<p>If <i>err_func</i> argument, if not NULL, is a pointer to a callback
function. The function is called in the event that the E-mail header is
corrupted to the point that it cannot even be parsed. This is a rare
instances -- most forms of corruption are still valid at least on the lexical
level. The only time this error is reported is in the event of mismatched
parenthesis, angle brackets, or quotes. The callback function receives the
<i>header</i> pointer, and an index to the syntax error in the header
string.</p>
<p>The semantics of <i>err_func</i> are subject to change. It is recommended
to leave this argument as NULL in the current version of the library.</p>
<p>rfc822t_alloc() returns a pointer to a dynamically-allocated <i>rfc822t</i>
structure. A NULL pointer is returned if there's insufficient memory to
allocate this structure. The rfc822t_free() function is used to destroy the
<i>rfc822t</i> structure and to free all the dynamically allocated memory.</p>
<p>NOTE: Until rfc822t_free() is called, the contents of <i>header</i> MUST
NOT be destroyed or altered in any way. The contents of <i>header</i> are not
modified by rfc822t_alloc(), however the <i>rfc822t</i> structure contains
pointers to portions of the supplied <i>header</i>.</p>
<h3>Extracting E-mail addresses</h3>
<pre>struct rfc822a *addrs=rfc822a_alloc(struct rfc822t *tokens);
void rfc822a_free(addrs);</pre>
<p>The rfc822a_alloc() function returns a dynamically-allocated <i>rfc822a</i>
structure, that contains individual addresses that were logically extracted
from a <i>rfc822t</i> structure. The rfc822a_alloc() function returns NULL if
there was insufficient memory to allocate the <i>rfc822a</i> structure. The
rfc822a_free() function destroys the <i>rfc822a</i> function, and frees all
associated dynamically-allocated memory. The <i>rfc822t</i> structure passed
to rfc822a_alloc() must not be destroyed before rfc822a_free() destroys the
<i>rfc822a</i> structure.</p>
<p>The <i>rfc822a</i> structure has the following fields:</p>
<pre>struct rfc822a {
struct rfc822addr *addrs;
int naddrs;
} ;</pre>
<p>The <i>naddrs</i> field gives the number of <i>rfc822addr</i> structures
that are pointed to by <i>addrs</i>, which is an array. Each <i>rfc822addr</i>
structure represents either an address found in the original E-mail header,
<i>or the contents of some legacy "syntactical sugar"</i>. For example, the
following is a valid E-mail header:</p>
<pre>To: recipient-list: tom@example.com, john@example.com;</pre>
<p>Typically, all of this, sans the "To:" part, is tokenized by
rfc822t_alloc(), then parsed by rfc822a_alloc(). The "recipient-list:" and
the trailing semicolon is a legacy mailing list specification that is no
longer in widespread use, but still must be accounted for. The resulting
<i>rfc822a</i> structure will have four <i>rfc822addr</i> structures, one for
"recipient-list:", one for each address, and one for the trailing semicolon.
Each <i>rfc822a</i> structure has the following fields:</p>
<pre>struct rfc822addr {
struct rfc822token *tokens;
struct rfc822token *name;
} ;</pre>
<p>If <i>tokens</i> is a null pointer, this structure represents some
non-address portion of the original header, such as "recipient-list:" or a
semicolon. Otherwise it points to a structure that represents the E-mail
address in tokenized form.</p>
<p><i>name</i> either points to the tokenized form of a non-address portion of
the original header, or to a tokenized form of the recipient's name.
<i>name</i> will be NULL if the recipient name was not provided. For the
following address: <code>Tom Jones &lt;tjones@example.com&gt;</code> The
<i>tokens</i> field will point to the tokenized form of "tjones@example.com",
and <i>name</i> points to the tokenized form of "Tom Jones".</p>
<p>Each <i>rfc822token</i> structure contains the following fields:</p>
<pre>struct rfc822token {
struct rfc822token *next;
int token;
const char *ptr;
int len;
} ;</pre>
<p>The <i>next</i> pointer builds a linked list of all tokens in this name or
address. The possible values for the <i>token</i> field are:</p>
<ul>
<li>0x00 - this is a simple atom - a sequence of non-special characters that
is delimited by whitespace or special characters (see below).<br>
<br>
</li>
<li>0x22 - the value of the ascii quote - this is a quoted string.<br>
<br>
</li>
<li>'(' - this is an old style comment. A deprecated form of E-mail
addressing uses, as an example, "john@example.com (John Smith)" instead of
"John Smith &lt;john@example.com&gt;". This old-style notation defined
parenthesized content as arbitrary comments. The <i>rfc822token</i> with
<i>token</i> set to '(' is created for the contents of the entire
comment.<br>
<br>
</li>
<li>'&lt;', '&gt;', '@', and many others - the remaining possible values of
<i>token</i> include all the characters in RFC 822 headers that have
special significance.</li>
</ul>
<p>When a <i>rfc822token</i> structure does not represent a special character,
the <i>ptr</i> field points to a text string giving its contents. The contents
are NOT null-terminated, the <i>len</i> field contains the number of
characters included. The macro rfc822_is_atom(token) indicates whether
<i>ptr</i> and <i>len</i> are used for the given <i>token</i>. Currently
rfc822_is_atom() returns true if <i>token</i> is a zero byte, '"', or '('.</p>
<p>Note that it's possible that <i>len</i> might be zero. This will be the
case for null addresses used as return addresses for delivery status
notifications.</p>
<h3>Working with E-mail addresses</h3>
<pre>void rfc822_deladdr(struct rfc822a *addrs, int index);
void rfc822tok_print(const struct rfc822token *list,
void (*func)(char, void *), void *func_arg);
void rfc822_print(const struct rfc822a *addrs,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *callback_arg);
void rfc822_addrlist(const struct rfc822a *addrs,
void (*print_func)(char, void *),
void *callback_arg);
void rfc822_namelist(const struct rfc822a *addrs,
void (*print_func)(char, void *),
void *callback_arg);
void rfc822_praddr(const struct rfc822a *addrs,
int index,
void (*print_func)(char, void *),
void *callback_arg);
void rfc822_prname(const struct rfc822a *addrs,
int index,
void (*print_func)(char, void *),
void *callback_arg);
void rfc822_prname_orlist(const struct rfc822a *addrs,
int index,
void (*print_func)(char, void *),
void *callback_arg);
char *rfc822_gettok(const struct rfc822token *list);
char *rfc822_getaddrs(const struct rfc822a *addrs);
char *rfc822_getaddr(const struct rfc822a *addrs, int index);
char *rfc822_getname(const struct rfc822a *addrs, int index);
char *rfc822_getname_orlist(const struct rfc822a *addrs, int index);
char *rfc822_getaddrs_wrap(const struct rfc822a *, int);</pre>
<p>These functions are used to work with individual addresses that are parsed
by rfc822a_alloc().</p>
<p>rfc822_deladdr() removes a single <i>rfc822addr</i> structure, whose
<i>index</i> is given, from the address array in <i>rfc822addr</i>.
<i>naddrs</i> is decremented by one.</p>
<p>rfc822tok_print() converts a tokenized <i>list</i> of <i>rfc822token</i>
objects into a text string. The callback function, <i>func</i>, is called one
character at a time, for every character in the tokenized objects. An
arbitrary pointer, <i>func_arg</i>, is passed unchanged as the additional
argument to the callback function. rfc822tok_print() is not usually the most
convenient and efficient function, but it has its uses.</p>
<p>rfc822_print() takes an entire <i>rfc822a</i> structure, and uses the
callback functions to print the contained addresses, in their original form,
separated by commas. The function pointed to by <i>print_func</i> is used to
print each individual address, one character at a time. Between the
addresses, the <i>print_separator</i> function is called to print the address
separator, usually the string ", ". The <i>callback_arg</i> argument is passed
along unchanged, as an additional argument to these functions.</p>
<p>The functions rfc822_addrlist() and rfc822_namelist() also print the
contents of the entire <i>rfc822a</i> structure, but in a different way.
rfc822_addrlist() prints just the actual E-mail addresses, not the recipient
names or comments. Each E-mail address is followed by a newline character.
rfc822_namelist() prints just the names or comments, followed by newlines.</p>
<p>The functions rfc822_praddr() and rfc822_prname() are just like
rfc822_addrlist() and rfc822_namelist(), except that they print a single name
or address in the <i>rfc822a</i> structure, given its <i>index</i>. The
functions rfc822_gettok(), rfc822_getaddrs(), rfc822_getaddr(), and
rfc822_getname() are equivalent to rfc822tok_print(), rfc822_print(),
rfc822_praddr() and rfc822_prname(), but, instead of using a callback function
pointer, these functions write the output into a dynamically allocated buffer.
That buffer must be destroyed by free(3) after use. These functions will
return a null pointer in the event of a failure to allocate memory for the
buffer.</p>
<p>rfc822_prname_orlist() is similar to rfc822_prname(), except that it will
also print the legacy RFC822 group list syntax (which are also parsed by
rfc822a_alloc()). rfc822_praddr() will print an empty string for an index
that corresponds to a group list name (or terminated semicolon).
rfc822_prname() will also print an empty string. rfc822_prname_orlist() will
instead print either the name of the group list, or a single string ";".
rfc822_getname_orlist() will instead save it into a dynamically allocated
buffer.</p>
<p>The function rfc822_getaddrs_wrap() is similar to rfc822_getaddrs(), except
that the generated text is wrapped on or about the 73rd column, using newline
characters.</p>
<h3>Working with dates</h3>
<pre>time_t timestamp=rfc822_parsedt(const char *datestr)
const char *datestr=rfc822_mkdate(time_t timestamp);
void rfc822_mkdate_buf(time_t timestamp, char *buffer);</pre>
<p>These functions convert between timestamps and dates expressed in the Date:
E-mail header format.</p>
<p>rfc822_parsedt() returns the timestamp corresponding to the given date
string (0 if there was a syntax error).</p>
<p>rfc822_mkdate() returns a date string corresponding to the given timestamp.
rfc822_mkdate_buf() writes the date string into the given buffer instead,
which must be of sufficient size to accommodate it.</p>
<h3>Working with 8-bit MIME-encoded headers</h3>
<pre>int error=rfc2047_decode(const char *text,
int (*callback_func)(const char *, int, const char *, void *),
void *callback_arg);
extern char *str=rfc2047_decode_simple(const char *text);
extern char *str=rfc2047_decode_enhanced(const char *text,
const char *charset);
void rfc2047_print(const struct rfc822a *a,
const char *charset,
void (*print_func)(char, void *),
void (*print_separator)(const char *, void *), void *);
char *buffer=rfc2047_encode_str(const char *string,
const char *charset);
int error=rfc2047_encode_callback(const char *string,
const char *charset,
int (*func)(const char *, size_t, void *),
void *callback_arg);
char *buffer=rfc2047_encode_header(const struct rfc822a *a,
const char *charset);</pre>
<p>These functions provide additional logic to encode or decode 8-bit content
in 7-bit RFC 822 headers, as specified in RFC 2047.</p>
<p>rfc2047_decode() is a basic RFC 2047 decoding function. It receives a
pointer to some 7bit RFC 2047-encoded text, and a callback function. The
callback function is repeatedly called. Each time it's called it receives a
piece of decoded text. The arguments are: a pointer to a text fragment, number
of bytes in the text fragment, followed by a pointer to the character set of
the text fragment. The character set pointer is NULL for portions of the
original text that are not RFC 2047-encoded.</p>
<p>The callback function also receives <i>callback_arg</i>, as its last
argument. If the callback function returns a non-zero value, rfc2047_decode()
terminates, returning that value. Otherwise, rfc2047_decode() returns 0 after
a successful decoding. rfc2047_decode() returns -1 if it was unable to
allocate sufficient memory.</p>
<p>rfc2047_decode_simple() and rfc2047_decode_enhanced() are alternatives to
rfc2047_decode() which forego a callback function, and return the decoded text
in a dynamically-allocated memory buffer. The buffer must be free(3)-ed after
use. rfc2047_decode_simple() discards all character set specifications, and
merely decodes any 8-bit text. rfc2047_decode_enhanced() is a compromise to
discarding all character set information. The local character set being used
is specified as the second argument to rfc2047_decode_enhanced(). Any RFC
2047-encoded text in a different character set will be prefixed by the name of
the character set, in brackets, in the resulting output.</p>
<p>rfc2047_decode_simple() and rfc2047_decode_enhanced() return a null pointer
if they are unable to allocate sufficient memory.</p>
<p>The rfc2047_print() function is equivalent to rfc822_print(), followed by
rfc2047_decode_enhanced() on the result. The callback functions are used in
an identical fashion, except that they receive text that's already
decoded.</p>
<p>The function rfc2047_encode_str() takes a <i>string</i> and <i>charset</i>
being the name of the local character set, then encodes any 8-bit portions of
<i>string</i> using RFC 2047 encoding. rfc2047_encode_str() returns a
dynamically-allocated buffer with the result, which must be free(3)-ed after
use, or NULL if there was insufficient memory to allocate the buffer.</p>
<p>The function rfc2047_encode_callback() is similar to rfc2047_encode_str()
except that the callback function is repeatedly called to received the
encoding string. Each invocation of the callback function receives a pointer
to a portion of the encoded text, the number of characters in this portion,
and <i>callback_arg</i>.</p>
<p>The function rfc2047_encode_header() is basically equivalent to
rfc822_getaddrs(), followed by rfc2047_encode_str();</p>
<h3>Working with subjects</h3>
<pre>char *basesubj=rfc822_coresubj(const char *subj)
char *basesubj=rfc822_coresubj_nouc(const char *subj)</pre>
<p>This function takes the contents of the subject header, and returns the
"core" subject header that's used in the specification of the IMAP THREAD
function. This function is designed to strip all subject line artifacts that
might've been added in the process of forwarding or replying to a message.
Currently, rfc822_coresubj() performs the following transformations:</p>
<ul>
<li>Whitespace - leading and trailing whitespace is removed. Consecutive
whitespace characters are collapsed into a single whitespace character.
All whitespace characters are replaced by a space.<br>
<br>
</li>
<li>Re:, (fwd) [foo] - these artifacts (and several others) are removed from
the subject line.</li>
</ul>
<p>Note that this function does NOT do MIME decoding. In order to implement
IMAP THREAD, it is necessary to call something like rfc2047_decode() before
calling rfc822_coresubj().</p>
<p>This function returns a pointer to a dynamically-allocated buffer, which
must be free(3)-ed after use.</p>
<p>rfc822_coresubj_nouc() is like rfc822_coresubj(), except that the subject
is not converted to uppercase.</p>
<h2>SEE ALSO</h2>
<a href="rfc2045.html">rfc2045(3)</a>, <a
href="reformime.html">reformime(1)</a>, <a
href="reformail.html">reformail(1)</a>.</body>
</html>

View File

@ -1,101 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include "rfc822.h"
#include <stdlib.h>
static void cntlen(char c, void *p)
{
if (c != '\n')
++ *(size_t *)p;
}
static void saveaddr(char c, void *p)
{
if (c != '\n')
{
char **cp=(char **)p;
*(*cp)++=c;
}
}
char *rfc822_getaddr(const struct rfc822a *rfc, int n)
{
size_t addrbuflen=0;
char *addrbuf, *ptr;
rfc822_praddr(rfc, n, &cntlen, &addrbuflen);
if (!(addrbuf=malloc(addrbuflen+1)))
return (0);
ptr=addrbuf;
rfc822_praddr(rfc, n, &saveaddr, &ptr);
addrbuf[addrbuflen]=0;
return (addrbuf);
}
char *rfc822_getname(const struct rfc822a *rfc, int n)
{
char *p, *q;
size_t addrbuflen=0;
char *addrbuf, *ptr;
rfc822_prname(rfc, n, &cntlen, &addrbuflen);
if (!(addrbuf=malloc(addrbuflen+1)))
return (0);
ptr=addrbuf;
rfc822_prname(rfc, n, &saveaddr, &ptr);
addrbuf[addrbuflen]=0;
/* Get rid of surrounding quotes */
for (p=q=addrbuf; *p; p++)
if (*p != '"') *q++=*p;
*q=0;
return (addrbuf);
}
char *rfc822_getname_orlist(const struct rfc822a *rfc, int n)
{
char *p, *q;
size_t addrbuflen=0;
char *addrbuf, *ptr;
rfc822_prname_orlist(rfc, n, &cntlen, &addrbuflen);
if (!(addrbuf=malloc(addrbuflen+1)))
return (0);
ptr=addrbuf;
rfc822_prname_orlist(rfc, n, &saveaddr, &ptr);
addrbuf[addrbuflen]=0;
/* Get rid of surrounding quotes */
for (p=q=addrbuf; *p; p++)
if (*p != '"') *q++=*p;
*q=0;
return (addrbuf);
}
char *rfc822_gettok(const struct rfc822token *t)
{
size_t addrbuflen=0;
char *addrbuf, *ptr;
rfc822tok_print(t, &cntlen, &addrbuflen);
if (!(addrbuf=malloc(addrbuflen+1)))
return (0);
ptr=addrbuf;
rfc822tok_print(t, &saveaddr, &ptr);
addrbuf[addrbuflen]=0;
return (addrbuf);
}

View File

@ -1,94 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include "rfc822.h"
#include <stdlib.h>
static void cntlen(char c, void *p)
{
c=c;
++ *(size_t *)p;
}
static void cntlensep(const char *p, void *ptr)
{
while (*p) cntlen(*p++, ptr);
}
static void saveaddr(char c, void *ptr)
{
*(*(char **)ptr)++=c;
}
static void saveaddrsep(const char *p, void *ptr)
{
while (*p) saveaddr(*p++, ptr);
}
char *rfc822_getaddrs(const struct rfc822a *rfc)
{
size_t addrbuflen=0;
char *addrbuf, *ptr;
rfc822_print(rfc, &cntlen, &cntlensep, &addrbuflen);
if (!(addrbuf=malloc(addrbuflen+1)))
return (0);
ptr=addrbuf;
rfc822_print(rfc, &saveaddr, &saveaddrsep, &ptr);
addrbuf[addrbuflen]=0;
return (addrbuf);
}
static void saveaddrsep_wrap(const char *p, void *ptr)
{
int c;
while ((c=*p++) != 0)
{
if (c == ' ') c='\n';
saveaddr(c, ptr);
}
}
char *rfc822_getaddrs_wrap(const struct rfc822a *rfc, int w)
{
size_t addrbuflen=0;
char *addrbuf, *ptr, *start, *lastnl;
rfc822_print(rfc, &cntlen, &cntlensep, &addrbuflen);
if (!(addrbuf=malloc(addrbuflen+1)))
return (0);
ptr=addrbuf;
rfc822_print(rfc, &saveaddr, &saveaddrsep_wrap, &ptr);
addrbuf[addrbuflen]=0;
for (lastnl=0, start=ptr=addrbuf; *ptr; )
{
while (*ptr && *ptr != '\n') ptr++;
if (ptr-start < w)
{
if (lastnl) *lastnl=' ';
lastnl=ptr;
if (*ptr) ++ptr;
}
else
{
if (lastnl)
start=lastnl+1;
else
{
start=ptr+1;
if (*ptr) ++ptr;
}
lastnl=0;
}
}
return (addrbuf);
}

View File

@ -1,113 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include "rfc822.h"
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
static const char * const months[]={
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"};
static const char * const wdays[]={
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"};
void rfc822_mkdate_buf(time_t t, char *buf)
{
struct tm *p;
int offset;
#if USE_TIME_ALTZONE
p=localtime(&t);
offset= -timezone;
if (p->tm_isdst > 0)
offset= -altzone;
if (offset % 60)
{
offset=0;
p=gmtime(&t);
}
offset /= 60;
#else
#if USE_TIME_DAYLIGHT
p=localtime(&t);
offset= -timezone;
if (p->tm_isdst > 0)
offset += 60*60;
if (offset % 60)
{
offset=0;
p=gmtime(&t);
}
offset /= 60;
#else
#if USE_TIME_GMTOFF
p=localtime(&t);
offset= p->tm_gmtoff;
if (offset % 60)
{
offset=0;
p=gmtime(&t);
}
offset /= 60;
#else
p=gmtime(&t);
offset=0;
#endif
#endif
#endif
offset = (offset % 60) + offset / 60 * 100;
sprintf(buf, "%s, %02d %s %04d %02d:%02d:%02d %+05d",
wdays[p->tm_wday],
p->tm_mday,
months[p->tm_mon],
p->tm_year+1900,
p->tm_hour,
p->tm_min,
p->tm_sec,
offset);
}
const char *rfc822_mkdate(time_t t)
{
static char buf[50];
rfc822_mkdate_buf(t, buf);
return (buf);
}

View File

@ -1,243 +0,0 @@
/*
** Copyright 1998 - 1999 Double Precision, Inc.
** See COPYING for distribution information.
*/
/*
** $Id$
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
/*
** time_t rfc822_parsedate(const char *p)
**
** p - contents of the Date: header, attempt to parse it into a time_t.
**
** returns - time_t, or 0 if the date cannot be parsed
*/
static unsigned parsedig(const char **p)
{
unsigned i=0;
while (isdigit((int)(unsigned char)**p))
{
i=i*10 + **p - '0';
++*p;
}
return (i);
}
static const char * const weekdays[7]={
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
} ;
static const char * const mnames[13]={
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec", NULL};
#define leap(y) ( \
((y) % 400) == 0 || \
(((y) % 4) == 0 && (y) % 100) )
static unsigned mlength[]={31,28,31,30,31,30,31,31,30,31,30,31};
#define mdays(m,y) ( (m) != 2 ? mlength[(m)-1] : leap(y) ? 29:28)
static const char * const zonenames[] = {
"UT","GMT",
"EST","EDT",
"CST","CDT",
"MST","MDT",
"PST","PDT",
"Z",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
NULL};
#define ZH(n) ( (n) * 60 * 60 )
static int zoneoffset[] = {
0, 0,
ZH(-5), ZH(-4),
ZH(-6), ZH(-5),
ZH(-7), ZH(-6),
ZH(-8), ZH(-7),
0,
ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12),
ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) };
static unsigned parsekey(const char **mon, const char * const *ary)
{
unsigned m, j;
for (m=0; ary[m]; m++)
{
for (j=0; ary[m][j]; j++)
if (tolower(ary[m][j]) != tolower((*mon)[j]))
break;
if (!ary[m][j])
{
*mon += j;
return (m+1);
}
}
return (0);
}
static int parsetime(const char **t)
{
unsigned h,m,s=0;
if (!isdigit((int)(unsigned char)**t)) return (-1);
h=parsedig(t);
if (h > 23) return (-1);
if (**t != ':') return (-1);
++*t;
if (!isdigit((int)(unsigned char)**t)) return (-1);
m=parsedig(t);
if (**t == ':')
{
++*t;
if (!isdigit((int)(unsigned char)**t)) return (-1);
s=parsedig(t);
}
if (m > 59 || s > 59) return (-1);
return (h * 60 * 60 + m * 60 + s);
}
time_t rfc822_parsedt(const char *rfcdt)
{
unsigned day=0, mon=0, year;
int secs;
int offset;
time_t t;
unsigned y;
/* Ignore day of the week. Tolerate "Tue, 25 Feb 1997 ... "
** without the comma. Tolerate "Feb 25 1997 ...".
*/
while (!day || !mon)
{
if (!*rfcdt) return (0);
if (isalpha((int)(unsigned char)*rfcdt))
{
if (mon) return (0);
mon=parsekey(&rfcdt, mnames);
if (!mon)
while (*rfcdt && isalpha((int)(unsigned char)*rfcdt))
++rfcdt;
continue;
}
if (isdigit((int)(unsigned char)*rfcdt))
{
if (day) return (0);
day=parsedig(&rfcdt);
if (!day) return (0);
continue;
}
++rfcdt;
}
while (*rfcdt && isspace((int)(unsigned char)*rfcdt))
++rfcdt;
if (!isdigit((int)(unsigned char)*rfcdt)) return (0);
year=parsedig(&rfcdt);
if (year < 70) year += 2000;
if (year < 100) year += 1900;
while (*rfcdt && isspace((int)(unsigned char)*rfcdt))
++rfcdt;
if (day == 0 || mon == 0 || mon > 12 || day > mdays(mon,year))
return (0);
secs=parsetime(&rfcdt);
if (secs < 0) return (0);
offset=0;
/* RFC822 sez no parenthesis, but I've seen (EST) */
while ( *rfcdt )
{
if (isalnum((int)(unsigned char)*rfcdt) || *rfcdt == '+' || *rfcdt == '-')
break;
++rfcdt;
}
if (isalpha((int)(unsigned char)*rfcdt))
{
int n=parsekey(&rfcdt, zonenames);
if (n > 0) offset= zoneoffset[n-1];
}
else
{
int sign=1;
unsigned n;
switch (*rfcdt) {
case '-':
sign= -1;
case '+':
++rfcdt;
}
if (isdigit((int)(unsigned char)*rfcdt))
{
n=parsedig(&rfcdt);
if (n > 2359 || (n % 100) > 59) n=0;
offset = sign * ( (n % 100) * 60 + n / 100 * 60 * 60);
}
}
if (year < 1970) return (0);
t=0;
for (y=1970; y<year; y++)
{
if ( leap(y) )
{
if (year-y >= 4)
{
y += 3;
t += ( 365*3+366 ) * 24 * 60 * 60;
continue;
}
t += 24 * 60 * 60;
}
t += 365 * 24 * 60 * 60;
}
for (y=1; y < mon; y++)
t += mdays(y, year) * 24 * 60 * 60;
return ( t + (day-1) * 24 * 60 * 60 + secs - offset );
}
const char *rfc822_mkdt(time_t t)
{
static char buf[80];
struct tm *tmptr=gmtime(&t);
buf[0]=0;
if (tmptr)
{
sprintf(buf, "%s, %02d %s %04d %02d:%02d:%02d GMT",
weekdays[tmptr->tm_wday],
tmptr->tm_mday,
mnames[tmptr->tm_mon],
tmptr->tm_year + 1900,
tmptr->tm_hour,
tmptr->tm_min,
tmptr->tm_sec);
}
return (buf);
}

View File

@ -1 +0,0 @@
timestamp

View File

@ -1,86 +0,0 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include "rfc822.h"
#include <stdio.h>
#include <stdlib.h>
static const char rcsid[]="$Id$";
static void print_func(char c, void *p)
{
p=p;
putchar(c);
}
static void print_separator(const char *s, void *p)
{
p=p;
printf("%s", s);
}
static struct rfc822t *tokenize(const char *p)
{
struct rfc822t *tp;
int i;
char buf[2];
printf("Tokenize: %s\n", p);
tp=rfc822t_alloc(p, NULL);
if (!tp) exit(0);
buf[1]=0;
for (i=0; i<tp->ntokens; i++)
{
buf[0]=tp->tokens[i].token;
if (buf[0] == '\0' || buf[0] == '"' || buf[0] == '(')
{
printf("%s: ", buf[0] == '"' ? "Quote":
buf[0] == '(' ? "Comment":"Atom");
fwrite(tp->tokens[i].ptr, tp->tokens[i].len, 1, stdout);
printf("\n");
}
else printf("Token: %s\n", buf[0] ? buf:"atom");
}
return (tp);
}
static struct rfc822a *doaddr(struct rfc822t *t)
{
struct rfc822a *a=rfc822a_alloc(t);
if (!a) exit(0);
printf("----\n");
rfc822_print(a, print_func, print_separator, NULL);
printf("\n");
rfc822_addrlist(a, print_func, NULL);
rfc822_namelist(a, print_func, NULL);
return (a);
}
int main()
{
struct rfc822t *t1, *t2, *t3, *t4;
struct rfc822a *a1, *a2, *a3, *a4;
t1=tokenize("nobody@example.com (Nobody (is) here\\) right)");
t2=tokenize("Distribution list: nobody@example.com daemon@example.com");
t3=tokenize("Mr Nobody <nobody@example.com>, Mr. Nobody <nobody@example.com>");
t4=tokenize("nobody@example.com, <nobody@example.com>, Mr. Nobody <nobody@example.com>");
a1=doaddr(t1);
a2=doaddr(t2);
a3=doaddr(t3);
a4=doaddr(t4);
rfc822a_free(a4);
rfc822a_free(a3);
rfc822a_free(a2);
rfc822a_free(a1);
rfc822t_free(t4);
rfc822t_free(t3);
rfc822t_free(t2);
rfc822t_free(t1);
return (0);
}

View File

@ -1,91 +0,0 @@
Tokenize: nobody@example.com (Nobody (is) here\) right)
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Comment: (Nobody (is) here\) right)
Tokenize: Distribution list: nobody@example.com daemon@example.com
Atom: Distribution
Atom: list
Token: :
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Atom: daemon
Token: @
Atom: example
Token: .
Atom: com
Tokenize: Mr Nobody <nobody@example.com>, Mr. Nobody <nobody@example.com>
Atom: Mr
Atom: Nobody
Token: <
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Token: >
Token: ,
Atom: Mr
Token: .
Atom: Nobody
Token: <
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Token: >
Tokenize: nobody@example.com, <nobody@example.com>, Mr. Nobody <nobody@example.com>
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Token: ,
Token: <
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Token: >
Token: ,
Atom: Mr
Token: .
Atom: Nobody
Token: <
Atom: nobody
Token: @
Atom: example
Token: .
Atom: com
Token: >
----
nobody@example.com (Nobody (is) here\) right)
nobody@example.com
Nobody (is) here\) right
----
Distribution list: nobody@example.com, daemon@example.com
nobody@example.com
daemon@example.com
nobody@example.com
daemon@example.com
----
Mr Nobody <nobody@example.com>, "Mr. Nobody" <nobody@example.com>
nobody@example.com
nobody@example.com
Mr Nobody
"Mr. Nobody"
----
nobody@example.com, nobody@example.com, "Mr. Nobody" <nobody@example.com>
nobody@example.com
nobody@example.com
nobody@example.com
nobody@example.com
nobody@example.com
"Mr. Nobody"

View File

@ -1,381 +0,0 @@
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id$ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#include <string.h>
#include "md5.h"
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned */
X = (const md5_word_t *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
{
const md5_byte_t *p = data;
size_t left = nbytes;
size_t offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += (int)(nbytes >> 29);
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}

View File

@ -1,91 +0,0 @@
/*
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id$ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
# define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
void md5_init(md5_state_t *pms);
/* Append a string to the message. */
void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
/* Finish the message and return the digest. */
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */

View File

@ -1,169 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $Id$
*
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$Header$";
#endif /* LIBC_SCCS and not lint */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.h>
#include "md5.h"
#define MD5_CTX md5_state_t
#define MD5Init md5_init
#define MD5Update(ctx, data, len) md5_append(ctx, (md5_byte_t*)data, len)
#define MD5Final(digest, ctx) md5_finish(ctx, digest)
static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static void
to64(s, v, n)
char *s;
unsigned long v;
int n;
{
while (--n >= 0) {
*s++ = itoa64[v&0x3f];
v >>= 6;
}
}
/*
* UNIX password
*
* Use MD5 for what it is best at...
*/
char *
md5_crypt(pw, salt)
register const char *pw;
register const char *salt;
{
static char *magic = "$1$"; /*
* This string is magic for
* this algorithm. Having
* it this way, we can get
* get better later on
*/
static char passwd[120], *p;
static const char *sp,*ep;
unsigned char final[16];
size_t sl,pl,i,j;
MD5_CTX ctx,ctx1;
unsigned long l;
/* Refine the Salt first */
sp = salt;
/* If it starts with the magic string, then skip that */
if(!strncmp(sp,magic,strlen(magic)))
sp += strlen(magic);
/* It stops at the first '$', max 8 chars */
for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
continue;
/* get the length of the true salt */
sl = ep - sp;
MD5Init(&ctx);
/* The password first, since that is what is most unknown */
MD5Update(&ctx,pw,strlen(pw));
/* Then our magic string */
MD5Update(&ctx,magic,strlen(magic));
/* Then the raw salt */
MD5Update(&ctx,sp,sl);
/* Then just as many characters of the MD5(pw,salt,pw) */
MD5Init(&ctx1);
MD5Update(&ctx1,pw,strlen(pw));
MD5Update(&ctx1,sp,sl);
MD5Update(&ctx1,pw,strlen(pw));
MD5Final(final,&ctx1);
for(pl = strlen(pw); pl > 0; )
{ MD5Update(&ctx,final,pl>16 ? 16 : pl);
if ( pl > 16 )
pl -= 16;
else
break;
}
/* Don't leave anything around in vm they could use. */
memset(final,0,sizeof final);
/* Then something really weird... */
for (j=0,i = strlen(pw); i ; i >>= 1)
if(i&1)
MD5Update(&ctx, final+j, 1);
else
MD5Update(&ctx, pw+j, 1);
/* Now make the output string */
strcpy(passwd,magic);
strncat(passwd,sp,sl);
strcat(passwd,"$");
MD5Final(final,&ctx);
/*
* and now, just to make sure things don't run too fast
* On a 60 Mhz Pentium this takes 34 msec, so you would
* need 30 seconds to build a 1000 entry dictionary...
*/
for(i=0;i<1000;i++) {
MD5Init(&ctx1);
if(i & 1)
MD5Update(&ctx1,pw,strlen(pw));
else
MD5Update(&ctx1,final,16);
if(i % 3)
MD5Update(&ctx1,sp,sl);
if(i % 7)
MD5Update(&ctx1,pw,strlen(pw));
if(i & 1)
MD5Update(&ctx1,final,16);
else
MD5Update(&ctx1,pw,strlen(pw));
MD5Final(final,&ctx1);
}
p = passwd + strlen(passwd);
l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
l = final[11] ; to64(p,l,2); p += 2;
*p = '\0';
/* Don't leave anything around in vm they could use. */
memset(final,0,sizeof final);
return passwd;
}

View File

@ -1,542 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemaker@uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2009, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <SWI-Stream.h>
#include <SWI-Prolog.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "error.h"
#define streq(s,q) (strcmp((s), (q)) == 0)
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Memory-files
make_memory_file(-Handle)
free_memory_file(+Handle)
open_memory_file(+Handle, +Mode, -Stream)
size_memory_file(+Handle, -Size)
memory_file_to_codes(+Handle, -Codes)
memory_file_to_atom(+Handle, -Atom)
atom_to_memory_file(+Atom, -Handle)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static functor_t FUNCTOR_memory_file1;
static atom_t ATOM_encoding;
static atom_t ATOM_unknown;
static atom_t ATOM_octet;
static atom_t ATOM_ascii;
static atom_t ATOM_iso_latin_1;
static atom_t ATOM_text;
static atom_t ATOM_utf8;
static atom_t ATOM_unicode_be;
static atom_t ATOM_unicode_le;
static atom_t ATOM_wchar_t;
static atom_t ATOM_read;
static atom_t ATOM_write;
static atom_t ATOM_free_on_close;
#define MEMFILE_MAGIC 0x5624a6b3L
#define NOSIZE ((size_t)-1)
typedef struct
{ long magic; /* MEMFILE_MAGIC */
IOENC encoding; /* encoding of the data */
int free_on_close; /* free if it is closed */
char *data; /* data of the file */
size_t data_size; /* byte-size of data */
size_t size; /* size in characters */
IOSTREAM *stream; /* Stream hanging onto it */
atom_t atom; /* Created from atom */
} memfile;
static int
unify_memfile(term_t handle, memfile *f)
{ return PL_unify_term(handle,
PL_FUNCTOR, FUNCTOR_memory_file1,
PL_POINTER, f);
}
static int
get_memfile(term_t handle, memfile **f)
{ if ( PL_is_functor(handle, FUNCTOR_memory_file1) )
{ term_t a = PL_new_term_ref();
void *ptr;
_PL_get_arg(1, handle, a);
if ( PL_get_pointer(a, &ptr) )
{ memfile *m = ptr;
if ( m->magic == MEMFILE_MAGIC )
{ *f = ptr;
return TRUE;
}
return pl_error(NULL, 0, NULL, ERR_EXISTENCE,
"memory_file", handle);
}
}
return pl_error(NULL, 0, NULL, ERR_ARGTYPE, 1,
handle, "memory_file");
}
static foreign_t
new_memory_file(term_t handle)
{ memfile *m = calloc(1, sizeof(*m));
if ( !m )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno,
"create", "memory_file", handle);
m->magic = MEMFILE_MAGIC;
m->encoding = ENC_UTF8;
m->data = 0;
m->size = 0;
if ( unify_memfile(handle, m) )
return TRUE;
m->magic = 0;
free(m);
return FALSE;
}
static int
destroy_memory_file(memfile *m)
{ if ( m->stream )
Sclose(m->stream);
if ( m->atom )
PL_unregister_atom(m->atom);
else if ( m->data )
Sfree(m->data); /* MS-Windows: malloc by other DLL! */
m->magic = 0;
free(m);
return TRUE;
}
static foreign_t
free_memory_file(term_t handle)
{ memfile *m;
if ( get_memfile(handle, &m) )
return destroy_memory_file(m);
return FALSE;
}
static void
closehook(void *closure)
{ memfile *m = closure;
m->stream = NULL;
if ( m->free_on_close )
destroy_memory_file(m);
}
static foreign_t
alreadyOpen(term_t handle, const char *op)
{ return pl_error(NULL, 0, "already open",
ERR_PERMISSION, handle, op, "memory_file");
}
static struct encname
{ IOENC code;
atom_t *name;
} encoding_names[] =
{ { ENC_UNKNOWN, &ATOM_unknown },
{ ENC_OCTET, &ATOM_octet },
{ ENC_ASCII, &ATOM_ascii },
{ ENC_ISO_LATIN_1, &ATOM_iso_latin_1 },
{ ENC_ANSI, &ATOM_text },
{ ENC_UTF8, &ATOM_utf8 },
{ ENC_UNICODE_BE, &ATOM_unicode_be },
{ ENC_UNICODE_LE, &ATOM_unicode_le },
{ ENC_WCHAR, &ATOM_wchar_t },
{ ENC_UNKNOWN, NULL },
};
IOENC
atom_to_encoding(atom_t a)
{ struct encname *en;
for(en=encoding_names; en->name; en++)
{ if ( *en->name == a )
return en->code;
}
return ENC_UNKNOWN;
}
static int
get_encoding(term_t t, IOENC *enc)
{ atom_t en;
if ( PL_get_atom(t, &en) )
{ IOENC encoding;
if ( (encoding = atom_to_encoding(en)) == ENC_UNKNOWN )
return pl_error(NULL, 0, NULL, ERR_DOMAIN, t, "encoding");
*enc = encoding;
return TRUE;
}
return pl_error(NULL, 0, NULL, ERR_TYPE, t, "encoding");
}
static foreign_t
open_memory_file4(term_t handle, term_t mode, term_t stream, term_t options)
{ memfile *m;
char *x;
atom_t iom;
IOSTREAM *fd;
IOENC encoding;
int free_on_close = FALSE;
if ( !get_memfile(handle, &m) )
return FALSE;
if ( m->stream )
return alreadyOpen(handle, "open");
if ( !PL_get_atom(mode, &iom) )
return pl_error("open_memory_file", 3, NULL, ERR_ARGTYPE, 2,
mode, "io_mode");
encoding = m->encoding;
if ( options )
{ term_t tail = PL_copy_term_ref(options);
term_t head = PL_new_term_ref();
while(PL_get_list(tail, head, tail))
{ int arity;
atom_t name;
if ( PL_get_name_arity(head, &name, &arity) && arity == 1 )
{ term_t arg = PL_new_term_ref();
_PL_get_arg(1, head, arg);
if ( name == ATOM_encoding )
{ if ( !get_encoding(arg, &encoding) )
return FALSE;
} else if ( name == ATOM_free_on_close )
{ if ( !PL_get_bool(arg, &free_on_close) )
return pl_error("open_memory_file", 4, NULL, ERR_TYPE,
arg, "boolean");
}
} else
return pl_error("open_memory_file", 4, NULL, ERR_TYPE, head, "option");
}
if ( !PL_get_nil(tail) )
return pl_error("open_memory_file", 4, NULL, ERR_TYPE, tail, "list");
}
if ( iom == ATOM_write )
{ x = "w";
if ( m->atom )
return pl_error("open_memory_file", 3, NULL, ERR_PERMISSION,
handle, "write", "memory_file");
if ( m->data )
{ Sfree(m->data);
m->data = NULL;
}
m->data_size = 0;
m->size = NOSIZE; /* don't know */
m->encoding = encoding;
} else if ( iom == ATOM_read )
{ x = "r";
m->free_on_close = free_on_close;
} else
{ return pl_error("open_memory_file", 3, NULL, ERR_DOMAIN,
mode, "io_mode");
}
if ( !(fd = Sopenmem(&m->data, &m->data_size, x)) )
return pl_error("open_memory_file", 3, NULL, ERR_ERRNO, errno,
"create", "memory_file", handle);
fd->close_hook = closehook;
fd->closure = m;
fd->encoding = encoding;
m->stream = fd;
return PL_unify_stream(stream, fd);
}
static foreign_t
open_memory_file(term_t handle, term_t mode, term_t stream)
{ return open_memory_file4(handle, mode, stream, 0);
}
static foreign_t
size_memory_file(term_t handle, term_t sizeh, term_t encoding)
{ memfile *m;
if ( get_memfile(handle, &m) )
{ if ( m->stream && !m->atom )
return alreadyOpen(handle, "size");
if ( m->data )
{ IOENC size_enc = m->encoding;
size_t size;
if ( encoding )
{ if ( !get_encoding(encoding, &size_enc) )
return FALSE;
} else
size_enc = m->encoding;
if ( m->size != NOSIZE && size_enc == m->encoding )
{ size = m->size;
} else
{ switch( size_enc )
{ case ENC_ISO_LATIN_1:
case ENC_OCTET:
size = m->data_size;
break;
case ENC_WCHAR:
size = m->data_size / sizeof(wchar_t);
break;
case ENC_UTF8:
size = PL_utf8_strlen(m->data, m->data_size);
break;
default:
assert(0);
return FALSE;
}
if ( size_enc == m->encoding )
m->size = size;
}
return PL_unify_int64(sizeh, size);
} else
{ return PL_unify_integer(sizeh, 0);
}
}
return FALSE;
}
static foreign_t
size_memory_file2(term_t handle, term_t size)
{ return size_memory_file(handle, size, 0);
}
static foreign_t
size_memory_file3(term_t handle, term_t size, term_t encoding)
{ return size_memory_file(handle, size, encoding);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
utf8_position_memory_file(+MF, -Here, -Size)
Given MF is a UTF-8 encoded memory file, unify here with the
byte-position of the read-pointer and Size with the total size of the
memory file in bytes. This is a bit hacky predicate, but the information
is easily available at low cost, while it is very valuable for producing
answers in content-length computation of the HTTP server. See
http_wrapper.pl
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static foreign_t
utf8_position(term_t handle, term_t here, term_t size)
{ memfile *m;
if ( !get_memfile(handle, &m) )
return FALSE;
if ( m->encoding != ENC_UTF8 )
return pl_error(NULL, 0, "no UTF-8 encoding",
ERR_PERMISSION, handle, "utf8_position", "memory_file");
if ( !PL_unify_integer(size, m->data_size) )
return FALSE;
if ( m->stream )
{ IOPOS *op = m->stream->position;
long p;
m->stream->position = NULL;
p = Stell(m->stream);
m->stream->position = op;
return PL_unify_integer(here, p);
} else
return PL_unify_integer(here, 0);
}
static foreign_t
atom_to_memory_file(term_t atom, term_t handle)
{ atom_t a;
if ( PL_get_atom(atom, &a) )
{ memfile *m = calloc(1, sizeof(*m));
if ( !m )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "create", "memory_file", handle);
m->atom = a;
PL_register_atom(m->atom);
m->magic = MEMFILE_MAGIC;
if ( (m->data = (char *)PL_atom_nchars(a, &m->size)) )
{ m->encoding = ENC_ISO_LATIN_1;
m->data_size = m->size;
} else if ( (m->data = (char *)PL_atom_wchars(a, &m->size)) )
{ m->encoding = ENC_WCHAR;
m->data_size = m->size * sizeof(wchar_t);
} else if ( PL_blob_data(a, &m->size, NULL) )
{ m->data = PL_blob_data(a, &m->data_size, NULL);
m->encoding = ENC_OCTET;
m->size = m->data_size;
}
if ( unify_memfile(handle, m) )
return TRUE;
else
{ PL_unregister_atom(m->atom);
m->magic = 0;
free(m);
return FALSE;
}
} else
{ return pl_error(NULL, 0, NULL, ERR_ARGTYPE, 1,
atom, "atom");
}
}
static foreign_t
memory_file_to_text(term_t handle, term_t atom, term_t encoding, int flags)
{ memfile *m;
if ( get_memfile(handle, &m) )
{ IOENC enc;
if ( encoding )
{ if ( !get_encoding(encoding, &enc) )
return FALSE;
} else
enc = m->encoding;
if ( m->stream )
return alreadyOpen(handle, "to_atom");
if ( m->data )
{ switch(enc)
{ case ENC_ISO_LATIN_1:
case ENC_OCTET:
return PL_unify_chars(atom, flags, m->data_size, m->data);
case ENC_WCHAR:
return PL_unify_wchars(atom, flags, m->data_size/sizeof(wchar_t), (pl_wchar_t*)m->data);
case ENC_UTF8:
return PL_unify_chars(atom, flags|REP_UTF8, m->data_size, m->data);
default:
assert(0);
}
} else
return PL_unify_chars(atom, flags, 0, "");
}
return FALSE;
}
static foreign_t
memory_file_to_atom2(term_t handle, term_t atom)
{ return memory_file_to_text(handle, atom, 0, PL_ATOM);
}
static foreign_t
memory_file_to_atom3(term_t handle, term_t atom, term_t encoding)
{ return memory_file_to_text(handle, atom, encoding, PL_ATOM);
}
static foreign_t
memory_file_to_codes2(term_t handle, term_t atom)
{ return memory_file_to_text(handle, atom, 0, PL_CODE_LIST);
}
static foreign_t
memory_file_to_codes3(term_t handle, term_t atom, term_t encoding)
{ return memory_file_to_text(handle, atom, encoding, PL_CODE_LIST);
}
#define MKATOM(n) ATOM_ ## n = PL_new_atom(#n);
install_t
install_memfile()
{ if ( PL_query(PL_QUERY_VERSION) <= 50505 )
{ PL_warning("Requires SWI-Prolog version 5.5.6 or later");
return;
}
FUNCTOR_memory_file1 = PL_new_functor(PL_new_atom("$memory_file"), 1);
MKATOM(encoding);
MKATOM(unknown);
MKATOM(octet);
MKATOM(ascii);
MKATOM(iso_latin_1);
MKATOM(text);
MKATOM(utf8);
MKATOM(unicode_be);
MKATOM(unicode_le);
MKATOM(wchar_t);
MKATOM(read);
MKATOM(write);
MKATOM(free_on_close);
PL_register_foreign("new_memory_file", 1, new_memory_file, 0);
PL_register_foreign("free_memory_file", 1, free_memory_file, 0);
PL_register_foreign("size_memory_file", 2, size_memory_file2, 0);
PL_register_foreign("size_memory_file", 3, size_memory_file3, 0);
PL_register_foreign("open_memory_file", 3, open_memory_file, 0);
PL_register_foreign("open_memory_file", 4, open_memory_file4, 0);
PL_register_foreign("atom_to_memory_file", 2, atom_to_memory_file, 0);
PL_register_foreign("memory_file_to_atom", 2, memory_file_to_atom2, 0);
PL_register_foreign("memory_file_to_codes", 2, memory_file_to_codes2,0);
PL_register_foreign("memory_file_to_atom", 3, memory_file_to_atom3, 0);
PL_register_foreign("memory_file_to_codes", 3, memory_file_to_codes3,0);
PL_register_foreign("utf8_position_memory_file", 3, utf8_position, 0);
}

View File

@ -1,49 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(memory_file,
[ new_memory_file/1, % -Handle
free_memory_file/1, % +Handle
size_memory_file/2, % +Handle, -Size
size_memory_file/3, % +Handle, -Size, +Encoding
open_memory_file/3, % +Handle, +Mode, -Stream
open_memory_file/4, % +Handle, +Mode, -Stream, +Options
atom_to_memory_file/2, % +Atom, -Handle
memory_file_to_atom/2, % +Handle, -Atom
memory_file_to_codes/2, % +Handle, -CodeList
memory_file_to_atom/3, % +Handle, -Atom, +Encoding
memory_file_to_codes/3, % +Handle, -CodeList, +Encoding
utf8_position_memory_file/3 % +Handle, -Here, -Size
]).
:- use_module(library(shlib)).
:- use_foreign_library(foreign(memfile)).

View File

@ -1,391 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2005, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef __WINDOWS__
#define HAVE_MALLOC_H 1
#endif
#include <SWI-Stream.h>
#include <SWI-Prolog.h>
#include <rfc2045.h>
#include "error.h"
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <errno.h>
#undef max /* be sure we have ours */
#define max(x, y) ((x)>(y) ? (x) : (y))
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This module defines an interface to the rfc2045 (MIME) parsing library
by Double Precision, Inc, part of the maildrop system.
Parsing MIME messages is accomplished using a single predicate. This
predicate parses the input and returns a complex term holding the
various MIME message parts. The mime message is encoded into the
following structure:
mime(Attributes, Data, SubMimeList)
Where Data is the (decoded) field data returned as an atom, Attributes
is a property-list and SubMimeList is a list of mime/3 terms reflecting
the sub-parts. Attributes contains the following members:
# id(Atom)
# description(Atom)
# language(Atom)
# md5(Atom)
# type(Atom)
# character_set(Atom)
# transfer_encoding(Atom)
# disposition(Atom)
# filename(Atom)
# name(Atom)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static atom_t ATOM_;
static atom_t ATOM_stream;
static functor_t FUNCTOR_type1;
static functor_t FUNCTOR_transfer_encoding1;
static functor_t FUNCTOR_character_set1;
static functor_t FUNCTOR_mime3;
static functor_t FUNCTOR_id1;
static functor_t FUNCTOR_description1;
static functor_t FUNCTOR_language1;
static functor_t FUNCTOR_md51;
static functor_t FUNCTOR_disposition1;
static functor_t FUNCTOR_name1;
static functor_t FUNCTOR_filename1;
struct dbuf
{ char *buf;
size_t size;
size_t allocated;
};
static int
add_data(const char *ndata, size_t len, void *closure)
{ struct dbuf *dbuf = closure;
if ( dbuf->size + (int)len > dbuf->allocated )
{ dbuf->allocated = max(dbuf->allocated, max(1024, dbuf->size + (int)len));
if ( dbuf->buf )
dbuf->buf = realloc(dbuf->buf, dbuf->allocated);
else
dbuf->buf = malloc(dbuf->allocated);
if ( !dbuf->buf )
{ pl_error("mime_parse", 3, NULL, ERR_ERRNO, errno, "add_data", "mime", 0);
return -1;
}
}
memcpy(dbuf->buf+dbuf->size, ndata, len);
dbuf->size += len;
return 0;
}
static int
mime_unify_data(term_t data, struct rfc2045 *rfc, const char *buffer)
{ off_t start_pos, end_pos, start_body, nlines, nbodylines;
struct dbuf dbuf;
int rval;
dbuf.buf = NULL;
dbuf.size = 0;
dbuf.allocated = 0;
rfc2045_mimepos(rfc,
&start_pos, &end_pos, &start_body, &nlines, &nbodylines);
rfc2045_cdecode_start(rfc, add_data, &dbuf);
if ( rfc2045_cdecode(rfc, buffer+start_body, end_pos-start_body) == 0 &&
rfc2045_cdecode_end(rfc) == 0 )
{ rval = PL_unify_atom_nchars(data, dbuf.size, dbuf.buf);
} else
rval = FALSE;
if ( dbuf.buf )
free(dbuf.buf);
return rval;
}
/* add_attribute() adds a name(value) term to the list if value is provided
(i.e. not NULL and non "")
*/
static int
add_attribute(term_t list, const char *value, functor_t functor)
{ if ( value && value[0] )
{ term_t h = PL_new_term_ref();
int rval;
rval = PL_unify_list(list, h, list) &&
PL_unify_term(h, PL_FUNCTOR, functor, PL_CHARS, value);
PL_reset_term_refs(h);
return rval;
}
return TRUE;
}
static int
mime_unify(term_t result, struct rfc2045 *rfc, const char *buffer)
{ term_t data = PL_new_term_ref();
term_t subs = PL_new_term_ref();
term_t atts = PL_new_term_ref();
if ( !PL_unify_term(result,
PL_FUNCTOR, FUNCTOR_mime3,
PL_TERM, atts,
PL_TERM, data,
PL_TERM, subs) )
return FALSE;
if ( rfc->isdummy )
{ if ( !PL_unify_nil(data) ||
!PL_unify_nil(atts) )
return FALSE;
} else
{ term_t at = PL_copy_term_ref(atts);
const char *type, *enc, *cset;
const char *disp, *name, *fnam;
const char *id = rfc2045_content_id(rfc);
const char *desc = rfc2045_content_description(rfc);
const char *lang = rfc2045_content_language(rfc);
const char *md5 = rfc2045_content_md5(rfc);
rfc2045_mimeinfo(rfc, &type, &enc, &cset);
rfc2045_dispositioninfo(rfc, &disp, &name, &fnam);
if ( !add_attribute(at, type, FUNCTOR_type1) ) return FALSE;
if ( !add_attribute(at, enc, FUNCTOR_transfer_encoding1) ) return FALSE;
if ( !add_attribute(at, cset, FUNCTOR_character_set1) ) return FALSE;
if ( !add_attribute(at, id, FUNCTOR_id1) ) return FALSE;
if ( !add_attribute(at, desc, FUNCTOR_description1) ) return FALSE;
if ( !add_attribute(at, lang, FUNCTOR_language1) ) return FALSE;
if ( !add_attribute(at, disp, FUNCTOR_disposition1) ) return FALSE;
if ( !add_attribute(at, name, FUNCTOR_name1) ) return FALSE;
if ( !add_attribute(at, fnam, FUNCTOR_filename1) ) return FALSE;
if ( !add_attribute(at, md5, FUNCTOR_md51) ) return FALSE;
if ( !PL_unify_nil(at) )
return FALSE;
}
if ( rfc->firstpart )
{ term_t st = PL_copy_term_ref(subs);
term_t s = PL_new_term_ref();
struct rfc2045 *sub;
if ( !PL_unify_atom(data, ATOM_) )
return FALSE;
for(sub=rfc->firstpart; sub; sub = sub->next)
{ if ( sub->isdummy )
continue;
if ( !PL_unify_list(st, s, st) ||
!mime_unify(s, sub, buffer) )
return FALSE;
}
return PL_unify_nil(st);
} else
{ if ( !PL_unify_nil(subs) ||
!mime_unify_data(data, rfc, buffer) )
return FALSE;
}
return TRUE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
get_character_data()
Get a buffer of data from a specification. Currently the following
specs are acceptable:
stream(Stream) All data from this stream
stream(Stream, N) At most N characters from stream
Atom, String, CodeList Data from native Prolog character data
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
get_character_data(term_t from, char **data, size_t *len, int *malloced)
{ atom_t name;
int arity;
char *buf;
size_t size;
if ( PL_get_name_arity(from, &name, &arity) && arity > 0 )
{ if ( name == ATOM_stream )
{ IOSTREAM *stream;
term_t arg = PL_new_term_ref();
_PL_get_arg(1, from, arg);
if ( !PL_get_stream_handle(arg, &stream) )
return pl_error(NULL, 0, NULL, ERR_ARGTYPE, 1, from, "stream");
if ( arity == 1 ) /* stream(Stream) */
{ int c;
size_t done, allocated = 1024;
if ( !(buf = malloc(allocated)) )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "allocate", "memory", 0);
for( done=0; (c=Sgetcode(stream)) != EOF; )
{ if ( done >= allocated )
{ allocated *= 2;
if ( !(buf = realloc(buf, allocated)) )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "allocate", "memory", 0);
}
buf[done++] = c;
}
*len = done;
*data = buf;
*malloced = TRUE;
return TRUE;
} else if ( arity == 2 ) /* stream(Stream, Length) */
{ long size;
long done;
int c;
_PL_get_arg(2, from, arg);
if ( !PL_get_long(arg, &size) || size < 0 )
return pl_error(NULL, 0, NULL, ERR_ARGTYPE, 1, arg, "natural");
if ( !(buf = malloc(size)) )
return pl_error(NULL, 0, NULL, ERR_ERRNO, errno, "allocate", "memory", 0);
for( done=0; (c=Sgetcode(stream)) != EOF && done < size; )
buf[done++] = c;
*len = done;
*data = buf;
*malloced = TRUE;
return TRUE;
}
}
} else if ( PL_get_nchars(from, &size, data, CVT_ATOM|CVT_STRING|CVT_LIST) )
{ *len = size;
*malloced = FALSE;
return TRUE;
}
return pl_error(NULL, 0, NULL, ERR_ARGTYPE, 1, from, "data");
}
foreign_t
mime_parse(term_t handle, term_t result)
{ char *buf;
size_t len = 0;
int malloced = FALSE;
struct rfc2045 *rfc;
int rval;
if ( !get_character_data(handle, &buf, &len, &malloced) )
return FALSE;
rfc = rfc2045_alloc();
rfc2045_parse(rfc, buf, len);
rval = mime_unify(result, rfc, buf);
if ( malloced )
free(buf);
rfc2045_free(rfc);
return rval;
}
/*******************************
* ERRORS *
*******************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Not typically elegant, but the documentation whishes us to call exit(),
which is even worse.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
rfc2045_error(const char *errmsg)
{ term_t e = PL_new_term_ref();
if ( (e=PL_new_term_ref()) &&
PL_unify_term(e,
PL_FUNCTOR_CHARS, "error", 2,
PL_FUNCTOR_CHARS, "mime", 1,
PL_CHARS, errmsg,
PL_VARIABLE) )
PL_throw(e);
PL_fatal_error("Could not recover from rfc2045 error");
}
/*******************************
* INSTALL *
*******************************/
#define mkfunctor(n, a) PL_new_functor(PL_new_atom(n), a)
install_t
install_mime()
{ ATOM_ = PL_new_atom("");
ATOM_stream = PL_new_atom("stream");
FUNCTOR_type1 = mkfunctor("type", 1);
FUNCTOR_transfer_encoding1 = mkfunctor("transfer_encoding", 1);
FUNCTOR_character_set1 = mkfunctor("character_set", 1);
FUNCTOR_mime3 = mkfunctor("mime", 3);
FUNCTOR_id1 = mkfunctor("id", 1);
FUNCTOR_description1 = mkfunctor("description", 1);
FUNCTOR_language1 = mkfunctor("language", 1);
FUNCTOR_md51 = mkfunctor("md5", 1);
FUNCTOR_disposition1 = mkfunctor("disposition", 1);
FUNCTOR_name1 = mkfunctor("name", 1);
FUNCTOR_filename1 = mkfunctor("filename", 1);
PL_register_foreign("mime_parse", 2, mime_parse, 0);
}

View File

@ -1,67 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(mime,
[ mime_parse/2 % +Data, -Mime
]).
:- use_module(library(shlib)).
:- use_foreign_library(foreign(mime), install_mime).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This module defines an interface to the rfc2045 (MIME) parsing library
by Double Precision, Inc, part of the maildrop system. This library is
distributed under the GPL and therefore all code using this library
should comply to the GPL.
Parsing MIME messages is accomplished using a single predicate. This
predicate parses the input and returns a complex term holding the
various MIME message parts. The mime message is encoded into the
following structure:
mime(Attributes, Data, SubMimeList)
Where Data is the (decoded) field data returned as an atom, Attributes
is a property-list and SubMimeList is a list of mime/3 terms reflecting
the sub-parts. Attributes contains the following members:
# id(Atom)
# description(Atom)
# language(Atom)
# md5(Atom)
# type(Atom)
# character_set(Atom)
# transfer_encoding(Atom)
# disposition(Atom)
# filename(Atom)
# name(Atom)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

View File

@ -1,360 +0,0 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2003-09-02.23
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003
# Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Send bug reports to <bug-automake@gnu.org>."
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
aclocal*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case "$f" in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if [ ! -f y.tab.h ]; then
echo >y.tab.h
fi
if [ ! -f y.tab.c ]; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex|flex)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if [ ! -f lex.yy.c ]; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
# We have makeinfo, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
fi
touch $file
;;
tar)
shift
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
fi
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

File diff suppressed because it is too large Load Diff

View File

@ -1,196 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2007, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
#ifndef H_NONBLOCKIO_INCLUDED
#define H_NONBLOCKIO_INCLUDED
/*******************************
* GET REQUIRED HEADERS *
*******************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <SWI-Stream.h>
#include <SWI-Prolog.h>
#ifdef __WINDOWS__
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else /*__WINDOWS__*/
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#ifdef HAVE_H_ERRNO
extern int h_errno;
#else
#define h_errno errno
#endif
#ifndef HAVE_SOCKLEN_T
#define socklen_t size_t
#endif
typedef int SOCKET;
#endif /*__WINDOWS__*/
typedef enum
{ TCP_ERRNO,
TCP_HERRNO
} nbio_error_map;
typedef enum /* nbio_setopt() commands */
{ TCP_NONBLOCK,
TCP_REUSEADDR,
TCP_NO_DELAY,
TCP_DISPATCH,
TCP_INSTREAM,
TCP_OUTSTREAM,
UDP_BROADCAST,
NBIO_END
} nbio_option;
typedef enum
{ REQ_NONE = 0, /* no request pending */
REQ_ACCEPT,
REQ_CONNECT,
REQ_READ,
REQ_WRITE,
REQ_RECVFROM,
REQ_SENDTO
} nbio_request;
/* nbio_get_flags() mask */
#define PLSOCK_INSTREAM 0x001
#define PLSOCK_OUTSTREAM 0x002
#define PLSOCK_BIND 0x004 /* What have we done? */
#define PLSOCK_LISTEN 0x008
#define PLSOCK_CONNECT 0x010
#define PLSOCK_ACCEPT 0x020 /* Set on accepted sockets */
#define PLSOCK_NONBLOCK 0x040 /* Set to non-blocking mode */
#define PLSOCK_DISPATCH 0x080 /* do not dispatch events */
#define PLSOCK_CLOSE_SEEN 0x100 /* FD_CLOSE seen */
#define PLSOCK_EOF_SEEN 0x200 /* Seen end-of-file */
#define PLSOCK_WAITING 0x400 /* using nbio_wait() */
typedef int nbio_sock_t; /* socket handle (not a file-descr) */
typedef struct _plsocket *plsocket_ptr; /* wrapped socket */
/*******************************
* BASIC FUNCTIONS *
*******************************/
#ifdef HAVE_DECLSPEC
#define NBIO_EXPORT(type) __declspec(dllexport) type
#else
#define NBIO_EXPORT(type) extern type
#endif
NBIO_EXPORT(int) nbio_init(const char *module);
NBIO_EXPORT(int) nbio_cleanup(void);
NBIO_EXPORT(int) nbio_debug(int level);
NBIO_EXPORT(nbio_sock_t)
nbio_socket(int domain, int type, int protocol);
NBIO_EXPORT(int) nbio_connect(nbio_sock_t socket,
const struct sockaddr *serv_addr,
size_t addrlen);
NBIO_EXPORT(int) nbio_bind(nbio_sock_t socket,
struct sockaddr *my_addr,
size_t addrlen);
NBIO_EXPORT(int) nbio_listen(nbio_sock_t socket, int backlog);
NBIO_EXPORT(nbio_sock_t)
nbio_accept(nbio_sock_t master,
struct sockaddr *addr,
socklen_t *addrlen);
extern ssize_t nbio_read(nbio_sock_t socket, char *buf, size_t bufSize);
extern ssize_t nbio_write(nbio_sock_t socket, char *buf, size_t bufSize);
NBIO_EXPORT(int) nbio_closesocket(nbio_sock_t socket);
extern int nbio_close_input(nbio_sock_t socket);
extern int nbio_close_output(nbio_sock_t socket);
extern ssize_t nbio_recvfrom(int socket, void *buf, size_t bufSize, int flags,
struct sockaddr *from, socklen_t *fromlen);
extern ssize_t nbio_sendto(nbio_sock_t socket, void *buf, size_t bufSize, int flags,
const struct sockaddr *to, socklen_t tolen);
NBIO_EXPORT(int) nbio_wait(nbio_sock_t socket, nbio_request);
NBIO_EXPORT(SOCKET) nbio_fd(nbio_sock_t socket);
extern int nbio_select(int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
extern int nbio_unify_ip4(term_t ip4, unsigned long hip);
extern int nbio_get_ip(term_t ip4, struct in_addr *ip);
extern int nbio_error(int code, nbio_error_map map);
extern const char*
nbio_last_error(nbio_sock_t socket);
NBIO_EXPORT(int) nbio_setopt(int socket, nbio_option opt, ...);
extern int nbio_get_flags(int socket);
/* support tipc_setopt() */
extern plsocket_ptr
nbio_to_plsocket(nbio_sock_t socket);
extern SOCKET plsocket_handle(plsocket_ptr s);
/*******************************
* CONVERSION *
*******************************/
extern int nbio_get_sockaddr(term_t Address,
struct sockaddr_in *addr);
extern int nbio_get_ip4(term_t ip4, struct in_addr *ip);
#endif /*H_NONBLOCKIO_INCLUDED*/

View File

@ -1,60 +0,0 @@
:- module(pltotex,
[ pltotex/2,
pltotex/0
]).
:- use_module(library(doc_latex)).
:- use_module(library(main)).
:- use_module(library(error)).
:- use_module(library(apply)).
:- use_module(library(lists)).
pltotex(Lib, Options) :-
( file_name_extension(_, pl, Lib)
-> Spec = Lib
; atom_to_term(Lib, Spec, _)
),
absolute_file_name(Spec, File,
[ access(read),
file_type(prolog)
]),
tex_file(File, Out),
user:use_module(File), % we want the operators in user
doc_latex(File, Out,
[ stand_alone(false)
| Options
]).
tex_file(File, TeXFile) :-
file_base_name(File, Local),
file_name_extension(Base0, _, Local),
strip(Base0, 0'_, Base),
file_name_extension(Base, tex, TeXFile).
strip(In, Code, Out) :-
atom_codes(In, Codes0),
delete(Codes0, Code, Codes),
atom_codes(Out, Codes).
%% pltotex
%
% Usage: pl -q -s pltotex.pl -g pltotex -- file ...
pltotex :-
main.
main(Argv) :-
partition(is_option, Argv, OptArgs, Files),
maplist(to_option, OptArgs, Options),
maplist(process_file(Options), Files).
is_option(Arg) :-
sub_atom(Arg, 0, _, _, --).
to_option('--section', section_level(section)).
to_option('--subsection', section_level(subsection)).
to_option('--subsubsection', section_level(subsubsection)).
process_file(Options, File) :-
pltotex(File, Options).

File diff suppressed because it is too large Load Diff

View File

@ -1,341 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemak@uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 2008-2009, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(process,
[ process_create/3, % +Exe, +Args, +Options
process_wait/2, % +PID, -Status
process_wait/3, % +PID, -Status, +Options
process_id/1, % -PID
process_id/2, % +Process, -PID
is_process/1, % +PID
process_release/1, % +PID
process_kill/1, % +PID
process_kill/2 % +PID, -Signal
]).
:- use_module(library(shlib)).
:- use_module(library(error)).
:- use_module(library(lists)).
:- use_module(library(option)).
:- use_foreign_library(foreign(process)).
/** <module> Create processes and redirect I/O
The module library(process) implements interaction with child processes
and unifies older interfaces such as shell/[1,2], open(pipe(command),
...) etc. This library is modelled after SICStus 4.
The main interface is formed by process_create/3. If the process id is
requested the process must be waited for using process_wait/2. Otherwise
the process resources are reclaimed automatically.
In addition to the predicates, this module defines a file search path
(see user:file_search_path/2 and absolute_file_name/3) named =path= that
locates files on the system's search path for executables. E.g. the
following finds the executable for =ls=:
==
?- absolute_file_name(path(ls), Path, [access(execute)]).
==
*|Incompatibilities and current limitations|*
* Where SICStus distinguishes between an internal process id and
the OS process id, this implements does not make this distinction.
This implies that is_process/1 is incomplete and unreliable.
* SICStus only supports ISO 8859-1 (latin-1). This implementation
supports arbitrary OS multibyte interaction using the default
locale.
* It is unclear what the detached(true) option is supposed to do. Disable
signals in the child? Use setsid() to detach from the session? The
current implementation uses setsid()
* An extra option env([Name=Value, ...]) is added to
process_create/3.
@tbd Implement detached option in process_create/3
@compat SICStus 4
*/
/*******************************
* PATH HANDLING *
*******************************/
:- multifile
user:file_search_path/2.
:- dynamic
user:file_search_path/2.
user:file_search_path(path, Dir) :-
getenv('PATH', Path),
( current_prolog_flag(windows, true)
-> atomic_list_concat(Dirs, (;), Path)
; atomic_list_concat(Dirs, :, Path)
),
member(Dir, Dirs).
%% process_create(+Exe, +Args:list, +Options) is det.
%
% Create a new process running the file Exe and using arguments
% from the given list. Exe is a file specification as handed to
% absolute_file_name/3. Typically one use the =path= file alias to
% specify an executable file on the current PATH. Args is a list
% of arguments that are handed to the new process. On Unix
% systems, each element in the list becomes a seperate argument in
% the new process. In Windows, the arguments are simply
% concatenated to form the commandline. Each argument itself is
% either a primitive or a list of primitives. A primitive is
% either atomic or a term file(Spec). Using file(Spec), the system
% inserts a filename using the OS filename conventions which is
% properly quoted if needed.
%
% Options:
%
% * stdin(Spec)
% * stdout(Spec)
% * stderr(Spec)
% Bind the standard streams of the new process. Spec is one of
% the terms below. If pipe(Pipe) is used, the Prolog stream is
% a stream in text-mode using the encoding of the default
% locale. The encoding can be changed using set_stream/2.
%
% * std
% Just share with the Prolog I/O streams
% * null
% Bind to a _null_ stream. Reading from such a stream
% returns end-of-file, writing produces no output
% * pipe(-Stream)
% Attach input and/or output to a Prolog stream.
%
% * cwd(+Directory)
% Run the new process in Directory. Directory can be a
% compound specification, which is converted using
% absolute_file_name/3.
% * env(+List)
% Specify the environment for the new process. List is
% a list of Name=Value terms. Note that the current
% implementation does not pass any environment variables.
% If unspecified, the environment is inherited from the
% Prolog process.
% * process(-PID)
% Unify PID with the process id of the created process.
% * detached(+Bool)
% In Unix: If =true=, detach the process from the terminal
% Currently mapped to setsid();
% In Windows: If =true=, detach the process from the current
% job via the CREATE_BREAKAWAY_FROM_JOB flag. In Vista and beyond,
% processes launched from the shell directly have the 'compatibility
% assistant' attached to them automatically unless they have a UAC
% manifest embedded in them. This means that you will get a
% permission denied error if you try and assign the newly-created
% PID to a job you create yourself.
% * window(+Bool)
% If =true=, create a window for the process (Windows only)
%
% If the user specifies the process(-PID) option, he *must* call
% process_wait/2 to reclaim the process. Without this option, the
% system will wait for completion of the process after the last
% pipe stream is closed.
%
% If the process is not waited for, it must succeed with status 0.
% If not, an process_error is raised.
%
% *|Windows notes|*
%
% On Windows this call is an interface to the CreateProcess() API.
% The commandline consists of the basename of Exe and the
% arguments formed from Args. Arguments are separated by a single
% space. If all characters satisfy iswalnum() it is unquoted. If
% the argument contains a double-quote it is quoted using single
% quotes. If both single and double quotes appear a domain_error
% is raised, otherwise double-quote are used.
%
% The CreateProcess() API has many options. Currently only the
% =CREATE_NO_WINDOW= options is supported through the
% window(+Bool) option. If omitted, the default is to use this
% option if the application has no console. Future versions are
% likely to support more window specific options and replace
% win_exec/2.
%
% *Examples*
%
% First, a very simple example that behaves the same as
% =|shell('ls -l')|=, except for error handling:
%
% ==
% ?- process_create(path(ls), ['-l'], []).
% ==
%
% @tbd The detach options is a no-op.
% @error process_error(Exe, Status) where Status is one of
% exit(Code) or killed(Signal). Raised if the process
% does not exit with status 0.
process_create(Exe, Args, Options) :-
exe_options(ExeOptions),
absolute_file_name(Exe, PlProg, ExeOptions),
must_be(list, Args),
maplist(map_arg, Args, Av),
prolog_to_os_filename(PlProg, Prog),
Term =.. [Prog|Av],
expand_cwd_option(Options, Options1),
process_create(Term, Options1).
exe_options(Options) :-
current_prolog_flag(windows, true), !,
Options = [ extensions(['',exe,com]), access(read) ].
exe_options(Options) :-
Options = [ access(execute) ].
expand_cwd_option(Options0, Options) :-
select_option(cwd(Spec), Options0, Options1), !,
( compound(Spec)
-> absolute_file_name(Spec, PlDir, [file_type(directory), access(read)]),
prolog_to_os_filename(PlDir, Dir),
Options = [cwd(Dir)|Options1]
; exists_directory(Spec)
-> Options = Options0
; existence_error(directory, Spec)
).
expand_cwd_option(Options, Options).
%% map_arg(+ArgIn, -Arg) is det.
%
% Map an individual argument. Primitives are either file(Spec) or
% an atomic value (atom, string, number). If ArgIn is a non-empty
% list, all elements are converted and the results are
% concatenated.
map_arg([], []) :- !.
map_arg(List, Arg) :-
is_list(List), !,
maplist(map_arg_prim, List, Prims),
atomic_list_concat(Prims, Arg).
map_arg(Prim, Arg) :-
map_arg_prim(Prim, Arg).
map_arg_prim(file(Spec), File) :- !,
( compound(Spec)
-> absolute_file_name(Spec, PlFile)
; PlFile = Spec
),
prolog_to_os_filename(PlFile, File).
map_arg_prim(Arg, Arg).
%% process_id(-PID) is det.
%
% True if PID is the process id of the running Prolog process.
%
% @deprecated Use current_prolog_flag(pid, PID)
process_id(PID) :-
current_prolog_flag(pid, PID).
%% process_id(+Process, -PID) is det.
%
% PID is the process id of Process. Given that they are united in
% SWI-Prolog, this is a simple unify.
process_id(PID, PID).
%% is_process(+PID) is semidet.
%
% True if PID might be a process. Succeeds for any positive
% integer.
is_process(PID) :-
integer(PID),
PID > 0.
%% process_release(+PID)
%
% Release process handle. In this implementation this is the same
% as process_wait(PID, _).
process_release(PID) :-
process_wait(PID, _).
%% process_wait(+PID, -Status) is det.
%% process_wait(+PID, -Status, +Options) is det.
%
% True if PID completed with Status. This call normally blocks
% until the process is finished. Options:
%
% * timeout(+Timeout)
% Default: =infinite=. If this option is a number, the
% waits for a maximum of Timeout seconds and unifies Status
% with =timeout= if the process does not terminate within
% Timeout. In this case PID is _not_ invalidated. On Unix
% systems only timeout 0 and =infinite= are supported. A
% 0-value can be used to poll the status of the process.
%
% * release(+Bool)
% Do/do not release the process. We do not support this flag
% and a domain_error is raised if release(false) is provided.
process_wait(PID, Status) :-
process_wait(PID, Status, []).
%% process_kill(+PID) is det.
%% process_kill(+PID, +Signal) is det.
%
% Send signal to process PID. Default is =term=. Signal is an
% integer, Unix signal name (e.g. =SIGSTOP=) or the more Prolog
% friendly variation one gets after removing =SIG= and downcase
% the result: =stop=. On Windows systems, Signal is ignored and
% the process is terminated using the TerminateProcess() API. On
% Windows systems PID must be obtained from process_create/3,
% while any PID is allowed on Unix systems.
%
% @compat SICStus does not accept the prolog friendly version. We
% choose to do so for compatibility with on_signal/3.
process_kill(PID) :-
process_kill(PID, term).
/*******************************
* MESSAGES *
*******************************/
:- multifile
prolog:error_message/3.
prolog:error_message(process_error(File, exit(Status))) -->
[ 'Process "~w": exit status: ~w'-[File, Status] ].
prolog:error_message(process_error(File, killed(Signal))) -->
[ 'Process "~w": killed by signal ~w'-[File, Signal] ].

View File

@ -1,123 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker & Steve Prior
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2007, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(prolog_server,
[ prolog_server/2 % +Port, +Options
]).
:- use_module(library(socket)).
%% prolog_server(?Port, +Options)
%
% Create a TCP/IP based server on the given Port, so you can
% telnet into Prolog and run an interactive session. This library
% is intended to provide access for debugging and management of
% embedded servers.
%
% Currently defined options are:
%
% * allow(IP)
% Allow access from IP, a term of the format ip(A,B,C,D).
% Multiple of such terms can exist and access is granted
% if the peer IP address unifies to one of them. If no
% allow option is provided access is only granted from
% ip(127,0,0,1) (localhost).
%
% For example:
%
% ==
% ?- prolog_server(4000, []).
%
% % telnet localhost 4000
% Welcome to the SWI-Prolog server on thread 3
%
% 1 ?-
% ==
%
% @bug As the connection does not involve a terminal, command history
% and completion are not provided. Neither are interrupts
% (Control-C). To terminate the Prolog shell one must enter the
% command "end_of_file."
prolog_server(Port, Options) :-
tcp_socket(ServerSocket),
tcp_setopt(ServerSocket, reuseaddr),
tcp_bind(ServerSocket, Port),
tcp_listen(ServerSocket, 5),
thread_create(server_loop(ServerSocket, Options), _,
[ alias(prolog_server)
]).
server_loop(ServerSocket, Options) :-
tcp_accept(ServerSocket, Slave, Peer),
tcp_open_socket(Slave, InStream, OutStream),
tcp_host_to_address(Host, Peer),
atom_concat('client@', Host, Alias),
thread_create(service_client(InStream, OutStream, Peer, Options),
_,
[ alias(Alias)
]),
server_loop(ServerSocket, Options).
service_client(InStream, OutStream, Peer, Options) :-
allow(Peer, Options), !,
thread_self(Id),
set_prolog_IO(InStream, OutStream, OutStream),
set_stream(InStream, tty(true)),
format(user_error,
'Welcome to the SWI-Prolog server on thread ~w~n~n',
[Id]),
call_cleanup(run_prolog,
( close(InStream),
close(OutStream),
thread_detach(Id))).
service_client(InStream, OutStream, _, _):-
thread_self(Id),
format(OutStream, 'Go away!!~n', []),
close(InStream),
close(OutStream),
thread_detach(Id).
run_prolog :-
catch(prolog, E,
( print_message(error, E),
% E = error(_, _),
run_prolog)).
allow(Peer, Options) :-
( member(allow(Allow), Options)
*-> Peer = Allow,
!
; Peer = ip(127,0,0,1)
).

View File

@ -1,155 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: L.Damas, V.S.Costa, Jan Wielemaker
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): Universidade do Porto, University of Amsterdam
Original code create for YAP under Artistic license. As this
license is compatible (but less restrictive than) the SWI-Prolog
license we keep the Artistic license.
*/
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: random.c *
* Last rev: *
* mods: *
* comments: Random number generation *
* *
*************************************************************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Ported to SWI-Prolog by Jan Wielemaker
To compile:
plld -o random -shared -fpic random.c
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <SWI-Prolog.h>
#include <math.h>
#include <limits.h>
static functor_t FUNCTOR_rand3;
static short a1 = 27314, b1 = 9213, c1 = 17773;
static int
type_error(term_t actual, const char *expected)
{ term_t ex;
if ( (ex = PL_new_term_ref()) &&
PL_unify_term(ex,
PL_FUNCTOR_CHARS, "error", 2,
PL_FUNCTOR_CHARS, "type_error", 2,
PL_CHARS, expected,
PL_TERM, actual,
PL_VARIABLE) )
return PL_raise_exception(ex);
return FALSE;
}
static int
domain_error(term_t actual, const char *expected)
{ term_t ex;
if ( (ex = PL_new_term_ref()) &&
PL_unify_term(ex,
PL_FUNCTOR_CHARS, "error", 2,
PL_FUNCTOR_CHARS, "domain_error", 2,
PL_CHARS, expected,
PL_TERM, actual,
PL_VARIABLE) )
return PL_raise_exception(ex);
return FALSE;
}
static int
get_short_ex(term_t t, short *p)
{ long v;
if ( !PL_get_long(t, &v) )
return type_error(t, "integer");
if ( v < SHRT_MIN || v > SHRT_MAX )
return domain_error(t, "short integer");
*p = (short)v;
return TRUE;
}
static int
get_short_arg_ex(int a, term_t state, short *p)
{ term_t arg = PL_new_term_ref();
_PL_get_arg(a, state, arg);
return get_short_ex(arg, p);
}
static foreign_t
p_random(term_t rnd)
{
double fli;
long int t1, t2, t3;
t1 = (a1 * 171) % 30269;
t2 = (b1 * 172) % 30307;
t3 = (c1 * 170) % 30323;
fli = (t1/30269.0) + (t2/30307.0) + (t3/30323.0);
a1 = (short)t1;
b1 = (short)t2;
c1 = (short)t3;
return PL_unify_float(rnd, fli-(int)(fli));
}
static foreign_t
p_setrand(term_t state)
{ if ( !PL_is_functor(state, FUNCTOR_rand3) )
return type_error(state, "rand_state");
if ( !get_short_arg_ex(1, state, &a1) ||
!get_short_arg_ex(2, state, &b1) ||
!get_short_arg_ex(3, state, &c1) )
return FALSE;
return TRUE;
}
static foreign_t
p_getrand(term_t state)
{ return PL_unify_term(state,
PL_FUNCTOR, FUNCTOR_rand3,
PL_INTEGER, a1,
PL_INTEGER, b1,
PL_INTEGER, c1);
}
install_t
install_random()
{ FUNCTOR_rand3 = PL_new_functor(PL_new_atom("rand"), 3);
PL_register_foreign("random", 1, p_random, 0);
PL_register_foreign("setrand", 1, p_setrand, 0);
PL_register_foreign("getrand", 1, p_getrand, 0);
}

View File

@ -1,163 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: R.A. O'Keefe, V.S. Costa, L. Damas, Jan Wielemaker
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): Universidade do Porto, University of Amsterdam
*/
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: random.yap *
* Last rev: 5/12/99 *
* mods: *
* comments: Random operations *
* *
*************************************************************************/
% original code from RA O'Keefe.
% This is algorithm AS 183 from Applied Statistics. I also have a C
% version. It is really very good. It is straightforward to make a
% version which yields 15-bit random integers using only integer
% arithmetic.
:- module(random,
[ random/1, % -float
random/3, % +Low, +High, -Random
randseq/3, % +Size, +Max, -Set
randset/3, % +Size, +Max, -List
getrand/1, % -State
setrand/1 % +State
]).
:- use_module(library(pairs)).
:- use_foreign_library(foreign(random)).
/** <module> Random numbers
Random number generator developed as part of the DEC10 library. The
algorithm is based on AS 183 from Applied Statistics. Originally
implemented ib Prolog by Richard O'Keeke. The SWI-Prolog versions is a
translation of a C-version for YAP based on the orginal source.
@copyright DEC10 version: Public domain, YAP: Artistic
@author R.A. O'Keefe, V.S. Costa, L. Damas, Jan Wielemaker
@see Built-in function random/1: A is random(10)
*/
/*******************************
* C PRIMITIVES *
*******************************/
%% random(-R:float) is det.
%
% Binds R to a new random number in [0.0,1.0).
%
% @see setrand/1, getrand/1.
%% setrand(+State:rand(A,B,C)) is det.
%% getrand(+State:rand(A,B,C)) is det.
%
% Query/set the state of the random library. A, B and C are
% integers in the range 1..30,000. The initial state is predefined
% and can be extracted using getrand/1:
%
% ==
% ?- getrand(X).
% X = rand(27314, 9213, 17773).
% ==
%
% @see random/1.
/*******************************
* PROLOG *
*******************************/
%% random(+L:int, +U:int, -R:int) is det.
%% random(+L:float, +U:float, -R:float) is det.
%
% Binds R to a random number in [L,U). If L and U are both
% integers, R is an integer, Otherwise, R is a float. Note that U
% will *never* be generated.
%
% @bug The state is only 48-bits. This is insufficient for
% generating uniformely distributed integers in a very
% large domain.
random(L, U, R) :-
integer(L), integer(U), !,
random(X),
R is L+floor((U-L)*X).
random(L, U, R) :-
number(L), number(U), !,
random(X),
R is L+((U-L)*X).
%% randset(+K:int, +N:int, -S:list(int)) is det.
%
% S is a sorted list of K integers in the range 1..N.
%
% @see randseq/3.
randset(K, N, S) :-
K >= 0,
K =< N,
randset(K, N, [], S).
randset(0, _, S, S) :- !.
randset(K, N, Si, So) :-
random(X),
X * N < K, !,
J is K-1,
M is N-1,
randset(J, M, [N|Si], So).
randset(K, N, Si, So) :-
M is N-1,
randset(K, M, Si, So).
%% randseq(+K:int, +N:int, -S:list(int)) is det.
%
% S is a list of K integers in the range 1..N. The order is
% random.
%
% @see randset/3.
randseq(K, N, S) :-
randseq(K, N, L, []),
keysort(L, R),
pairs_values(R, S).
randseq(0, _, S, S) :- !.
randseq(K, N, [Y-N|Si], So) :-
random(X),
X * N < K, !,
random(Y),
J is K-1,
M is N-1,
randseq(J, M, Si, So).
randseq(K, N, Si, So) :-
M is N-1,
randseq(K, M, Si, So).

View File

@ -1,170 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2005, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
#include <SWI-Stream.h>
#include <SWI-Prolog.h>
#define BUFSIZE 256
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This library is dynamically picked up by library(readline), which falls
back to a pure Prolog implementation if this library cannot be found.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static atom_t ATOM_end_of_file;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read_line_to_codes(+Stream, -Codes, ?Tail)
Read a line, upto the next '\n' from Stream. Normally the line is
returned as a difference list Codes-Tail. If EOF is encountered, the
Codes list is closed and Tail is unified with [].
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static foreign_t
read_line_to_codes3(term_t stream, term_t codes, term_t tail)
{ wchar_t buf[BUFSIZE];
wchar_t *o = buf, *e = &buf[BUFSIZE];
IOSTREAM *s;
term_t cl = PL_copy_term_ref(codes);
int rc = FALSE;
if ( !PL_get_stream_handle(stream, &s) )
return FALSE;
for(;;)
{ int c = Sgetcode(s);
if ( c == EOF )
{ if ( (s->flags & SIO_FERR) )
goto out; /* error */
if ( tail == 0 && o == buf )
{ rc = PL_unify_atom(codes, ATOM_end_of_file);
goto out;
}
if ( PL_unify_wchars(cl, PL_CODE_LIST, o-buf, buf) &&
(tail == 0 || PL_unify_nil(tail)) )
rc = TRUE;
goto out;
}
if ( o == e )
{ if ( !PL_unify_wchars_diff(cl, cl, PL_CODE_LIST, o-buf, buf) )
goto out;
o = buf;
}
*o++ = c;
if ( c == '\n' )
{ if ( tail )
{ if ( PL_unify_wchars_diff(cl, cl, PL_CODE_LIST, o-buf, buf) &&
PL_unify(cl, tail) )
rc = TRUE;
} else
{ o--;
if ( o>buf && o[-1] == '\r' )
o--;
rc = PL_unify_wchars(cl, PL_CODE_LIST, o-buf, buf);
}
goto out;
}
}
out:
PL_release_stream(s);
return rc;
}
static foreign_t
read_line_to_codes2(term_t stream, term_t codes)
{ return read_line_to_codes3(stream, codes, 0);
}
static foreign_t
read_stream_to_codes3(term_t stream, term_t codes, term_t tail)
{ wchar_t buf[BUFSIZE];
wchar_t *o = buf, *e = &buf[BUFSIZE];
IOSTREAM *s;
term_t cl = PL_copy_term_ref(codes);
if ( !PL_get_stream_handle(stream, &s) )
return FALSE;
for(;;)
{ int c = Sgetcode(s);
if ( c == EOF )
{ if ( !PL_release_stream(s) )
return FALSE; /* error */
if ( tail )
{ if ( PL_unify_wchars_diff(cl, cl, PL_CODE_LIST, o-buf, buf) &&
PL_unify(cl, tail) )
return TRUE;
return FALSE;
} else
{ return PL_unify_wchars(cl, PL_CODE_LIST, o-buf, buf);
}
}
if ( o == e )
{ if ( !PL_unify_wchars_diff(cl, cl, PL_CODE_LIST, o-buf, buf) )
{ PL_release_stream(s);
return FALSE;
}
o = buf;
}
*o++ = c;
}
}
static foreign_t
read_stream_to_codes2(term_t stream, term_t codes)
{ return read_stream_to_codes3(stream, codes, 0);
}
install_t
install_readutil()
{ ATOM_end_of_file = PL_new_atom("end_of_file");
PL_register_foreign("read_line_to_codes", 3, read_line_to_codes3, 0);
PL_register_foreign("read_line_to_codes", 2, read_line_to_codes2, 0);
PL_register_foreign("read_stream_to_codes", 3, read_stream_to_codes3, 0);
PL_register_foreign("read_stream_to_codes", 2, read_stream_to_codes2, 0);
}

View File

@ -1,128 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <SWI-Prolog.h>
#include "clib.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Provide an interface to the Unix system resources (getrlimit()/setrlimit()).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if !defined(RLIMIT_NOFILE) && defined(RLIMIT_OFILE)
#define RLIMIT_NOFILE RLIMIT_OFILE
#endif
foreign_t
pl_rlimit(term_t what, term_t old, term_t new)
{ char *s;
int resource;
struct rlimit rlim;
if ( PL_get_atom_chars(what, &s) )
{ if ( strcmp(s, "cpu") == 0 )
resource = RLIMIT_CPU;
else if ( strcmp(s, "fsize") == 0 )
resource = RLIMIT_FSIZE;
else if ( strcmp(s, "data") == 0 )
resource = RLIMIT_DATA;
else if ( strcmp(s, "stack") == 0 )
resource = RLIMIT_STACK;
else if ( strcmp(s, "core") == 0 )
resource = RLIMIT_CORE;
#ifdef RLIMIT_RSS
else if ( strcmp(s, "rss") == 0 )
resource = RLIMIT_RSS;
#endif
#ifdef RLIMIT_MEMLOCK
else if ( strcmp(s, "memlock") == 0 )
resource = RLIMIT_MEMLOCK;
#endif
#ifdef RLIMIT_NPROC
else if ( strcmp(s, "nproc") == 0 )
resource = RLIMIT_NPROC;
#endif
#ifdef RLIMIT_NOFILE
else if ( strcmp(s, "nofile") == 0 )
resource = RLIMIT_NOFILE;
#endif
else
return pl_error("rlimit", 3, NULL, ERR_DOMAIN,
what, "resource");
} else
return pl_error("rlimit", 3, NULL, ERR_TYPE,
what, "atom");
if ( getrlimit(resource, &rlim) == 0 )
{ int rval;
if ( rlim.rlim_cur == RLIM_INFINITY )
rval = PL_unify_atom_chars(old, "unlimited");
else
rval = PL_unify_int64(old, rlim.rlim_cur);
if ( rval )
{ int64_t n;
if ( PL_get_int64(new, &n) )
{
set:
if ( rlim.rlim_cur != (unsigned long) n )
{ rlim.rlim_cur = n;
if ( !setrlimit(resource, &rlim) == 0 )
return pl_error("rlimit", 3, NULL, ERR_ERRNO, errno, "set", "resource_limit", what);
}
return TRUE;
} else if ( PL_get_atom_chars(new, &s) && strcmp(s, "unlimited") == 0 )
{ n = RLIM_INFINITY;
goto set;
} else
return pl_error("rlimit", 3, NULL, ERR_TYPE,
new, "integer_or_unlimited");
} else
return FALSE;
} else
return pl_error("rlimit", 3, NULL, ERR_ERRNO, errno, "get", "resource_limit", what);
}
install_t
install_rlimit()
{ PL_register_foreign("rlimit", 3, pl_rlimit, 0);
}

View File

@ -1,51 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(clib_rlimit,
[ rlimit/3 % +Limit, -Old, +New
]).
% rlimit(+Limit, -Old, +New)
%
% Query and set POSIX resource limits. Provided resources are:
%
% cpu CPU time (seconds)
% fsize file-size (bytes)
% data size of data-segment (bytes)
% stack size of C-stack (bytes)
% core size of a core-dump (bytes)
% rss resident set size
% memlock locked-in-memory address space
% nproc number of processes
% nofile number of open files
:- use_foreign_library(foreign(rlimit)).

View File

@ -1,75 +0,0 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: wielemak@science.uva.nl
WWW: http://www.swi-prolog.org
Copyright (C): 1985-2007, University of Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(crypto_hash,
[ sha_hash/3, % +Data, -Hash, +Options
sha_new_ctx/2, % -NewContext, +Options
sha_hash_ctx/4, % +OldCtx, +Data, -NewCtx, -Hash
hmac_sha/4 % +Key, +Data, -Hash, +Options
]).
:- use_module(library(shlib)).
:- use_foreign_library(foreign(sha4pl)).
%% sha_hash(+Data, -Hash, +Options) is det
%
% Hash is the SHA hash of Data, The conversion is controlled
% by Options:
%
% * algorithm(+Algorithm)
% One of =sha1= (default), =sha224=, =sha256=, =sha384= or
% =sha512=
%
% @param Data is either an atom, string or code-list
% @param Hash is a packed string
%% sha_new_ctx(-NewContext, +Options) is det
%
% NewContext is unified with the empty SHA computation context
% (which includes the Options.) It could later be passed to
% sha_hash_ctx/4.
%
% For Options, see sha_hash/3.
%% sha_hash_ctx(+OldContext, +Data, -NewContext, -Hash) is det
%
% Hash is the SHA hash of Data. NewContext is the new SHA
% computation context, while OldContext is the old. OldContext
% may be produced by a prior invocation of either sha_new_ctx/3 or
% sha_hash_ctx/4 itself.
%
% This predicate allows a SHA function to be computed in chunks,
% which may be important while working with Metalink (RFC 5854),
% BitTorrent or similar technologies, or simply with big files.
%% hmac_sha(+Key, +Data, -Hash, +Options) is det
%
% For Options, see sha_hash/3.

View File

@ -1 +0,0 @@
Original source: http://fp.gladman.plus.com/cryptography_technology/sha/index.htm

View File

@ -1,142 +0,0 @@
/*
---------------------------------------------------------------------------
Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue 20/10/2006
*/
#ifndef BRG_ENDIAN_H
#define BRG_ENDIAN_H
#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
/* Include files where endian defines and byteswap functions may reside */
#if defined(__sun__)
# include <sys/isa_defs.h>
#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
# include <sys/endian.h>
#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ )
# include <machine/endian.h>
#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
# if !defined( __MINGW32__ )
# include <endian.h>
# if !defined( __BEOS__ )
# include <byteswap.h>
# endif
# endif
#endif
/* Now attempt to set the define for platform byte order using any */
/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */
/* seem to encompass most endian symbol definitions */
#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
# endif
#elif defined( BIG_ENDIAN )
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
#elif defined( LITTLE_ENDIAN )
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
# endif
#elif defined( _BIG_ENDIAN )
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
#elif defined( _LITTLE_ENDIAN )
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
# endif
#elif defined( __BIG_ENDIAN )
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
#elif defined( __LITTLE_ENDIAN )
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
# endif
#elif defined( __BIG_ENDIAN__ )
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
#elif defined( __LITTLE_ENDIAN__ )
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#endif
/* if the platform byte order could not be determined, then try to */
/* set this define using common machine defines */
#if !defined(PLATFORM_BYTE_ORDER)
#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \
defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \
defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \
defined( vax ) || defined( vms ) || defined( VMS ) || \
defined( __VMS ) || defined( _M_X64 )
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \
defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \
defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \
defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \
defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \
defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \
defined( THINK_C ) || defined( __VMCMS__ )
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
/*** JW: __WINDOWS__ for compiling SWI-Prolog. None of the above appears to be
defined, despite the VS2005 and Platform SDK claiming _M_X64 must be
defined
***/
#elif __WINDOWS__ /* **** EDIT HERE IF NECESSARY **** */
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
#elif 0 /* **** EDIT HERE IF NECESSARY **** */
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
#else
# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order
#endif
#endif
#endif

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