use external module for clib
This commit is contained in:
parent
6b5046bb8c
commit
123cf5af84
@ -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.
|
@ -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)
|
@ -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
|
||||
|
||||
|
@ -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.
|
@ -1 +0,0 @@
|
||||
1.2.1
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
@ -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
@ -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*/
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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).
|
@ -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)
|
||||
).
|
@ -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).
|
||||
|
@ -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).
|
||||
|
@ -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:
|
@ -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;
|
||||
}
|
||||
|
@ -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*/
|
@ -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);
|
||||
}
|
@ -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).
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
@ -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
|
@ -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.
|
@ -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.
|
@ -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--
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
@ -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)
|
||||
|
1044
packages/clib/maildrop/rfc2045/aclocal.m4
vendored
1044
packages/clib/maildrop/rfc2045/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
@ -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
@ -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>
|
@ -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);
|
||||
}
|
@ -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
@ -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
|
@ -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 <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 <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>
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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()
|
||||
{
|
||||
}
|
@ -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));
|
||||
}
|
@ -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);
|
||||
}
|
@ -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"
|
@ -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);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "rfc2045.h"
|
||||
|
||||
void rfc2045_enomem()
|
||||
{
|
||||
rfc2045_error("Out of memory.");
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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()
|
||||
{
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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)
|
||||
|
1044
packages/clib/maildrop/rfc822/aclocal.m4
vendored
1044
packages/clib/maildrop/rfc822/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
@ -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)
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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)>
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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 <rfc822.h></code></p>
|
||||
|
||||
<p><code>#include <rfc2047.h></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 <jsmith@example.com></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 <tjones@example.com></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 <john@example.com>". 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>'<', '>', '@', 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>
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -1 +0,0 @@
|
||||
timestamp
|
@ -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);
|
||||
}
|
@ -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"
|
@ -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));
|
||||
}
|
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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)).
|
@ -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);
|
||||
}
|
@ -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)
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
@ -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
@ -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*/
|
@ -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
@ -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] ].
|
@ -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)
|
||||
).
|
@ -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);
|
||||
}
|
||||
|
@ -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).
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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)).
|
||||
|
@ -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.
|
@ -1 +0,0 @@
|
||||
Original source: http://fp.gladman.plus.com/cryptography_technology/sha/index.htm
|
@ -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
Reference in New Issue
Block a user