commit 50de79fe7f9e194b5a6bdd3a63fb3bdb455588a8
Author: parazyd <parazyd@dyne.org>
Date: Thu, 15 Sep 2016 01:44:49 +0200
initial sources import
Diffstat:
A | BUILD.Win32 | | | 30 | ++++++++++++++++++++++++++++++ |
A | COPYRIGHT | | | 134 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | HISTORY | | | 502 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Install | | | 1403 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | README | | | 191 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/Makefile.deps | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/Makefile.in | | | 83 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/buffers.c | | | 816 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/chain.c | | | 384 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/chain1.c | | | 301 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/chain2.c | | | 685 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/compress.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/config.h | | | 403 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/crypto.c | | | 492 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/crypto.h | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/dllmain.c | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | Src/dummy.c | | | 16 | ++++++++++++++++ |
A | Src/keymgt.c | | | 434 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mail.c | | | 898 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/maildir.c | | | 323 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/main.c | | | 820 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menu.c | | | 1003 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menu.h | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menunym.c | | | 472 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menusend.c | | | 556 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menustats.c | | | 445 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/menuutil.c | | | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mime.c | | | 814 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mix.c | | | 1262 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mix.h | | | 917 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mix3.h | | | 443 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mixlib.def | | | 121 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/mpgp.c | | | 264 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/nym.c | | | 669 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/parsedate.y | | | 879 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgp.c | | | 494 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgp.h | | | 189 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpcreat.c | | | 848 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpdata.c | | | 1539 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpdb.c | | | 583 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pgpget.c | | | 870 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/pool.c | | | 981 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/random.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rem.c | | | 709 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rem1.c | | | 599 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rem2.c | | | 486 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/remailer.c | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | Src/rfc822.c | | | 585 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/rndseed.c | | | 157 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/service.c | | | 331 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/stats.c | | | 442 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/tests/test-parse_yearmonthday.c | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/util.c | | | 704 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Src/version.h | | | 1 | + |
A | THANKS | | | 102 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | TODO | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/abuse.txt.in | | | 99 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/adminkey.txt | | | 1 | + |
A | conf/blocked.txt.in | | | 20 | ++++++++++++++++++++ |
A | conf/dest.alw | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | conf/dest.blk | | | 2 | ++ |
A | conf/end.hlp | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | conf/header.blk | | | 22 | ++++++++++++++++++++++ |
A | conf/intro.hlp | | | 15 | +++++++++++++++ |
A | conf/mix.cfg | | | 14 | ++++++++++++++ |
A | conf/mix.cfg.ex | | | 192 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/mix.hlp | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/mlist.txt | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/news.hlp | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pgp.hlp | | | 143 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pgponly.hlp | | | 144 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pubring.asc | | | 544 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/pubring.mix | | | 384 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/rab.blk | | | 0 | |
A | conf/reply.txt.in | | | 32 | ++++++++++++++++++++++++++++++++ |
A | conf/rlist.txt | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/type1.hlp | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | conf/usage.txt.in | | | 24 | ++++++++++++++++++++++++ |
A | idea.txt | | | 34 | ++++++++++++++++++++++++++++++++++ |
A | mixmaster.1 | | | 1136 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | mpgp.1 | | | 121 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/installer/mixinstall.nsi | | | 70 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/mix.sln | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/mix.vcproj | | | 193 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/mixlib.vcproj | | | 459 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/pcre.vcproj | | | 117 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/pcre_chartables.vcproj | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/pdcurses.vcproj | | | 607 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | win32/zlib.vcproj | | | 217 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
89 files changed, 31462 insertions(+), 0 deletions(-)
diff --git a/BUILD.Win32 b/BUILD.Win32
@@ -0,0 +1,30 @@
+Mixmaster on Windows is known to build with Microsoft Visual Studio .NET
+2003 Professional.
+
+You will need openssl, zlib, pcre, and pdcurses.
+
+First, build openssl as described in the openssl documentation. Place
+the entire build directory in Src/openssl.
+
+zlib, pcre, and pdcurses sources are assumed to be in Src/zlib-1.1.4,
+Src/pcre-2.08, and Src/pdcurses respectively.
+
+Open the mixmaster project win32/mix.sln, and build the mix solution.
+You should find the results in win32/release.
+
+
+References:
+ - http://www.openssl.org/
+ - http://pdcurses.sourceforge.net/
+
+--
+Peter Palfrader, Sat, 1 May 2004 20:31:48 +0200
+
+
+[Note to users of Mixmaster 3.0rc1 and earlier: mix.cfg.txt and pop3.cfg
+are now named mix.ini and pop3.ini, respectively, on WIN32. You will
+need to manually rename your custom config files, if appropriate.]
+
+--
+Len Sassaman, Thu, 13 Sep 2007 14:56:37 +0200
+
diff --git a/COPYRIGHT b/COPYRIGHT
@@ -0,0 +1,134 @@
+Copyright (c) 1999-2000 Anonymizer Inc.
+Copyright (c) 2000-2002 Ulf Moeller
+Copyright (c) 2001-2002 Janis Jagars
+Copyright (c) 2001-2007 Peter Palfrader
+Copyright (c) 2001-2008 Len Sassaman
+Copyright (c) 2004-2008 Colin Tuckley
+Copyright (c) 2007-2008 Steve Crook
+
+
+MIXMASTER LICENSE AGREEMENT
+
+1. Grant of License.
+
+ Anonymizer Inc. grants you the following non-exclusive license for
+ the Mixmaster program and its associated documentation (the "Program"),
+ subject to all of the following terms and conditions:
+
+ a) You may use the Program, and copy and distribute verbatim copies
+ of the Program as you receive it, in any medium.
+
+ Local regulations may exist which limit your rights to distribute or
+ use cryptographic software. In certain jurisdictions, parts of this
+ software may be protected by patents. It is your responsibility to
+ obtain the appropriate licenses.
+
+ b) You may modify the Program or incorporate the Program or any
+ portion of it into other computer programs. You may copy and
+ distribute such modifications or work, provided that you:
+
+ (i) cause the modified Program to carry a prominent notice
+ stating that it has been modified, and cause the modified files
+ to carry notices stating that you changed the files and the
+ date of any change;
+
+ (ii) reproduce and include this Agreement, the copyright
+ notices and disclaimer of warranty on any copy; and
+
+ (iii) provide Anonymizer Inc. with a copy of the Source Code of
+ such modifications or work via electronic mail to the address
+ mixmaster@anonymizer.com, and grant Anonymizer Inc. a perpetual,
+ royalty-free license to use and distribute the modifications or
+ work in its products.
+
+ "Source Code" means the preferred form of a work for making
+ modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to
+ control compilation and installation of an executable.
+
+ c) Should Anonymizer Inc. be acquired by another entity, you:
+
+ (i) will grant to the acquiring entity the items in section
+ 1.b.(iii) in leiu of Anonymizer, Inc.;
+
+ d) Should Anonymizer Inc. cease to exist, and no aquiring entity be
+ available to accept Source Code modifications, you:
+
+ (i) will grant Lance Cottrell the items in section 1.b.(iii) in leiu
+ of Anonymizer, Inc.
+
+ (ii) should Mr. Cottrell be deceased, section 1.b.(iii) of this
+ license will be rendered null and void.
+
+ e) In the case that the electronic mail address mixmaster@anonymizer.com
+ ceases to accept electronic mail,
+
+ (i) submission of changes to the Mixmaster project at SourceForge
+ will be accceptable;
+
+ (ii) if Mixmaster development is no longer hosted by SourceForge,
+ submission of changes to any open source repository similar to
+ SourceForge, or
+
+ (iii) submission to the Internet news group alt.privacy.anon-server
+ will be acceptable.
+
+ f) Submission of changes is required as a "best effort". If it is not
+ possible for you to access any of the notification locations, a notation
+ in the modified code stating that the modifications should be submitted by
+ any capable parties who subsequently make use of the modified code will
+ be acceptable in lieu of code submission.
+
+2. Reservation of Rights.
+
+ No rights are granted to the Program except as expressly set forth
+ herein. You may not copy, modify, sublicense, or distribute the
+ Program except as expressly provided under this Agreement. Any
+ attempt otherwise to copy, modify, sublicense or distribute the
+ Program is void, and will automatically terminate your rights under
+ this Agreement.
+
+3. DISCLAIMER OF WARRANTY.
+
+ BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. THE
+ PROGRAM IS PROVIDED ON AN ``AS IS'' BASIS, WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
+ WARRANTIES THAT THE PROGRAM IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR
+ A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE
+ QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+ PROGRAM PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT ANONYMIZER INC. OR
+ ANY DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+ NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
+ WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF THE
+ PROGRAM IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+4. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL ANONYMIZER INC.
+ OR ANY DEVELOPER OR ANY OTHER CONTRIBUTOR OR ANY SUPPLIER OF ANY OF
+ SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER
+ INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK
+ STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+5. General.
+
+ This license represents the complete agreement concerning subject
+ matter hereof. If any provision of this Agreement is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This Agreement shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ The application of the United Nations Convention on Contracts for the
+ International Sale of Goods is expressly excluded. Any law or
+ regulation which provides that the language of a contract shall be
+ construed against the drafter shall not apply to this License.
diff --git a/HISTORY b/HISTORY
@@ -0,0 +1,502 @@
+ 1998/1999 2.9 written from scratch.
+
+1999-04-14 2.9beta0 public preview release.
+
+1999-05-17 2.9beta1 Bug fixes (remix, OpenPGP encryption, FreeBSD
+ name conflict); Win32 DLL.
+
+1999-05-18 2.9beta2 Install bug fixes. -N and -n options renamed.
+
+1999-05-19 2.9beta3 OpenSSL-related bug fix. Type 1 remailer fixes
+ (pointed out by <kev@drule.org>).
+
+1999-05-20 2.9beta4 Read and generate OpenPGP encrypted secret keys.
+
+1999-05-20 2.9beta5 The client sent messages if PGP encryption failed.
+
+1999-05-28 2.9beta6 Message-ID generation bug fixes. Contributed by:
+ Johannes Kroeger <hanne@squirrel.owl.de>.
+ Remix-To bug fix.
+
+1999-06-09 2.9beta7 More (minor) remailer and Install script fixes.
+
+1999-06-10 2.9beta8 Regular expression bug fix. Thanks to Johannes
+ and Kevin for help with debugging!
+
+1999-07-20 2.9beta9 Bug fixes (remailer, nym creation).
+
+1999-08-03 2.9beta10 Fix for buffer overrun error.
+ "Chain:" pseudo-header may contain the number of
+ copies like this: `Chain: *,*,*,*; copies=3'
+
+1999-09-09 2.9beta11 Support MIME attachments and OpenPGP/MIME in the
+ client.
+ Do not select cpunk remailers if PGP key is missing.
+ Fix error in nym creation.
+ Header lines can be edited when composing new
+ messages in the mail reader.
+ Accept empty pass phrase to allow storing the
+ nym database on an encrypted file system.
+ More verbose error messages.
+ Various minor bug fixes.
+ * Thanks to Gerd Beuster for many good suggestions!
+
+1999-09-22 2.9beta12 OpenSSL 0.9.3 or newer is now required.
+ For the Mixmaster DLL, allow the application to
+ seed the random number generator.
+
+1999-09-29 2.9beta13 Fix OpenPGP 3DES decryption.
+ Store DSA secret keys in PGP5 compatible format.
+ Support new "ekx" capability.
+ Use the more secure new style OpenPGP conventional
+ encryption to protect the nym database and nym
+ keys.
+
+1999-10-01 2.9beta14 Bug fix.
+
+1999-10-01 2.9beta15 Bug fix: create mixrand.bin in Mix directory.
+ Support "Encrypt-IDEA" directive.
+
+1999-10-11 2.9beta16 Fix memory leaks.
+
+1999-11-03 2.9beta17 Bug fix.
+ Sending messages is logged as DEBUGINFO.
+
+1999-11-09 2.9beta18 Bug fix for rlist with trailing spaces.
+ Print remailer reliability (by Gerd Beuster).
+
+1999-12-19 2.9beta19 (internal)
+
+1999-12-19 2.9beta20 Output remailer RSA keys separately from the
+ DSA/ElGamal keys to avoid problems with old
+ versions of PGP.
+ Messages in mail folders can be deleted. Nym
+ messages and other encrypted mail will be
+ written back as plain text (by Gerd Beuster).
+ SMTP bug fix.
+ Support multiple OpenPGP decryption subkeys.
+ Fix remailer bug with Newsgroups header in encrypted
+ T1 messages.
+ Fix MIME-decoding bug (pointed out by Gerd Beuster).
+ Nym creation bug fix (by Gerd Beuster).
+
+2000-03-09 2.9beta21 Support for PGP partial length packets (by
+ Christian Mock).
+
+2000-03-16 2.9beta22 Bug fixes (by Antonomasia) and minor changes.
+
+2000-06-29 2.9beta23 Bug fix for nym creation with several newsgroups
+ reply blocks (by Gerd Beuster).
+ --nym option bug fix (by Adam Back).
+
+2001-09-11 2.9beta24 Changed pool.c to allow Mixmaster keys to pass
+ even when binary blocking is enabled. Note that
+ the solution is not a nice one: It does not
+ recognize Mix keys, it simply allows 10 lines of
+ binary garbage instead of 3. This should be enough
+ for Mix keys to come through (by Peter Palfrader).
+ Fixed a bug in pgpdata.c affecting v3 OpenPGP keys.
+ (by Michael Young).
+
+2001-09-14 2.9beta25 Now builds with pcre3 (by Peter Palfrader).
+ Added support for destination.allow (by Peter
+ Palfrader).
+ If the sender email address or IP address matches
+ anything in source.blk, ignore the message (by
+ cmeclax).
+ Added support for the Mutt -T option (by Bill
+ O'Hanlon).
+ Patches merged (by Len Sassaman).
+
+2001-09-17 2.9beta30 Version renamed to avoid conflicts with other
+ unofficial releases.
+
+2001-09-19 2.9beta31 Fixed a bug in mime.c that sometimes resulted in
+ malformed text attachments (by Michael Young).
+ Better error handling (by Scott Renfro).
+ Added support for multiple dest.blk files. This
+ is needed for the Remailer Abuse Blocklist (by
+ Markus Stöger).
+ Added support for remailer-adminkey replies to
+ provide a better way for remops to distribute
+ their keys. (by Markus Stöger).
+ Fixed errors with pcre2.08 (by Rodney Thayer).
+ Added long command option --type-list for the -T
+ option, and updated help (by Len Sassaman).
+ Removed redundant "encoded" variable in mime.c.
+ Fixed Installer bugs.
+
+2001-11-06 2.9beta32 Client functionality updates.
+ POP sockets now properly close.
+ Memory may be freed without allocating.
+ Correct time is written to mbox.
+ Key flags correctly set in key.txt. (all by
+ Disastry).
+ OpenSSL and OpenBSD Install script issues
+ addressed.
+
+2001-12-16 2.9b33 Support for Mixmaster as a service on Windows
+ platforms added (by Disastry).
+ Problem transparently remixing to Type I remailers
+ debugged and corrected (by Andy Dustman,
+ Disastry, Senshi-Admin).
+ Fixed an error in chain.c that was causing
+ segfaults with chains greater than 20 remailers.
+ Non-multipart MIME message errors fixed.
+ Fixed an error in rfc822.c (by Scott Renfro).
+ Fixed pgpget.c errors. (by Ulf Möller).
+ No longer permits automatic blocking of entire
+ domains or newsgroups.
+ Help files re-written (by Lucky Green).
+ Fixed inconsistencies between software name and
+ package name.
+
+2002-07-01 2.9b34 Encrypt-to directive is now supported.
+ Partial packets now properly expire if not
+ reassembled (by cmeclax).
+ Fixed an address blocking error introduced in
+ the last version (Peter Palfrader).
+ Various command line bug fixes.
+
+2002-07-10 2.9b35 Updated zlib due to security reasons.
+ Does not generate keys in client mode.
+ Uses binary format for id.log.
+ Assorted mpgp fixes (by Disastry).
+ Added support for storing the key passphrase
+ in the mix.cfg file. (by Disastry).
+ Now reports the contents of dest.alw for
+ middleman remailers (by Kat).
+ Reworked the OpenSSL version check in the
+ Install script.
+
+2002-08-09 2.9b36 Removed duplicate define of NYMDB from menu.h.
+ Fix a strncat() to undefined string variable in
+ mix.c (Closes: #584381).
+ Have the Makefile list all prerequisites for each
+ build target (Closes: #584386).
+ Change »majordomo@*« to »majordomo@« in default
+ dest.blk. The dest block engine does not under-
+ stand shell globs. Either substring matches or
+ regexen.
+ Fixed -T switch: if type2.list is not available fall
+ back to pubring.mix.
+ USE_IDEA is no longer default in config.h. It always
+ gets defined by the Install script instead.
+ Only create OpenPGP RSA keys if we compiled with
+ IDEA.
+ Make all filenames configurable in mix.cfg.
+ Add global mix.cfg support (compile time option).
+ The -G option now forces creation of new keys even in
+ client mode (Closes: #585176).
+ Random Documentation updates.
+ Default to not installing a .forward file in Install
+ script.
+ Fix unused variable warning on OpenBSD.
+ Fix public remailer keys getting re-signed
+ every time keys are requested (Closes: #478383).
+ Make smtp sending similar to local /usr/lib/sendmail
+ sending (wrt header/body separation;
+ Closes: #482052).
+ Add X-Loop header on mailbox forwarded messages.
+ Several small fixes by Sami Farin et al.
+ Detach correctly in daemon mode.
+ Minor Install script fixes.
+
+2002-08-20 2.9b37 OpenPGP enhancement release (fixes by Disastry).
+ Fix a small bug in pgpdata.c that stopped Mixmaster
+ from reading cipher preferences.
+ Fixed Passphrase reading in mpgp (the test program)
+ on Windows platform.
+ Add Hash: header when clearsigning.
+ Properly handle RSA keys whose key size is not a
+ multiple of 64.
+ Remove leading zeros from MPI.
+ Use MDC packets whenever possible.
+ List CAST5 and AES128 in cipher preferences.
+ Now displays Mixmaster version in the PGP version
+ header for non remailer/nym messages.
+
+2002-09-11 2.9b38 Install script deals with lack of patented IDEA
+ algorithm in a sane way (closes: #479020).
+ Compiled-in passphrase is now deprecated.
+ When expiring packet ids from id.log also expire
+ packets that are dated more than half a year in
+ the future. That way we get rid of invalid
+ packets introduced by the switch to a binary file.
+ The stats in remailer-stats replies always had a
+ peak at 00:00 GMT which was wrong. Fixed.
+ (closes: #597688).
+ Fixed a bug with reading armored keyrings consisting
+ of more than one armored block or having comments
+ in front of the one armored block.
+ In RSA PGP keys, we now set e=0x11.
+ Mixmaster now deletes error and temporary files
+ older than PACKETEXP time along with expired
+ partial packets.
+ Linux PPC fixes (and all other archs where char is
+ unsigned).
+
+2002-10-07 2.9b39 Added a new feature, --store-mail (-I), which will
+ deliver an encrypted mix packet to the message pool
+ without attempting being decrypted.
+ Made minor updates for WIN32 DLL.
+ When sending type II messages interactively you may
+ now choose a middleman remailer as the last hop
+ in your chain (closes: #481244).
+ If a footer.txt file exists its content will be
+ appended to outgoing messages leaving the remailer
+ network at this hop (closes: #490117).
+ List known remailers in remailer-conf reply (closes:
+ #480330).
+ The files created with "SENDMAIL outfile" have
+ different names now to scale beyond 10k files
+ (closes: #587593).
+ Fixed the "is a mailfolder" checking for -f.
+ Various fixes for Mixmaster when not using ncurses.
+ Added new option --config to allow loading of
+ configuration information from an alternate file.
+ POOL is now used correctly if set in mix.cfg.
+ ASCII armor checksum is now verified on PGP keys.
+ Corrected a bug where 1/4096 of pgp messages was
+ destroyed due an improper armor checksum
+ interpretation.
+ Added password-based authenticated SMTP for mix.
+ Currently, only AUTH LOGIN is supported.
+ Mixmaster now handles <CR><LF> in pubring.mix.
+ Removed incorrect NT service checks in mix.c.
+ Mixmaster now keeps no stats in client mode.
+ The pool is autmatically checked for waiting
+ messages in the client configuration.
+ Mixmaster now bears a DFSG-compliant license.
+ Fixed permissions on tarball release.
+ Documentation updates.
+
+2002-10-16 2.9b40 New option MAILIN that can be set to either a mbox
+ or Maildir folder. New mail will be read from it
+ and the folder cleared every time Mixmaster
+ processes its pool, or at MAILINTIME intervals
+ (closes: #597043).
+ The Mixmaster daemon now writes a pid file.
+ Mixmaster in daemon mode now catches SIGTERM and
+ SIGINT and finishes its current queue run and then
+ exits successfully.
+ Minor code formating cleanup and Install script
+ fixes.
+
+2002-12-15 2.9b41 The Mixmaster protocol version is now prepended
+ to the software version in the Mixmaster cap-
+ string.
+ Minor configuration default changes and Install
+ script fixes.
+ Install script now always uses "make" and not
+ "gmake".
+ IDEA detection is fixed on systems that provide
+ the header files but then turn out to not
+ have the required functions upon linking.
+ Install now properly identifies system-wide
+ installations of pcre and/or zlib if they
+ are installed in /usr/local/.
+ Mixmaster will now ensure that an address
+ submitted in a blocking request does not
+ match that of a known remailer before
+ adding it to the dest.blk file (patch
+ submitted by Trek. Vulnerability originally
+ discovered by noise and rabbi.)
+ Minor documentation fixes.
+
+2002-12-16 2.9b42 Minor documentation fixes.
+ Append another newline character to mbox folders
+ when storing a mail so that the mandatory empty
+ line is there.
+
+2002-12-16 2.9.0rc1 Release candidate. Packaging changes only.
+
+2002-12-25 2.9.0 Release version. Minor documentation changes
+ and version number change only.
+
+2003-11-08 2.9.1 Several changes for the Windows build.
+ Some Install script fixes.
+ Fixed a problem in blockrequest() where a buffer
+ could have been used after it was free()'d which
+ resulted in segfaults.
+ Check that feedback buffer is not null before
+ operating on it in chain_select().
+ Closes #631353, thanks Sami Farin.
+ Make sure DH/DSA param file is actually opened
+ before writing to it. Fixes a segfault in
+ case it is not.
+ Handle a pool we cannot read correctly: don't close
+ the NULL dir handle (segfaults on *BSD). We also
+ print a warning in that case now.
+ Minor stats fix (gmtime vs localtime).
+ Fix pool stats bug.
+
+2004-03-20 3.0b1 FEATURE ENHANCEMENTS:
+
+ The secret pgp keyring is now stored ASCII armored
+ with one key per ascii armor.
+ NB: Due to the bug with reading armored keyrings and
+ secring being stored armored now, it is not
+ advisable to downgrade Mixmaster unless special
+ action is taken to preserve the secret pgp
+ keyring.
+ Mixmaster now prompts for secret key passphrase when
+ started in daemon mode.
+ Mixmaster checks expiration and revocation status of
+ pgp keys, userids, and subkeys.
+ Mixmaster will not encrypt or sign with a revoked
+ or expired key.
+ When encrypting, Mixmaster uses preferences from
+ the primary userid (or the latest userid, if zero
+ or more than one primary userid is present.)
+ Mixmaster keys now have creation and expiration date.
+ It is not secured by any crypto voodoo, it's only
+ informational for clients to decide which keys to
+ use should they have more than one per remailer.
+ - on the client side we do not show remailers (and
+ therefore not use them) if their key is expired.
+ - the remailer refuses to decrypt messages to keys
+ that expired one month ago or earlier.
+ - the remailer automatically creates new Mixmaster
+ keys if the current ones are about to expire or
+ already are expired.
+ - the latest key from secring.mix is written to
+ key.txt. It used to be the first one. Since
+ creation of new mix key appends the key, this
+ seemed sensible.
+ Mixmaster now generates dummy messages automatically
+ as mail enters and exits the pool.
+ Applied Maildir feature patch by drt@un.bewaff.net,
+ with some changes by PP:
+ MAILBOX can now be a Maildir (closes: #586223).
+ New Star-Exclude feature by Colin Tuckley:
+ User-selected remailers can be excluded from
+ being chosen as random hops.
+ Have stats on intermediate vs. final hop count
+ (closes: #649900).
+ Add max capability for Type I.
+ Config option EXTFLAGS allows appending additional
+ flags to the capabilities string. (Hauke Lampe)
+ Config option PRECEDENCE allows setting the
+ Precedence: header on all outgoing mail.
+ (Hauke Lampe)
+ In order to serve help files in different languages
+ we need a way to reply to requests like
+ remailer-help-it. In order to not have to modify
+ the code for each and every new ressource,
+ Mixmaster now sends the file
+ requests/remailer-<something> to
+ remailer-<something> requests.
+ remailer-{help,key, stats,conf,adminkey} still are
+ special cases though.
+ Drop messages without timestamps and messages with
+ future timestamps. This abandons backwards
+ compatibility with Mixmaster 2.0.3 and earlier.
+ Mixmaster attempts to detect system clock
+ misconfigurations and refuses to run as a
+ remailer if there is a problem suspected.
+ Only applies to Mixmaster in remailer mode.
+
+ BUG FIXES:
+
+ Mixmaster in daemon mode reloads configuration on
+ SIGHUP.
+ In the curses interface chain selection it was not
+ possible to select a random last hop with a usenet
+ post message. Fixed (closes: #719165).
+ If remix was enabled and we had a Type-I Anon-Post-To
+ request we accidently randhoped it via the
+ configured default remailing chain (default:
+ *,*,*,*).
+ Fixed (closes: #729494).
+ In client mode (REMAIL n) the pool is flushed every
+ time mixmaster is run unless CLIENTAUTOFLUSH is
+ set to n. (closes: #676794: Rate implementation
+ doubled)
+ Found that weird bug that sometimes led to "Unknown
+ remailer version!" errors: In chain_randfinal() we
+ selected a random value between 0 and maxrem
+ instead of 0 and maxrem - 1. Mixmaster now uses
+ broken-chain info from stats.
+ Warn if remailer stats are older than a day or
+ from the future.
+ Don't send messages to ourselves via the mailsystem
+ but instead place them in the pool as incoming
+ messages so that they will get processed with the
+ next pool run.
+ No longer try to send a message if there are no
+ recipients left.
+ Set default max-randhops from 20 to 4.
+ Remix-To chain is limited by max-randhops limit as
+ well.
+ Messages to more than one remailer are dropped.
+ Nym support is not compiled in by default anymore.
+ The OpenPGP module mpgp now includes a man
+ page (large contributions by Trek).
+ Ignore 'No reliable remailers' problems when
+ randhopping messages in middleman mode.
+ That is better than dropping them.
+ Experimental feature: --redirect -l <chain>.
+ If you have a mixmaster message with a
+ chain starting with hop1 (you cannot know any
+ more because it already is encrypted) then
+ mix --redirect -l foo,bar < file
+ redirect the message so the chain is actually
+ foo,bar,hop1,... and places it in your pool.
+ If the total number of hops (which cannot be
+ known) exceeds 20 the message is damanged
+ and will fail at the 20th node.
+
+2004-05-06 3.0b2
+ Use /dev/arandom instead of /dev/srandom on
+ OpenBSD (Nikolay Sturm).
+ Fall back to 3DES as Encrypt-Key cipher if we don't
+ have IDEA. - Laurent Fousse <laurent@komite.net>
+ Also sort mail into the various mboxes if autoreply
+ is not set.
+ Properly ignore whitespace in chain selection.
+ Removed unused functions in keymgt.c.
+ Added new options -V, --version, and --about.
+ Made manpage corrections.
+ Minor ncurses display tweaks.
+ General improvements for Win32 support (by
+ goblin and Peter Palfrader).
+ Preliminary Windows Installer work.
+ On Win32, default to Application Data/Mixmaster for
+ mixmaster's basedirectory. This can still be
+ overridden by MIXPATH or the registry entry
+ HKEY_CURRENT_USER\Software\Mixmaster\MixDir
+ Introduced new option "(e)dit configuration
+ file" in the main menu.
+ Changed 'q)uit' to 'q)uit w/o sending' in
+ menusend.c.
+ Added stats downloading support. Currently
+ works under Win32 only (by goblin).
+ Fixed bug in buffers.c.
+
+2006-06-24 3.0rc1
+ Prefer pubring.asc over secring.pgp.
+ Support an unpublished dest.alw file.
+ Added MINLAT directive. Ensures randhopped
+ messages are sent through remailers of
+ latency of MINLAT time or greater
+ (suggested by Steve Crook).
+ Improved OpenSSL version checking in the
+ Install script.
+ Added full stats download support.
+ Fixed buffer overflow bug in keymgt.c.
+
+2008-03-03 3.0
+ Changed name of WIN32 default config file
+ from mix.cfg.txt to mix.ini.
+ Changed pop3.cfg to pop3.ini on WIN32.
+ Updated Install script.
+ Minor documentation changes.
+
+
+
+Mixmaster maintainer history:
+
+1998-2000: Ulf Möller -- versions 2.9beta0 through 2.9beta22.
+2000: Johannes Kroeger -- version 2.9beta23.
+2001-2008: Len Sassaman -- versions 2.9beta24 through present.
diff --git a/Install b/Install
@@ -0,0 +1,1403 @@
+#!/bin/sh
+# Mixmaster version 3.0 -- (C) 1999-2008 Anonymizer Inc. and others.
+
+# Mixmaster may be redistributed and modified under certain conditions.
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+# ANY KIND, either express or implied. See the file COPYRIGHT for
+# details.
+
+# $Id: Install 979 2008-03-03 18:17:07Z rabbi $
+
+#whereis program default-path
+whereis()
+{
+ #echo "Looking for $1..."
+ found=""
+ for i in $* `which $1 2>&1`
+ do
+ if [ -f "$i" -a -x "$i" ]
+ then
+ found=$i
+ fi
+ done
+ if [ "$found" = "" ]
+ then
+ found=$2
+# echo "$1 not found. Using $found."
+# else
+# echo "$1 is at $found."
+ fi
+}
+
+if echo -n | grep n >/dev/null
+then
+ echo1=""
+ echo2="\c"
+else
+ echo1="-n"
+ echo2=""
+fi
+
+# readln text default
+readln()
+{
+ echo $echo1 "$1 [$2] $echo2"
+ read ans
+ if [ -z "$ans" ]
+ then
+ ans="$2"
+ fi
+}
+
+# findlib libxxx.a -- find and configure libraries
+# Input:
+# $1 library name
+# $CONFIG library configure options
+# $INCDIR possible include directories
+# $SRCDIR possible library source directories
+# $LIBDIR possible library binary directories
+#
+# Output:
+# $found library directory
+# $lib library name
+# $INCDIR include directory if required, empty otherwise
+# $LDFLAG linker options
+# $LIB path to library file
+# $MAKELIB Makefile entry to compile library
+findlib()
+{
+ lib=$1
+ libso=`echo $lib | sed 's/\.a$/.so/'`
+ echo "Looking for $lib..."
+
+ found=
+ source=
+ type=
+ LIB=
+ LDFLAG=
+ MAKELIB=
+
+ for i in /usr/local/lib /usr/lib /lib /usr/lib64
+ do
+ if [ -r $i/$lib -o -r $i/$libso ]
+ then
+ found=$i
+ type=system
+ fi
+ done
+
+ for i in $LIBDIR
+ do
+ if [ -r $i/$lib -o -r $i/$libso ]
+ then
+ found=$i
+ type=installed
+ fi
+ done
+
+ for i in $SRCDIR
+ do
+ if [ -r $i/$lib -o -r $i/lib/$lib ]
+ then
+ found=$i
+ type=binary
+ fi
+ done
+
+ if [ -r "$found/$libso" ]
+ then
+ echo "Found at $found/$libso."
+ elif [ -r "$found/$lib" ]
+ then
+ echo "Found at $found/$lib."
+ elif [ -r "$found/lib/$lib" ]
+ then
+ echo "Found at $found/lib/$lib."
+ fi
+
+ for i in $SRCDIR
+ do
+ if [ -d $i -a ! "$type" = binary ]
+ then
+ source=$i
+ fi
+ done
+
+ if [ "$source" != "" ]
+ then
+ echo "Found source directory $source."
+ if [ "$found" = "" ]
+ then
+ ans=y
+ else
+ echo "Use the source if the pre-installed library causes compilation problems."
+ readln "Use source?" n
+ fi
+ if [ "$ans" = "y" ]
+ then
+ found=$source
+ type=source
+ fi
+ fi
+
+ if [ "$found" = "" ]
+ then
+ echo "Not found."
+ fi
+
+ if [ -r $found/lib/$lib ]
+ then
+ LIB=$found/lib/$lib
+ else
+ LIB=$found/$lib
+ fi
+ if [ "$type" = system ]
+ then
+ LIB=
+ LDFLAG="-l`echo $lib | sed 's/^lib//;s/\.a$//'` -L$found"
+ if [ "$found" = "/usr/local/lib" ]
+ then
+ INCDIR="/usr/local/include $INCDIR"
+ fi
+ fi
+
+ incdir=$INCDIR
+ INCDIR=
+ for i in $incdir
+ do
+ if [ -d $i ]
+ then
+ INCDIR=$i
+ fi
+ done
+
+ if [ "$type" = source -o "$type" = binary ]
+ then
+ if [ ! -r $found/lib/$lib ]
+ then
+ MAKELIB="$found/$lib:
+ cd $found; make $lib"
+ fi
+ if [ -d $found/include ]
+ then
+ INCDIR=$found/include
+ else
+ INCDIR=$found
+ fi
+ fi
+
+ if [ "$type" = source ]
+ then
+ dir=`pwd`
+ if [ "$dir" = "" ]
+ then
+ dir=$PWD
+ fi
+
+ cd $found
+ if [ -x configure ]
+ then
+ echo "Configuring..."
+ ./configure $CONFIG
+ fi
+ if [ "$lib" = "libcrypto.a" ]
+ then
+ if [ -f config ]
+ then
+ sh config
+ elif [ -x Configure ]
+ then
+ ./Configure 2>tmp.$$
+ cat tmp.$$
+ readln "Your system?" `cat tmp.$$ | tr ' ' '\n' | grep -i \`uname\` | tail -1`
+ rm -f tmp.$$
+ echo "Configuring..."
+ ./Configure $ans
+ fi
+ fi
+ cd $dir
+ fi
+}
+
+# Global installation.
+
+
+##########################################################################
+umask 077
+
+#FIXME -- Mixmaster now should be installed as root, and Install should
+#create a remailer user. /var/spool/mixmaster is a good home.
+
+if [ `whoami` = root ]
+then
+ echo "Please create a new user, e.g, \`mix', and install Mixmaster under that
+user id. Installing Mixmaster as root is not recommended."
+ readln "Continue anyway?" n
+ if [ "$ans" = n ]
+ then
+ exit 1
+ fi
+fi
+
+MIXDIR="$PWD"
+if [ "$MIXDIR" = "" ]
+then
+ MIXDIR=`pwd`
+fi
+MIXCFG="$MIXDIR/conf"
+MIXSRC="$MIXDIR/Src"
+MIXDEST0=${MIXPATH:-$HOME/Mix}
+
+system=`uname`
+if [ "$system" = "MS-DOS" ]
+then
+ system=msdos
+fi
+
+if [ "$HOSTNAME" = "" ]
+then
+ HOSTNAME=`hostname`
+fi
+if [ "$HOSTNAME" = "" ]
+then
+ HOSTNAME=msdos
+ system=msdos
+fi
+
+if [ "$system" = msdos ]
+then
+ MIXDEST0=${MIXPATH:-C:/Mix}
+fi
+
+if [ -f "$MIXSRC/Makefile" ]
+then
+ if grep "#Makefile generated.*$HOSTNAME" $MIXSRC/Makefile
+ then
+ echo "Found a Makefile for this system."
+ readln "Use this Makefile?" y
+ if [ "$ans" = n ]
+ then
+ rm -f "$MIXSRC/Makefile"
+ fi
+ else
+ readln "Remove old Makefile?" y
+ if [ "$ans" = y ]
+ then
+ rm -f "$MIXSRC/Makefile"
+ fi
+ fi
+fi
+
+if [ -f "$MIXSRC/Makefile" ]
+then
+ MIXDEST=`grep "DSPOOL=" $MIXSRC/Makefile | sed 's/.*DSPOOL=..//;s/\".*//'`
+ if [ "$MIXDEST" = "" ]
+ then
+ MIXDEST="$MIXDEST0"
+ fi
+fi
+
+if [ "$MIXDEST" = "" ]
+then
+ readln "Mixmaster directory?" "$MIXDEST0"
+ MIXDEST=$ans
+else
+ echo "Mixmaster directory: $MIXDEST"
+fi
+
+if [ ! -d "$MIXDEST" ]
+then
+ echo "Creating directory $MIXDEST"
+ mkdir "$MIXDEST"
+fi
+
+if [ ! -d "$MIXDEST" ]
+then
+ echo "Cannot not create $MIXDEST"
+ exit 1
+fi
+
+if [ -f "$MIXDEST/mix.cfg" ]
+then
+ if [ -f "$MIXDEST/secring.mix" ]
+ then
+ remailer=y
+ if grep PASSPHRASE "$MIXDEST/mix.cfg" >/dev/null
+ then
+ PASSINCONFIG=1
+ fi
+ else
+ readln "Do you want to set up a remailer?" n
+ remailer=$ans
+ fi
+elif [ -f "$MIXDEST/mixmaster.conf" ]
+then
+ echo "Upgrading from Mixmaster 2.0.*"
+ remailer=n
+else
+ readln "Do you want to set up a remailer?" y
+ remailer=$ans
+fi
+
+
+ans=""
+if [ "$remailer" = "y" ]
+then
+ ans="n"
+ if [ "$PASSINCONFIG" != 1 ]
+ then
+ echo ""
+ echo "You can either compile your secret passphrase into the binary
+or you can set it in your config file. Note that the former does not
+really increase security as the passphrase can still be discovered by
+running something like \`strings mixmaster'."
+ echo ""
+ echo "Most users should answer \`n' to this question:"
+ echo ""
+ readln "Do you want to compile the passphrase into the binary?" n
+ fi
+
+ rm -f "$MIXSRC/mix.o" # make sure our new passphrase takes effect
+ if [ "$ans" = "y" ]
+ then
+ ans=""
+ echo "Please enter a passphrase for your remailer (must be the same
+whenever you re-compile Mixmaster)."
+ read ans
+
+ if [ "$ans" != "" ]
+ then
+ PASS="PASS=$ans"
+ else
+ echo "WARNING: not setting a passphrase"
+ fi
+ else
+ if [ "$PASSINCONFIG" != 1 ]
+ then
+ ans=""
+ echo "Please enter a passphrase for your remailer (it will be
+stored in mix.cfg in clear)."
+ read ans
+
+ if [ "$ans" = "" ]
+ then
+ echo "WARNING: setting empty passphrase"
+ fi
+ PASSPHRASE="PASSPHRASE $ans"
+ if [ -f $MIXDEST/mix.cfg ]
+ then
+ echo "$PASSPHRASE" >> $MIXDEST/mix.cfg
+ fi
+ fi
+ fi
+fi
+
+
+cd "$MIXSRC"
+if [ ! -f Makefile ]
+then
+ LIBS=
+ INC=
+ DEF=
+ LDFLAGS=
+
+ if [ ! -z "$PASS" ]
+ then
+ DEF="$DEF -DCOMPILEDPASS='\"\$(PASS)\"'"
+ fi
+
+ if [ "$system" = msdos ]
+ then
+ readln "Use WIN32 GUI?" y
+ if [ "$ans" = y ]
+ then
+ system=win32
+ LDFLAGS=-lwsock32
+ fi
+ fi
+ if [ "$system" = SunOS ]
+ then
+ LDFLAGS="-lsocket -lnsl"
+ fi
+
+ LIBDIR=
+ INCDIR=
+ SRCDIR=zlib*
+ findlib libz.a
+ if [ "$found" = "" ]
+ then
+ readln "Continue anyway?" n
+ if [ "$ans" = "n" ]
+ then
+ echo "Please install zlib 1.1.4 or 1.2.3 or greater now."
+ exit 1
+ fi
+ else
+ ZLIB="$MAKELIB"
+ DEF="$DEF -DUSE_ZLIB"
+ LIBS="$LIBS $LIB"
+ LDFLAGS="$LDFLAGS $LDFLAG"
+ if [ "$INCDIR" != "" ]
+ then
+ INC="$INC -I$INCDIR"
+ fi
+ fi
+
+ LIBDIR=
+ INCDIR="/usr/include /usr/include/pcre /usr/local/pcre/include"
+ SRCDIR=pcre*
+ findlib libpcre.a
+ if [ "$found" != "" ]
+ then
+ PCRE="$MAKELIB"
+ DEF="$DEF -DUSE_PCRE"
+ LIBS="$LIBS $LIB"
+ LDFLAGS="$LDFLAGS $LDFLAG"
+ if [ "$INCDIR" != "" ]
+ then
+ INC="$INC -I$INCDIR"
+ fi
+ fi
+
+ opensslinfo="Please get OpenSSL 0.9.6l or greater from http://www.openssl.org/"
+ opensslwarning6="WARNING: This version of OpenSSL contains known vulnerabilities. Please upgrade to OpenSSL 0.9.6l or greater!"
+ opensslwarning7="WARNING: This version of OpenSSL contains known vulnerabilities. Please upgrade to OpenSSL 0.9.7c or greater!"
+ opensslwarning0=$opensslwarning7
+ LIBDIR=/usr/local/ssl/lib
+ INCDIR="/usr/include /usr/include/ssl /usr/lib/ssl/include /usr/local/ssl/include"
+ SRCDIR="openssl*"
+
+ opensslwarn()
+ {
+ if [ "$1" = "6" ]
+ then
+ echo $opensslwarning6
+ elif [ "$1" = "7" ]
+ then
+ echo $opensslwarning7
+ else
+ echo $opensslwarning0
+ fi
+ readln "Continue anyway?" y
+ if [ "$ans" = "n" ]
+ then
+ echo $opensslinfo
+ exit 1
+ fi
+ }
+
+ if [ "$system" = win32 ]
+ then
+ findlib libeay32.a
+ else
+ findlib libcrypto.a
+ fi
+ if [ "$found" = "" ]
+ then
+ echo $opensslinfo
+ exit 1
+ fi
+
+ OPENSSLLIB="$LIB"
+ LIBS="$LIBS $LIB"
+ LDFLAGS="$LDFLAGS $LDFLAG"
+ if [ "$MAKELIB" != "" ]
+ then
+ OPENSSL="$found/$lib:
+ cd $found/crypto; make"
+ fi
+ if [ -d "$INCDIR/openssl" ]
+ then
+ INC="$INC -I$INCDIR"
+ else
+ # detect old SSLeay versions
+ if [ -f "$INCDIR/crypto.h" ]
+ then
+ version=800
+ if grep OPENSSL "$INCDIR/crypto.h" > /dev/null
+ then
+ version=920
+ fi
+ fi
+ fi
+
+ # Find the OpenSSL version header
+ if [ -f "$INCDIR/openssl/opensslv.h" ]
+ then
+ version=`grep 'SSL.*_VERSION_NUMBER.*0x' $INCDIR/openssl/opensslv.h | sed 's/.*0x0*//;s/[ ].*//;s/L$//' | tr '[a-f]' '[A-F]'`
+ elif [ -f "$INCDIR/opensslv.h" ]
+ then
+ version=`grep 'SSL.*_VERSION_NUMBER.*0x' $INCDIR/opensslv.h | sed 's/.*0x0*//;s/[ ].*//;s/L$//' | tr '[a-f]' '[A-F]'`
+ fi
+ if [ "$version" = "" ]
+ then
+ echo "Warning: Can't find OpenSSL version number!"
+ readln "Continue anyway?" y
+ if [ "$ans" = "n" ]
+ then
+ echo $opensslinfo
+ exit 1
+ fi
+#
+# Here we match against known OpenSSL versions
+#
+ elif [ "$version" = "90581F" ]
+ then
+ decimalversion=9459743
+ echo "Compiling with OpenSSL 0.9.5a."
+ opensslwarn 6
+ elif [ "$version" = "90601F" ]
+ then
+ decimalversion=9461791
+ echo "Compiling with OpenSSL 0.9.6a."
+ opensslwarn 6
+ elif [ "$version" = "90602F" ]
+ then
+ decimalversion=9461807
+ echo "Compiling with OpenSSL 0.9.6b."
+ opensslwarn 6
+ elif [ "$version" = "90603F" ]
+ then
+ decimalversion=9461823
+ echo "Compiling with OpenSSL 0.9.6c."
+ opensslwarn 6
+ elif [ "$version" = "90604F" ]
+ then
+ decimalversion=9461839
+ echo "Compiling with OpenSSL 0.9.6d."
+ opensslwarn 6
+ elif [ "$version" = "90605F" ]
+ then
+ decimalversion=9461855
+ echo "Compiling with OpenSSL 0.9.6e."
+ opensslwarn 6
+ elif [ "$version" = "90606F" ]
+ then
+ decimalversion=9461871
+ echo "Compiling with OpenSSL 0.9.6f."
+ opensslwarn 6
+ elif [ "$version" = "90607F" ]
+ then
+ decimalversion=9461887
+ echo "Compiling with OpenSSL 0.9.6g."
+ opensslwarn 6
+ elif [ "$version" = "90608F" ]
+ then
+ decimalversion=9461903
+ echo "Compiling with OpenSSL 0.9.6h."
+ opensslwarn 6
+elif [ "$version" = "90609F" ]
+ then
+ decimalversion=9461919
+ echo "Compiling with OpenSSL 0.9.6i."
+ opensslwarn 6
+ elif [ "$version" = "9060A0" ]
+ then
+ decimalversion=9461920
+ echo "Compiling with OpenSSL 0.9.6j."
+ opensslwarn 6
+ elif [ "$version" = "9060B0" ]
+ then
+ decimalversion=9461936
+ echo "Compiling with OpenSSL 0.9.6k."
+ opensslwarn 6
+ elif [ "$version" = "9060C0" ]
+ then
+ decimalversion=9461952
+ echo "Compiling with OpenSSL 0.9.6l."
+ elif [ "$version" = "9060D0" ]
+ then
+ decimalversion=9461968
+ echo "Compiling with OpenSSL 0.9.6m."
+ elif [ "$version" = "90700F" ]
+ then
+ decimalversion=9465871
+ echo "Compiling with OpenSSL 0.9.7."
+ opensslwarn 7
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90701F" ]
+ then
+ decimalversion=9465887
+ echo "Compiling with OpenSSL 0.9.7a."
+ opensslwarn 7
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90702F" ]
+ then
+ decimalversion=9465903
+ echo "Compiling with OpenSSL 0.9.7b."
+ opensslwarn 7
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90703F" ]
+ then
+ decimalversion=9465919
+ echo "Compiling with OpenSSL 0.9.7c."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90704F" ]
+ then
+ decimalversion=9465935
+ echo "Compiling with OpenSSL 0.9.7d."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90705F" ]
+ then
+ decimalversion=9465951
+ echo "Compiling with OpenSSL 0.9.7e."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90706F" ]
+ then
+ decimalversion=9465967
+ echo "Compiling with OpenSSL 0.9.7f."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90707F" ]
+ then
+ decimalversion=9465983
+ echo "Compiling with OpenSSL 0.9.7g."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90708F" ]
+ then
+ decimalversion=9465999
+ echo "Compiling with OpenSSL 0.9.7h."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90709F" ]
+ then
+ decimalversion=9466015
+ echo "Compiling with OpenSSL 0.9.7i."
+ DEF="$DEF -DUSE_AES"
+
+ elif [ "$version" = "9070AF" ]
+ then
+ decimalversion=9466031
+ echo "Compiling with OpenSSL 0.9.7j."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "9070BF" ]
+ then
+ decimalversion=9466047
+ echo "Compiling with OpenSSL 0.9.7k."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "9070CF" ]
+ then
+ decimalversion=9466063
+ echo "Compiling with OpenSSL 0.9.7l."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "9070DF" ]
+ then
+ decimalversion=9466079
+ echo "Compiling with OpenSSL 0.9.7m."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "9070EF" ]
+ then
+ decimalversion=9466095
+ echo "Compiling with OpenSSL 0.9.7n."
+ echo "This version was unreleased at the time of packaging."
+ echo "It is not guaranteed to work. Please report any problems."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90800F" ]
+ then
+ decimalversion=9469967
+ echo "Compiling with OpenSSL 0.9.8."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90801F" ]
+ then
+ decimalversion=9469983
+ echo "Compiling with OpenSSL 0.9.8a."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90802F" ]
+ then
+ decimalversion=9469999
+ echo "Compiling with OpenSSL 0.9.8b."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90803F" ]
+ then
+ decimalversion=9470015
+ echo "Compiling with OpenSSL 0.9.8c."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90804F" ]
+ then
+ decimalversion=9470031
+ echo "Compiling with OpenSSL 0.9.8d."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90805F" ]
+ then
+ decimalversion=9470047
+ echo "Compiling with OpenSSL 0.9.8e."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90806F" ]
+ then
+ decimalversion=9470063
+ echo "Compiling with OpenSSL 0.9.8f."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90807F" ]
+ then
+ decimalversion=9470079
+ echo "Compiling with OpenSSL 0.9.8g."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90808F" ]
+ then
+ decimalversion=9470095
+ echo "Compiling with OpenSSL 0.9.8h."
+ DEF="$DEF -DUSE_AES"
+ elif [ "$version" = "90809F" ]
+ then
+ decimalversion=9470111
+ echo "Compiling with OpenSSL 0.9.8h."
+ echo "This version was unreleased at the time of packaging."
+ echo "It is not guaranteed to work. Please report any problems."
+ DEF="$DEF -DUSE_AES"
+ fi
+#
+# Now we try to guess about unknown versions:
+#
+ if [ "$decimalversion" = "" ]
+ then
+ decimalversion=`echo 16i $version p | dc`
+ fi
+ if [ "$decimalversion" = "" ]
+ then
+ echo "Warning: This version: ${version} of OpenSSL is not recognized."
+ readln "Continue anyway?" y
+ if [ "$ans" = "n" ]
+ then
+ echo $opensslinfo
+ exit 1
+ else
+ echo "Does this version of OpenSSL contain AES support?"
+ readln "If unsure of the answer, say \`n'" n
+ if [ "$ans" = "y" ]
+ then
+ DEF="$DEF -DUSE_AES"
+ fi
+ fi
+ elif [ "$decimalversion" -lt "2336" ] # 920
+ then
+ echo "This version: ${version} of SSLeay is not supported."
+ echo $opensslinfo
+ exit 1
+ elif [ "$decimalversion" -lt "9449728" ] # 903100
+ then
+ echo "This version: ${version} of OpenSSL is not supported."
+ echo $opensslinfo
+ exit 1
+ elif [ "$decimalversion" -gt "9470111" ] # 0.9.8h
+ then
+ echo "Warning: This version: ${version} of OpenSSL is untested."
+ readln "Continue anyway?" y
+ if [ "$ans" = "n" ]
+ then
+ echo $opensslinfo
+ exit 1
+ else
+ echo "Does this version of OpenSSL contain AES support?"
+ readln "If unsure of the answer, say \`n'" n
+ if [ "$ans" = "y" ]
+ then
+ DEF="$DEF -DUSE_AES"
+ fi
+ fi
+ fi
+
+ LIBDIR=
+ INCDIR=/usr/include/ncurses
+ SRCDIR=ncurses*
+ CONFIG=--enable-termcap
+ if [ "$TERMINFO" != "" ]
+ then
+ CONFIG="--datadir=$TERMINFO"
+ fi
+ if [ -d /usr/share/terminfo ]
+ then
+ CONFIG=
+ fi
+ if [ -d /usr/lib/terminfo ]
+ then
+ CONFIG=--datadir=/usr/lib/terminfo
+ fi
+
+ if [ `uname` = OpenBSD ]
+ then
+ findlib libcurses.a
+ else
+ findlib libncurses.a
+ fi
+ if [ "$found" = "" ]
+ then
+ if [ "$system" != win32 ]
+ then
+ readln "Do you want to use Mixmaster's menu-based user interface?" y
+ if [ "$ans" = "y" ]
+ then
+ echo "Please install ncurses now. It is available from http://www.clark.net/pub/dickey/ncurses/ncurses.tar.gz"
+ exit 1
+ fi
+ fi
+ else
+ DEF="$DEF -DUSE_NCURSES"
+ if [ "$type" = system -o "$type" = installed ]
+ then
+ LIBS="$LIBS $LIB"
+ LDFLAGS="$LDFLAGS $LDFLAG"
+ else
+ LIBS="$LIBS $found/lib/$lib"
+ NCURSES="$found/lib/$lib:
+ cd $found/ncurses; make ../lib/$lib"
+ fi
+ if [ "$INCDIR" != "" ]
+ then
+ INC="$INC -I$INCDIR"
+ elif [ -f "/usr/include/ncurses.h" ]
+ then
+ DEF="$DEF -DHAVE_NCURSES_H"
+ fi
+ fi
+
+ ideawarn()
+ {
+ echo "
+ WARNING: Your version of OpenSSL has been configured without IDEA support.
+ If you continue, Mixmaster will be installed with reduced functionality.
+ This means (among other things) that Mixmaster will not create an RSA
+ OpenPGP key (to avoid mail loss in the Type I system). You may want to
+ re-install OpenSSL before proceeding.
+
+ This will not concern you if you only plan to run a type II remailer or
+ simply want a type II client."
+ readln "Continue anyway?" y
+ if [ "$ans" = "n" ]
+ then
+ exit 1
+ fi
+ }
+
+ if [ "$system" = OpenBSD ]
+ then
+ LIBDIR=
+ INCDIR=
+ SRCDIR=idea*
+ findlib libidea.a
+ if [ "$found" = "" ]
+ then
+ ideawarn
+ else
+ DEF="$DEF -DUSE_IDEA"
+ IDEALIB="$MAKELIB"
+ LIBS="$LIBS $LIB"
+ LDFLAGS="$LDFLAGS $LDFLAG"
+ if [ "$INCDIR" != "" ]
+ then
+ INC="$INC -I$INCDIR"
+ fi
+ fi
+ elif [ "$system" = msdos -o "$system" = win32 ]
+ then
+ DEF="$DEF -DUSE_IDEA"
+ else
+ echo "Checking for IDEA support..."
+ cat <<END >tmptst.c
+#include <openssl/idea.h>
+int main() {
+ void *dummy;
+ dummy = idea_cfb64_encrypt;
+ exit(0);
+}
+END
+ if gcc $LDFLAGS $INC tmptst.c -o tmptst $OPENSSLLIB
+ then
+ DEF="$DEF -DUSE_IDEA"
+ else
+ ideawarn
+ fi
+ rm -f tmptst.c tmptst
+ fi
+
+ echo "testing for setenv()..."
+ cat <<END >tmptst.c
+int main() {
+#include <stdlib.h>
+ setenv("TZ", "GMT", 0);
+ exit(0);
+}
+END
+ if gcc tmptst.c -o tmptst
+ then
+ DEF="$DEF -DHAVE_SETENV"
+ fi
+ echo "done"
+ rm -f tmptst.c tmptst
+
+# if [ "$MIXDEST" = "$HOME/Mix" ]
+# then
+# SPOOL=
+# else
+ SPOOL=-DSPOOL=\'\"$MIXDEST\"\'
+# fi
+
+ echo "Generating Makefile."
+ echo "#Makefile generated on $HOSTNAME `date`" >Makefile
+ sed -e "s#%MIXDIR#$SPOOL#" \
+ -e "s#%LIBS#$LIBS#" \
+ -e "s#%LDFLAGS#$LDFLAGS#" \
+ -e "s#%INC#$INC#" \
+ -e "s#%DEF#$DEF#" < Makefile.in >> Makefile
+# echo "$ZLIB" >>Makefile
+# echo "$PCRE" >>Makefile
+ echo "$IDEALIB" >>Makefile
+ echo "$NCURSES" >>Makefile
+ echo "$OPENSSL" >>Makefile
+fi
+
+
+
+
+
+echo "Compiling. Please wait."
+whereis make
+make=$found
+
+if [ "$system" = win32 ]
+then
+# (cd zlib*; make libz.a)
+# (cd pcre*; make libpcre.a)
+ if [ "$PASS" != "" ]
+ then
+ $make "$PASS" dllmix
+ else
+ $make dllmix
+ fi
+else
+ if [ "$PASS" != "" ]
+ then
+ $make "$PASS"
+ else
+ $make
+ fi
+fi
+
+if [ -x mixmaster ]
+then
+ echo
+else
+ echo "Error: The compilation failed. Please consult the documentation (section
+\`Installation problems')."
+ readln "Remove the old Makefile?" y
+ if [ "$ans" = y ]
+ then
+ rm -f Makefile
+ fi
+ exit 1
+fi
+
+if [ -f "$MIXDEST/mixmaster.conf" -a ! -f "$MIXDEST/mix.cfg" ]
+then
+ export MIXDEST
+ export MIXDIR
+ export MIXSRC
+ "${MIXDIR}/upgrade"
+ exit 0
+fi
+
+if [ -f mixmaster.exe ]
+then
+ cp mixmaster.exe "$MIXDEST"
+else
+ cp mixmaster "$MIXDEST"
+fi
+
+cd "$MIXCFG"
+for i in mlist.txt pubring.mix rlist.txt pubring.asc
+do
+ if [ ! -f "$MIXDEST/$i" ]
+ then
+ cp "$i" "$MIXDEST"
+ fi
+done
+
+if [ "$remailer" = "y" ]
+then
+ cd "$MIXCFG"
+ for i in adminkey.txt dest.alw
+ do
+ if [ ! -f "$MIXDEST/$i" ]
+ then
+ cp "$i" "$MIXDEST"
+ fi
+ done
+fi
+
+if [ "$remailer" = "n" ]
+then
+ if [ ! -f "$MIXDEST/mix.cfg" ]
+ then
+ whereis sendmail /usr/lib/sendmail /usr/sbin/sendmail
+ echo "SENDMAIL $found -t" >"$MIXDEST/mix.cfg"
+ cat mix.cfg >>"$MIXDEST/mix.cfg"
+ fi
+ echo "Client installation complete."
+ exit
+fi
+
+for i in *.blk
+do
+ if [ ! -f "$MIXDEST/$i" ]
+ then
+ cp "$i" "$MIXDEST"
+ fi
+done
+
+cd "$MIXDEST"
+
+installed=n
+if [ -f mix.cfg ]
+then
+ if grep REMAILERADDR mix.cfg >/dev/null
+ then
+ installed=y
+ fi
+fi
+
+if [ "$installed" = "n" ]
+then
+ Date=`date`
+ whereis sendmail /usr/lib/sendmail /usr/sbin/sendmail
+ sendmail=$found
+
+ echo "Mixmaster can be installed in the low-maintenance \`middleman' mode.
+In that mode, it will send mail to other remailers only, to avoid
+complaints about anonymous messages."
+ readln "Install as middleman?" n
+ middle=$ans
+
+ readln "The e-mail address of your remailer:" `whoami`@$HOSTNAME
+ RMA=$ans
+
+ echo "Do you want Mixmaster to send auto-replies to messages it does not
+understand (If the address <$RMA> is also used"
+ readln "for mail to be read by a human, type \`n')?" y
+ autoreply=$ans
+
+ if [ "$middle" = n ]
+ then
+ readln "An address to appear in the \`From:' line of anonymous messages:" `echo $RMA | sed 's/.*@/nobody@/'`
+ RAA=$ans
+
+ readln "Address for complaints to be sent to:" `echo $RMA | sed 's/.*@/abuse@/'`
+ CA=$ans
+ else
+ RAA=$RMA
+ CA=$RMA
+ fi
+
+ echo "Choose a name for your remailer. It will appear in remailer status messages."
+ readln "Long name:" "Anonymous Remailer"
+ RMN=$ans
+
+ if [ "$middle" = n ]
+ then
+ echo "Choose a name to be used in the \`From:' line of remailed messages."
+ readln "Anon long name:" "Anonymous"
+ RAN=$ans
+ fi
+
+ readln "A short name to appear in lists:" `echo $HOSTNAME|sed 's/\..*//'`
+ SN=$ans
+
+ readln "Accept Mixmaster (Type II) messages?" y
+ mix=$ans
+
+ readln "Accept PGP (Type I) remailer messages?" n
+ pgp=$ans
+
+ unencrypted=n
+ if [ "$pgp" = "y" ]
+ then
+ readln "Accept unencrypted remailer messages?" n
+ unencrypted=$ans
+ fi
+
+ echo "Mixmaster will log error messages and warnings. Do you want to log"
+ readln "informational messages about normal operation as well?" y
+ if [ "$ans" = y ]
+ then
+ verbose=2
+ else
+ verbose=1
+ fi
+
+ readln "Filter binary attachments?" n
+ binfilter=$ans
+
+ if [ "$middle" = n ]
+ then
+ if [ "$autoreply" = y ]
+ then
+ readln "Allow users to add themselves to the list of blocked addresses?" y
+ autoblock=$ans
+ fi
+
+ echo "Do you want to allow posting? Newsgroups can be restricted in dest.blk.
+y)es, post locally; use m)ail-to-news gateway; n)o."
+ readln "Allow posting to Usenet?" m
+ post="$ans"
+ if [ "$ans" = y ]
+ then
+ whereis inews /usr/lib/news/inews
+ readln "News posting software:" "$found -h"
+ news=$ans
+ readln "Organization line for anonymous Usenet posts:" "Anonymous Posting Service"
+ orga=$ans
+ readln "Use anti-spam message IDs?" y
+ mid=$ans
+ elif [ "$ans" = m ]
+ then
+ readln "Mail-to-news gateway:" mail2news@nym.alias.net
+ news=$ans
+ fi
+ fi
+
+# Commented the poolsize question out, since poolsize is the least
+# important of the three pool parameters.
+#
+# echo "How many messages do you want to keep in the reordering pool?
+#A larger pool is more secure, but also causes higher latency.
+#0 means to remail immediately."
+# readln "Pool size:" 45
+# poolsize=$ans
+
+ mbox=
+ if [ -f ~/.forward ]
+ then
+ mbox=`head -1 ~/.forward | sed 's/^"//;s/"$//'`
+ if echo "$mbox" | grep 'mix' >/dev/null 2>/dev/null
+ then
+ mbox=
+ elif echo "$mbox" | grep 'procmail' >/dev/null 2>/dev/null
+ then
+ if grep mix ~/.procmailrc >/dev/null 2>/dev/null
+ then
+ mbox=
+ fi
+ fi
+ fi
+
+ if [ "$mbox" = "" ]
+ then
+ mbox=${MAIL:-/usr/spool/mail/$NAME}
+ touch "$mbox"
+ if [ ! -w "$mbox" ]
+ then
+ echo "$mbox is not writeable."
+ readln "Mailbox for non-remailer messages:" "${MIXDEST}/mbox"
+ mbox=$ans
+ fi
+ fi
+
+ cat <<END >mix.cfg
+# mix.cfg -- installed $Date
+SENDMAIL $sendmail -t
+
+# Where to store non-remailer messages:
+MAILBOX $mbox
+#MAILABUSE mbox.abuse
+#MAILBLOCK mbox.block
+#MAILUSAGE mbox.usage
+#MAILANON mbox.anon
+#MAILERROR mbox.error
+#MAILBOUNCE mbox.bounce
+
+REMAIL y
+MIDDLEMAN $middle
+
+BINFILTER $binfilter
+AUTOBLOCK $autoblock
+
+ERRLOG error.log
+VERBOSE $verbose
+
+# Remailer name and addresses
+REMAILERADDR $RMA
+ANONADDR $RAA
+COMPLAINTS $CA
+
+SHORTNAME $SN
+REMAILERNAME $RMN
+ANONNAME $RAN
+
+# Supported formats:
+MIX $mix
+PGP $pgp
+UNENCRYPTED $unencrypted
+
+# Maximum message size in kB (0 for no limit):
+SIZELIMIT 0
+
+# Usenet news:
+NEWS $news
+ORGANIZATION $orga
+MID $mid
+
+# Remailing strategy:
+SENDPOOLTIME 15m
+POOLSIZE 45
+RATE 65
+INDUMMYP 10
+OUTDUMMYP 90
+CHAIN *,*,*,*
+IDEXP 7d
+PACKETEXP 7d
+
+$PASSPHRASE
+
+END
+
+fi # not yet installed
+
+
+REPLACE="s/%RMN/$RMN/g;s/%RMA/$RMA/g;s/%CA/$CA/g;s/%RAA/$RAA/g"
+if [ "$installed" = "n" ]
+then
+ cd "$MIXCFG"
+ if [ ! -f "$MIXDEST/help.txt" ]
+ then
+ sed "$REPLACE" < intro.hlp >"$MIXDEST/help.txt"
+ if [ "$mix" = y ]
+ then
+ sed "$REPLACE" < mix.hlp >>"$MIXDEST/help.txt"
+ fi
+ if [ "$unencrypted" = y ]
+ then
+ sed "$REPLACE" < type1.hlp >>"$MIXDEST/help.txt"
+ if [ "$pgp" = y ]
+ then
+ sed "$REPLACE" < pgp.hlp >>"$MIXDEST/help.txt"
+ fi
+ elif [ "$pgp" = y ]
+ then
+ sed "$REPLACE" < pgponly.hlp >>"$MIXDEST/help.txt"
+ fi
+ if [ "$post" = y ]
+ then
+ if [ "$pgp" = y -o "$unencrypted" = y ]
+ then
+ sed "$REPLACE" < news.hlp >>"$MIXDEST/help.txt"
+ fi
+ fi
+ sed "$REPLACE" < end.hlp >>"$MIXDEST/help.txt"
+ fi
+
+ for i in *.txt.in
+ do
+ j=`echo $i | sed 's/\.in$//'`
+ if [ ! -f "$MIXDEST/$j" ]
+ then
+ sed "$REPLACE" < "$i" >"$MIXDEST/$j"
+ fi
+ done
+ cd "$MIXDEST"
+fi
+
+echo
+if [ ! -f secring.mix ]
+then
+ echo "Generating secret keys. This may take a while..."
+else
+ echo "Updating secret keys..."
+fi
+./mixmaster -K
+if [ -f key.txt ]
+then
+ echo "Done."
+ echo
+else
+ echo "Installation failed. Please consult the Mixmaster documentation."
+ exit 1
+fi
+
+if [ "$system" = msdos -o "$system" = win32 ]
+then
+ exit
+fi
+
+umask 033
+
+# Set .forward?
+#
+set=y
+# FIXME -- Mixmastger should run in daemon mode, not from procmail
+# Make the Install script do that.
+
+if grep procmail ~/.forward >/dev/null 2>/dev/null
+then
+ if grep mix ~/.procmailrc >/dev/null 2>/dev/null
+ then
+ echo "Mixmaster is installed in your .procmailrc file."
+ set=n
+ fi
+fi
+
+if [ "$set" = y -a -f ~/.forward ]
+then
+ echo "Your current .forward is:"
+ cat ~/.forward
+ echo
+ if grep mix ~/.forward >/dev/null 2>/dev/null
+ then
+ echo "Mixmaster already is installed in your .forward file."
+ set=n
+ elif [ "$mbox" != "" ]
+ then
+ if echo "$mbox" | grep '|' >/dev/null 2>/dev/null
+ then
+ echo "Mixmaster will pipe messages to $mbox"
+ elif echo $mbox | grep '@' >/dev/null 2>/dev/null
+ then
+ echo "Mixmaster will forward messages to $mbox"
+ else
+ echo "Mixmaster will store messages to $mbox"
+ fi
+ fi
+fi
+
+if [ "$set" = y ]
+then
+ echo "Set .forward to the following line:"
+ echo "\"|${MIXDEST}/mixmaster -RM\""
+ if [ -f ~/.forward ]
+ then
+ readln "Overwrite now?" n
+ else
+ readln "Do that now?" n
+ fi
+ if [ "$ans" = "y" ]
+ then
+ echo "\"|${MIXDEST}/mixmaster -RM\"" >~/.forward
+ fi
+fi
+
+#FIXME -- we need a second script that can re-generate help files
+# when the conf changes.
+
+if [ "$RMA" != "" ]
+then
+ echo "
+Mixmaster will send the following files as auto-replies:
+Mail to <$RMA> with Subject: remailer-help => help.txt"
+ echo "Mail to <$RMA> with Subject: remailer-adminkey => adminkey.txt
+Remember to add your Remailer Admin public PGP key to the adminkey.txt file."
+ if [ "$autoblock" = y ]
+ then
+ echo "Mail to <$RMA> with line DESTINATION-BLOCK => blocked.txt"
+ fi
+ if [ "$autoreply" = y ]
+ then
+ echo "Other mail to <$RMA> => usage.txt"
+ echo
+ if [ "$CA" != "$RMA" ]
+ then
+ echo "If you arrange for mail to <$CA> and <$RAA>
+to be forwarded to <$RMA>:
+Mail to <$CA> => abuse.txt
+Mail to <$RAA> => reply.txt"
+ fi
+ fi
+fi
+
+echo
+echo "Mixmaster installation complete."
+
diff --git a/README b/README
@@ -0,0 +1,191 @@
+Mixmaster 3.0 -- anonymous remailer software -- (C) 1999 - 2000 Anonymizer Inc.
+ (C) 2000-2008 The Mixmaster Development Team
+-------------------------------------------------------------------------------
+
+This program consists of
+
+* a remailer client:
+
+ The remailer client supports sending anonymous mail using Cypherpunk and
+ Mixmaster remailers. It supports OpenPGP encryption (compatible with PGP 2,
+ PGP 5 and up, and GnuPG).
+
+ The client can be used with a menu-based user interface and with command line
+ options.
+
+* a remailer:
+
+ The remailer supports the Cypherpunk and Mixmaster message formats. It can
+ be integrated with the mail delivery system of Unix-based computers or use
+ the POP3 and SMTP protocols for mail transfer. Mixmaster includes an
+ automated abuse-handling system.
+
+Please report any problems via the bug and patch trackers at
+http://sourceforge.net/projects/mixmaster/
+
+
+Installation:
+------------
+
+Libraries:
+
+ Mixmaster requires the libraries OpenSSL, zlib, and pcre.
+
+ If you want to use the menu-based user interface, you also need the ncurses
+ library. If these libraries are not installed on your system, you will need
+ to obtain the latest versions from the sources below and extract them in the
+ the Src/ directory first.
+
+ OpenSSL is available from http://www.openssl.org/source/
+
+ Ncurses can be obtained from http://ftp.gnu.org/pub/gnu/ncurses/
+
+ The Perl Compatable Regular Expressions library can be obtained from
+ ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
+
+ The zlib compression libraries can be obtained from
+ http://www.gzip.org/zlib/
+
+To install or upgrade Mixmaster, type `./Install'.
+
+Mixmaster clients rely on pingers to compile statistics and keyrings for
+currently operating remailers. A list of public pingers can be obtained from
+http://www.noreply.org/allpingers/.
+
+Alternatively clients can operate their own pingers to generate statistics.
+Pinger software can be obtained from http://www.palfrader.org/echolot/. If you
+choose this option, please publish the pinger results for the benefit of other
+Mixmaster users and notify the metastats maintainer at admin@mixmin.net.
+
+The required files published by pingers are:-
+ pubring.asc Type 1 remailer keys
+ pubring.mix Type 2 remailer keys
+ rlist.txt List of reliable type 1 remailers
+ mlist.txt List of reliable type 2 remailers
+ type2.list List of known type 2 remailers (optional)
+
+Using the remailer client:
+-------------------------
+
+To use the menu-based user interface, simply run `mixmaster'. To send an
+anonymous or pseudonymous reply to a message from within your mail or news
+reader, you can pipe it to `mixmaster'.
+
+The interactive mode supports sending mail and contains a simple mail reading
+function. OpenPGP messages are encrypted and decrypted automatically.
+
+In the non-interactive mode, Mixmaster reads a message from a file or from its
+standard input. The command line options are described in the manual page
+(mixmaster.1).
+
+
+Mixmaster as a remailer:
+-----------------------
+
+The Mixmaster remailer can be installed on any account that can receive mail.
+Non-remailer messages will be delivered as usual. If you have root access, you
+may want to create a new user (e.g., `remailer') and install Mixmaster under
+that user id.
+
+The Install script provides a simple way to set up the remailer. More
+information about configuring Mixmaster can be found in the manual page.
+Typically, incoming mail is piped to "mixmaster -RM". In a UUCP setting, it may
+be useful to use just "mixmaster -R", and run "mixmaster -S" once all messages
+have arrived.
+
+Announcing a new remailer to the public is most commonly done by posting the
+remailer keys and capabilities to alt.privacy.anon-server as well as the
+"remops" mailing list. Information about the remops list can be found here:
+http://lists.mixmin.net/mailman/listinfo/remops
+
+
+Installation problems:
+---------------------
+
+In case one of the libraries Mixmaster uses is installed incorrectly on your
+system, place the library source code (available from the locations listed
+above) in the Src directory, remove the old Makefile, run the Install script
+again and answer `y' when asked whether to use the source code.
+
+The ncurses library can use termcap and terminfo databases. The Mixmaster
+Install script tries to find out whether terminfo is available. If you get a
+"Can't open display" error when starting the Mixmaster menu, run "./configure
+--enable-termcap; make lib/libncurses.a" in the ncurses directory.
+
+
+Security notes:
+--------------
+
+The ciphers and the anonymizing mix-net protocol used in Mixmaster correspond
+to the state of the art (see the Security Considerations section of the
+Mixmaster Protocol specification for details). However, no security proofs
+exist for any practical cryptosystem. It is unlikely that their security will
+be broken, but there is no "perfect security". Software can also contain
+implementation errors. The complete Mixmaster source code is available for
+public review, so that everyone can verify what the program does, and it is
+unlikely that security related errors or secret back doors in the software
+would go unnoticed.
+
+No software is secure if run in an insecure environment. For that reason you
+must make sure that there is no malicious software (such as viruses) running on
+your computer. Deleted files and even passphrases can in many cases be read
+from the hard disk if an adversary has access to the computer. The use of disk
+encryption programs is recommended to avoid this risk.
+
+Anonymous messages are secure as long as at least one of the remailers you use
+in a chain is honest. You can use up to 20 remailers in a chain, but
+reliability and speed decrease with longer chains. Four is a reasonable number
+of remailers to use. Many remailer operators sign their keys. You should verify
+those signatures with OpenPGP to make sure that you have the actual remailer
+keys.
+
+Anonymous keys usually cannot be introduced to the OpenPGP web of trust without
+giving up anonymity. For that reason, this client will use any OpenPGP key
+found on the key ring, whether it is certified or not. Your key ring must not
+contain any invalid keys when used with this program.
+
+If you want to use a pseudonym, the client will ask you for a passphrase to
+protect the nym database. Your passphrase should be long, and hard to guess.
+Anyone who gets hold of your nym database and private keys and can determine
+the passphrase will be able to compromise your pseudonymous identities. Note
+that some operating systems may store your passphrase on your hard disk in
+clear.
+
+While a good client passphrase can protect your keys if someone gets hold of
+your files, the remailer passphrase offers only casual protection for the
+remailer keys. If you install a remailer, the remailer passphrase must be
+different from your private passphrases.
+
+Note that nym.alias.net style nym-servers are trivially breakable by an
+adversary performing a long-term intersection attack. Discussion of
+these attacks can be found in section 4.2 of The Pynchon Gate, by
+Sassaman, Cohen, and Mathewson, 2005. Use of Type I remailers for any
+purpose is discouraged.
+
+
+Copyright:
+---------
+
+Mixmaster may be redistributed and modified under certain conditions. This
+software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
+either express or implied. See the file COPYRIGHT for details.
+
+A license is required to use the IDEA(TM) algorithm for commercial purposes;
+see the file idea.txt for details.
+
+Mixmaster uses the compression library zlib by Jean-loup Gailly and Mark Adler,
+the free ncurses library and the regex library by Philip Hazel. This product
+includes cryptographic software written by Eric Young (eay@cryptsoft.com). This
+product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit (http://www.OpenSSL.org/). For some platforms: This product
+includes software developed by the University of California, Berkeley and its
+contributors.
+
+Additionally, this software uses code provided by the members of the
+Mixmaster development team. The members respectively hold the copyright
+to the code in question, having elected to make it available under the
+Mixmaster license.
+
+All trademarks are the property of their respective owners.
+
+$Id: README 974 2008-03-03 17:40:11Z rabbi $
diff --git a/Src/Makefile.deps b/Src/Makefile.deps
@@ -0,0 +1,46 @@
+# Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+# Mixmaster may be redistributed and modified under certain conditions.
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+# ANY KIND, either express or implied. See the file COPYRIGHT for
+# details.
+
+# $Id: $
+
+buffers.o: mix3.h config.h version.h mix.h
+chain.o: mix3.h config.h version.h mix.h
+chain1.o: mix3.h config.h version.h mix.h pgp.h
+chain2.o: mix3.h config.h version.h mix.h
+chain3.o: mix3.h config.h version.h mix.h
+compress.o: mix3.h config.h version.h mix.h
+crypto.o: mix3.h config.h version.h mix.h crypto.h
+dllmain.o: mix3.h config.h version.h mix.h
+dummy.o: mix3.h config.h version.h mix.h
+keymgt.o: mix3.h config.h version.h mix.h
+mail.o: mix3.h config.h version.h mix.h
+maildir.o: mix3.h config.h version.h mix.h
+main.o: mix3.h config.h version.h mix.h
+menu.o: menu.h mix3.h config.h version.h mix.h
+menunym.o: menu.h mix3.h config.h version.h mix.h
+menusend.o: menu.h mix3.h config.h version.h mix.h
+menuutil.o: menu.h mix3.h config.h version.h mix.h
+mime.o: mix3.h config.h version.h mix.h
+mix.o: mix3.h config.h version.h mix.h menu.h
+nym.o: mix3.h config.h version.h mix.h pgp.h
+pgp.o: mix3.h config.h version.h mix.h pgp.h
+pgpcreat.o: mix3.h config.h version.h mix.h pgp.h crypto.h
+pgpdata.o: mix3.h config.h version.h mix.h pgp.h crypto.h
+pgpdb.o: mix3.h config.h version.h mix.h pgp.h
+pgpget.o: mix3.h config.h version.h mix.h pgp.h crypto.h
+mpgp.o: mix3.h config.h version.h mix.h pgp.h
+pool.o: mix3.h config.h version.h mix.h
+random.o: mix3.h config.h version.h mix.h crypto.h
+rem.o: mix3.h config.h version.h mix.h
+rem1.o: mix3.h config.h version.h mix.h
+rem2.o: mix3.h config.h version.h mix.h
+rem3.o: mix3.h config.h version.h mix.h
+remailer.o: mix.h
+rfc822.o: mix3.h config.h version.h mix.h
+rndseed.o: mix3.h config.h version.h mix.h
+stats.o: mix3.h config.h version.h mix.h
+util.o: mix3.h config.h version.h mix.h
diff --git a/Src/Makefile.in b/Src/Makefile.in
@@ -0,0 +1,83 @@
+# Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+# Mixmaster may be redistributed and modified under certain conditions.
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+# ANY KIND, either express or implied. See the file COPYRIGHT for
+# details.
+
+# $Id: Makefile.in 647 2003-10-25 23:34:13Z weasel $
+
+# Edit according to the libraries you want to use:
+INC = %INC
+DEF = %DEF -DUSE_SOCK %MIXDIR
+LIBS = %LIBS
+LDFLAGS = %LDFLAGS
+
+OPT = -g -Wall
+# OPT = -g -pg -Wall -DDEBUG
+# OPT = -O2 -Wall
+
+CFLAGS = $(INC) $(DEF) $(OPT)
+CC = gcc
+AR = ar rc
+RANLIB = ranlib
+#MAKE = make
+
+OBJ = mix.o rem.o rem1.o rem2.o chain.o chain1.o chain2.o nym.o pgp.o pgpdb.o pgpdata.o pgpget.o pgpcreat.o pool.o mail.o rfc822.o mime.o keymgt.o compress.o stats.o crypto.o random.o util.o buffers.o maildir.o parsedate.tab.o
+
+MIXOBJ = rndseed.o menu.o menusend.o menunym.o menuutil.o menustats.o
+NOMENUOBJ = rndseed.o dummy.o
+WINOBJ = winmain.o winutil.o
+
+all: mixmaster
+
+mixmaster: $(OBJ) $(MIXOBJ) main.o $(LIBS)
+ $(CC) $(OBJ) $(MIXOBJ) main.o $(LIBS) $(LDFLAGS) -o mixmaster
+
+libmix.a: $(OBJ) $(MIXOBJ) dllmain.o
+ $(AR) libmix.a $(OBJ) $(MIXOBJ) dllmain.o
+
+libmix32.a: libmix.a mixlib.def
+ dllwrap --dllname mixlib.dll --def mixlib.def --output-lib libmix32.a libmix.a zlib-1.1.4/libz.a pcre-2.08/libpcre.a openssl/libeay32.a -lwsock32
+
+dllmix: main.o libmix32.a
+ $(CC) main.o libmix32.a -o dllmix
+
+winmix.exe: $(WINOBJ) libmix32.a
+ $(CC) $(WINOBJ) libmix32.a -lgdi32 -luser32 $(LDFLAGS) -o mixmaster.exe
+
+winmix: winmenu.res #winmix.exe
+ rsrc winmenu.res mixmaster.exe
+
+winmenu.o: winmenu.rc winmenu.h
+ windres winmenu.rc winmenu.o
+
+remailer: $(OBJ) $(NOMENUOBJ) remailer.o $(LIBS)
+ $(CC) $(OBJ) $(NOMENUOBJ) remailer.o $(LIBS) $(LDFLAGS) -o remailer
+
+mpgp: $(OBJ) $(NOMENUOBJ) mpgp.o $(LIBS)
+ $(CC) $(OBJ) $(NOMENUOBJ) mpgp.o $(LIBS) $(LDFLAGS) -o mpgp
+
+test: $(OBJ) test.o $(NOMENUOBJ) $(LIBS)
+ $(CC) $(OBJ) test.o $(NOMENUOBJ) $(LIBS) $(LDFLAGS) -o test
+
+clean:
+ -rm -f *.o *.a *.res *~ mixmaster mix *.exe remailer test mpgp core gmon.out
+
+allclean: clean
+ -rm -f Makefile
+
+distclean: allclean
+
+ci: clean
+ cd ~/src/mix3; ci -l * Mix/* Mix/Src/*; echo
+
+parsedate.tab.c: parsedate.y
+ @echo Expect 6 shift/reduce conflicts
+ bison parsedate.y
+
+parsedate: parsedate.tab.c
+ gcc -DTEST parsedate.tab.c -o parsedate
+
+
+include Makefile.deps
diff --git a/Src/buffers.c b/Src/buffers.c
@@ -0,0 +1,816 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Dynamically allocated buffers
+ $Id: buffers.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef WIN32
+#include <io.h>
+#endif /* WIN32 */
+#include <assert.h>
+#ifdef POSIX
+#include <unistd.h>
+#endif /* POSIX */
+
+static void fail(void)
+{
+ errlog(ERRORMSG, "Out of memory!\n");
+ abort();
+}
+
+#define space 128 /* allocate some additional space */
+
+static void alloc(BUFFER *b)
+{
+ b->data = malloc(space);
+ if (b->data == NULL)
+ fail();
+ b->data[0] = 0;
+ b->size = space;
+}
+
+#undef buf_new /* DEBUG */
+BUFFER *buf_new(void)
+{
+ BUFFER *b;
+
+ b = malloc(sizeof(BUFFER));
+ if (b == NULL)
+ fail();
+ alloc(b);
+ b->length = 0;
+ b->ptr = 0;
+ b->sensitive = 0;
+
+ return (b);
+}
+
+#ifdef DEBUG
+static void sanity_check(BUFFER *b)
+{
+ assert(b != NULL);
+ assert(b->size > 0);
+ assert(b->data != NULL);
+ assert(b->length >= 0 && b->length < b->size);
+ assert(b->ptr >= 0 && b->ptr <= b->length);
+}
+#else /* not DEBUG */
+#define sanity_check(arg)
+#endif /* else not DEBUG */
+
+int buf_reset(BUFFER *buffer)
+{
+ sanity_check(buffer);
+
+ buffer->length = 0;
+ buffer->ptr = 0;
+ if (buffer->sensitive)
+ memset(buffer->data, 0, buffer->size);
+ free(buffer->data);
+ alloc(buffer);
+ return (0);
+}
+
+int buf_free(BUFFER *buffer)
+{
+ int err = 0;
+
+ if (buffer->sensitive)
+ memset(buffer->data, 0, buffer->size);
+ free(buffer->data);
+ free(buffer);
+ return (err);
+}
+
+int buf_clear(BUFFER *buffer)
+{
+ sanity_check(buffer);
+ buffer->data[0] = '\0';
+ buffer->length = 0;
+ buffer->ptr = 0;
+ return (0);
+}
+
+int buf_append(BUFFER *buffer, byte *msg, int len)
+{
+ assert(len >= 0);
+ sanity_check(buffer);
+
+ if (buffer->length + len >= buffer->size) {
+ register byte *new;
+ register long newsize;
+
+ newsize = 2 * buffer->length; /* double buffer size */
+ if (newsize < buffer->length + len + space)
+ newsize = buffer->length + len + space;
+ new = malloc(newsize);
+ if (new == NULL)
+ fail();
+ memcpy(new, buffer->data, buffer->length);
+ if (buffer->sensitive)
+ memset(buffer->data, 0, buffer->size);
+ free(buffer->data);
+ buffer->data = new;
+ buffer->size = newsize;
+ }
+ if (msg != NULL)
+ memcpy(buffer->data + buffer->length, msg, len);
+ buffer->length += len;
+
+ buffer->data[buffer->length] = 0;
+ return (0);
+}
+
+int buf_appendrnd(BUFFER *to, int n)
+{
+ buf_append(to, NULL, n);
+ rnd_bytes(to->data + to->length - n, n);
+ return (0);
+}
+
+int buf_appendzero(BUFFER *to, int n)
+{
+ buf_append(to, NULL, n);
+ memset(to->data + to->length - n, 0, n);
+ return (0);
+}
+
+int buf_setrnd(BUFFER *b, int n)
+{
+ buf_prepare(b, n);
+ rnd_bytes(b->data, n);
+ return (0);
+}
+
+int buf_cat(BUFFER *to, BUFFER *from)
+{
+ return (buf_append(to, from->data, from->length));
+}
+
+int buf_set(BUFFER *to, BUFFER *from)
+{
+ buf_reset(to);
+ return (buf_cat(to, from));
+}
+
+int buf_appendc(BUFFER *to, byte b)
+{
+ return (buf_append(to, &b, 1));
+}
+
+int buf_rest(BUFFER *to, BUFFER *from)
+{
+ assert(from != to);
+ return (buf_append(to, from->data + from->ptr, from->length - from->ptr));
+}
+
+int buf_appends(BUFFER *buffer, char *s)
+{
+ return (buf_append(buffer, s, strlen(s)));
+}
+
+int buf_sets(BUFFER *buffer, char *s)
+{
+ buf_clear(buffer);
+ return (buf_appends(buffer, s));
+}
+
+int buf_setc(BUFFER *buffer, byte c)
+{
+ buf_clear(buffer);
+ return (buf_appendc(buffer, c));
+}
+
+int buf_nl(BUFFER *b)
+{
+ return (buf_append(b, "\n", 1));
+}
+
+int buf_vappendf(BUFFER *b, char *fmt, va_list args)
+{
+ for (; *fmt != '\0'; fmt++)
+ if (*fmt == '%') {
+ int lzero = 0;
+ int longvar = 0;
+ int len = 0;
+
+ for (;;) {
+ if (*++fmt == '\0')
+ return (-1);
+ if (*fmt == '%') {
+ buf_appendc(b, '%');
+ break;
+ } else if (*fmt == 'b') { /* extension of printf */
+ buf_cat(b, va_arg(args, BUFFER *));
+
+ break;
+ } else if (*fmt == 'c') {
+ buf_appendc(b, va_arg(args, int));
+
+ break;
+ } else if (*fmt == 's') {
+ buf_appends(b, va_arg(args, char *));
+
+ break;
+ } else if (*fmt == 'd' || *fmt == 'X') {
+ int base, val, sign = 0;
+ BUFFER *out;
+
+ out = buf_new();
+ base = *fmt == 'd' ? 10 : 16;
+ if (longvar)
+ val = va_arg(args, long);
+
+ else
+ val = va_arg(args, int);
+
+ if (val < 0)
+ sign = 1, val = -val;
+ do {
+ if (val % base > 9)
+ buf_appendc(out, val % base - 10 + 'A');
+ else
+ buf_appendc(out, val % base + '0');
+ val /= base;
+ } while (val > 0);
+ if (sign)
+ len--;
+ while (len-- > out->length)
+ buf_appendc(b, lzero ? '0' : ' ');
+ if (sign)
+ buf_appendc(b, '-');
+ for (len = out->length - 1; len >= 0; len--)
+ buf_appendc(b, out->data[len]);
+ buf_free(out);
+ break;
+ } else if (*fmt == 'l')
+ longvar = 1;
+ else if (*fmt == '0' && len == 0)
+ lzero = 1;
+ else if (isdigit(*fmt))
+ len = len * 10 + *fmt - '0';
+ else
+ assert(0);
+ }
+ } else
+ buf_appendc(b, *fmt);
+ return (0);
+}
+
+int buf_setf(BUFFER *b, char *fmt, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ buf_clear(b);
+ ret = buf_vappendf(b, fmt, args);
+ va_end(args);
+ return (ret);
+}
+
+int buf_appendf(BUFFER *b, char *fmt, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ ret = buf_vappendf(b, fmt, args);
+ va_end(args);
+ return (ret);
+}
+
+int buf_pad(BUFFER *buffer, int size)
+{
+ assert(size - buffer->length >= 0);
+ buf_appendrnd(buffer, size - buffer->length);
+ return (0);
+}
+
+int buf_prepare(BUFFER *buffer, int size)
+{
+ buf_clear(buffer);
+ buf_append(buffer, NULL, size);
+ return (0);
+}
+
+int buf_read(BUFFER *outmsg, FILE *infile)
+{
+ char buf[BUFSIZE];
+ int n;
+ int err = -1;
+
+ assert(infile != NULL);
+ sanity_check(outmsg);
+
+ for (;;) {
+ n = fread(buf, 1, BUFSIZE, infile);
+ if (n > 0)
+ err = 0;
+ buf_append(outmsg, buf, n);
+ if (n < BUFSIZE)
+ break;
+#ifdef BUFFER_MAX
+ if (outmsg->length > BUFFER_MAX) {
+ errlog(ERRORMSG, "Message file too large. Giving up.\n");
+ return (1);
+ }
+#endif /* BUFFER_MAX */
+ }
+
+#ifdef WIN32
+ if (isatty(fileno(infile)) && isatty(fileno(stdout)))
+ printf("\n");
+#endif /* WIN32 */
+
+ return (err);
+}
+
+int buf_write(BUFFER *buffer, FILE *out)
+{
+ assert(out != NULL);
+ sanity_check(buffer);
+
+ return (fwrite(buffer->data, 1, buffer->length, out) == buffer->length
+ ? 0 : -1);
+}
+
+int buf_write_sync(BUFFER *buffer, FILE *out)
+{
+ int ret = 0;
+
+ if (buf_write(buffer, out) == -1) {
+ fclose(out);
+ return -1;
+ }
+
+ if (fflush(out) != 0)
+ ret = -1;
+
+#ifdef POSIX
+ /* dir entry not synced */
+ if (fsync(fileno(out)) != 0)
+ ret = -1;
+#endif /* POSIX */
+
+ if (fclose(out) != 0)
+ ret = -1;
+
+ return ret;
+}
+
+int buf_rewind(BUFFER *buffer)
+{
+ sanity_check(buffer);
+
+ buffer->ptr = 0;
+ return (0);
+}
+
+int buf_get(BUFFER *buffer, BUFFER *to, int n)
+{
+ sanity_check(buffer);
+ sanity_check(to);
+ assert(n > 0);
+ assert(buffer != to);
+
+ buf_clear(to);
+ if (buffer->length - buffer->ptr < n)
+ return (-1);
+ buf_append(to, buffer->data + buffer->ptr, n);
+ buffer->ptr += n;
+ return (0);
+}
+
+int buf_getc(BUFFER *buffer)
+{
+ sanity_check(buffer);
+ if (buffer->ptr == buffer->length)
+ return (-1);
+ else
+ return (buffer->data[buffer->ptr++]);
+}
+
+void buf_ungetc(BUFFER *buffer)
+{
+ sanity_check(buffer);
+ if (buffer->ptr > 0)
+ buffer->ptr--;
+}
+
+int buf_getline(BUFFER *buffer, BUFFER *line)
+{
+ register int i;
+ int ret = 0;
+ int nl = 0;
+
+ sanity_check(buffer);
+
+ if (line != NULL)
+ buf_clear(line);
+ if (buffer->ptr == buffer->length)
+ return (-1);
+
+ for (i = buffer->ptr; i < buffer->length; i++) {
+ if (buffer->data[i] > '\r')
+ continue;
+ if (buffer->data[i] == '\0' || buffer->data[i] == '\n') {
+ nl = 1;
+ break;
+ }
+ if (buffer->data[i] == '\r' &&
+ i + 1 <= buffer->length && buffer->data[i + 1] == '\n') {
+ nl = 2;
+ break;
+ }
+ }
+
+ if (line != NULL)
+ buf_append(line, buffer->data + buffer->ptr, i - buffer->ptr);
+ if (i == buffer->ptr)
+ ret = 1;
+ buffer->ptr = i + nl;
+
+ return (ret);
+}
+
+int buf_chop(BUFFER *b)
+{
+ int i;
+
+ sanity_check(b);
+
+ for (i = 0; i < b->length; i++)
+ if (b->data[i] == '\0' || b->data[i] == '\n' ||
+ (b->data[i] == '\r' && i + 1 < b->length &&
+ b->data[i + 1] == '\n'))
+ b->length = i;
+ b->data[b->length] = 0;
+ return (0);
+}
+
+int buf_isheader(BUFFER *buffer)
+{
+ BUFFER *line;
+ long p;
+ int i;
+ int err;
+ int ret;
+
+ line = buf_new();
+ p = buffer->ptr;
+ ret = 0;
+ err = buf_getline(buffer, line);
+ if (err != 0)
+ goto end;
+
+ for (i = 0; i < line->length; i++) {
+ if (line->data[i] == ' ' || line->data[i] == '\t')
+ break;
+ if (line->data[i] == ':') {
+ ret = 1;
+ break;
+ }
+ }
+
+end:
+ buffer->ptr = p;
+ buf_free(line);
+ return(ret);
+}
+
+int buf_getheader(BUFFER *buffer, BUFFER *field, BUFFER *content)
+{
+ BUFFER *line;
+ long p;
+ int i;
+ int err;
+
+ line = buf_new();
+ buf_reset(field);
+ buf_reset(content);
+
+ err = buf_getline(buffer, line);
+ if (err != 0)
+ goto end;
+
+ err = -1;
+ for (i = 0; i < line->length; i++) {
+ if (line->data[i] == ' ' || line->data[i] == '\t')
+ break;
+ if (line->data[i] == ':') {
+ err = 0;
+ break;
+ }
+ }
+ if (err == -1 && bufileft(line, "From ")) {
+ buf_set(field, line);
+ err = 0;
+ }
+ if (err == -1) {
+ /* badly formatted message -- try to process anyway */
+ buf_sets(field, "X-Invalid");
+ buf_set(content, line);
+ err = 0;
+ goto end;
+ }
+ buf_append(field, line->data, i);
+ if (i < line->length)
+ i++;
+ else
+ err = 1;
+ while (i < line->length &&
+ (line->data[i] == ' ' || line->data[i] == '\t'))
+ i++;
+ buf_append(content, line->data + i, line->length - i);
+
+ for (;;) {
+ p = buffer->ptr;
+ if (buf_getline(buffer, line) != 0)
+ break;
+ if (line->data[0] != ' ' && line->data[0] != '\t')
+ break;
+#if 1
+ buf_nl(content);
+ buf_cat(content, line);
+#else /* end of 1 */
+ buf_appendc(content, ' ');
+ buf_appends(content, line->data + 1);
+#endif /* else if not 1 */
+ }
+ buffer->ptr = p;
+end:
+ buf_free(line);
+ return (err);
+}
+
+int buf_appendheader(BUFFER *buffer, BUFFER *field, BUFFER *content)
+{
+ return buf_appendf(buffer, "%b: %b\n", field, content);
+}
+
+int buf_lookahead(BUFFER *buffer, BUFFER *line)
+{
+ long p;
+ int e;
+
+ p = buffer->ptr;
+ e = buf_getline(buffer, line);
+ buffer->ptr = p;
+ return (e);
+}
+
+int buf_eq(BUFFER *b1, BUFFER *b2)
+{
+ sanity_check(b1);
+ sanity_check(b2);
+
+ if (b1->length != b2->length)
+ return (0);
+ if (b1->length > 0 && memcmp(b1->data, b2->data, b1->length) != 0)
+ return (0);
+ return (1);
+}
+
+int buf_ieq(BUFFER *b1, BUFFER *b2)
+{
+ int i;
+ sanity_check(b1);
+ sanity_check(b2);
+
+ if (b1->length != b2->length)
+ return (0);
+ for (i = 0; i < b1->length; i++)
+ if (tolower(b1->data[i]) != tolower(b2->data[i]))
+ return (0);
+ return (1);
+}
+
+void buf_move(BUFFER *dest, BUFFER *src)
+ /* equivalent to buf_set(dest, src); buf_reset(src); */
+{
+ BUFFER temp;
+ sanity_check(src);
+ buf_reset(dest);
+ temp.data = dest->data, temp.size = dest->size;
+ dest->data = src->data, dest->size = src->size, dest->length = src->length;
+ src->data = temp.data, src->size = temp.size, src->length = 0;
+ dest->ptr = 0, src->ptr = 0;
+}
+
+int buf_appendl(BUFFER *b, long l)
+{
+ buf_appendc(b, (l >> 24) & 255);
+ buf_appendc(b, (l >> 16) & 255);
+ buf_appendc(b, (l >> 8) & 255);
+ buf_appendc(b, l & 255);
+ return (0);
+}
+
+int buf_appendl_lo(BUFFER *b, long l)
+{
+ buf_appendc(b, l & 255);
+ buf_appendc(b, (l >> 8) & 255);
+ buf_appendc(b, (l >> 16) & 255);
+ buf_appendc(b, (l >> 24) & 255);
+ return (0);
+}
+
+long buf_getl(BUFFER *b)
+{
+ long l;
+
+ if (b->ptr + 4 > b->length)
+ return (-1);
+ l = buf_getc(b) << 24;
+ l += buf_getc(b) << 16;
+ l += buf_getc(b) << 8;
+ l += buf_getc(b);
+ return (l);
+}
+
+long buf_getl_lo(BUFFER *b)
+{
+ long l;
+
+ if (b->ptr + 4 > b->length)
+ return (-1);
+ l = buf_getc(b);
+ l += buf_getc(b) << 8;
+ l += buf_getc(b) << 16;
+ l += buf_getc(b) << 24;
+
+ return (l);
+}
+
+int buf_appendi(BUFFER *b, int i)
+{
+ buf_appendc(b, (i >> 8) & 255);
+ buf_appendc(b, i & 255);
+ return (0);
+}
+
+int buf_appendi_lo(BUFFER *b, int i)
+{
+ buf_appendc(b, i & 255);
+ buf_appendc(b, (i >> 8) & 255);
+ return (0);
+}
+
+int buf_geti(BUFFER *b)
+{
+ int i;
+
+ if (b->ptr + 2 > b->length)
+ return (-1);
+ i = buf_getc(b) << 8;
+ i += buf_getc(b);
+ return (i);
+}
+
+int buf_geti_lo(BUFFER *b)
+{
+ int i;
+
+ if (b->ptr + 2 > b->length)
+ return (-1);
+ i = buf_getc(b);
+ i += buf_getc(b) << 8;
+ return (i);
+}
+
+int buf_getb(BUFFER *b, BUFFER *p)
+{
+ long l;
+
+ l = buf_getl(b);
+ return (buf_get(b, p, l));
+}
+
+int buf_appendb(BUFFER *b, BUFFER *p)
+{
+ long l;
+
+ l = p->length;
+ buf_appendl(b, l);
+ return (buf_cat(b, p));
+}
+
+int bufleft(BUFFER *b, char *k) {
+ return(strleft(b->data, k));
+}
+
+int bufileft(BUFFER *b, char *k) {
+ return(strileft(b->data, k));
+}
+
+int buffind(BUFFER *b, char *k) {
+ return(strfind(b->data, k));
+}
+
+int bufifind(BUFFER *b, char *k) {
+ return(strifind(b->data, k));
+}
+
+int bufiright(BUFFER *b, char *k) {
+ int l = strlen(k);
+ if (l <= b->length)
+ return (strieq(b->data + b->length - l, k));
+ return(0);
+}
+
+int bufeq(BUFFER *b, char *k) {
+ return(streq(b->data, k));
+}
+
+int bufieq(BUFFER *b, char *k) {
+ return(strieq(b->data, k));
+}
+
+/* void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest,
+ * int from, int len);
+ *
+ * Cut a chunk out of the buffer.
+ *
+ * Starting with from, len bytes are cut out of buffer. The chunk
+ * of text that has been cut out is returned in cut_out, the
+ * remainings of buffer are returned in rest.
+ *
+ * This function was added by Gerd Beuster. (gb@uni-koblenz.de)
+ */
+
+void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest,
+ int from, int len){
+
+ assert((len >= 0) && (from >= 0));
+ assert(from+len <= buffer->length);
+ assert(cut_out != rest);
+
+ buffer->ptr = 0;
+ if(from > 0)
+ buf_get(buffer, rest, from);
+ buf_get(buffer, cut_out, len);
+ buf_rest(rest, buffer);
+}
+
+
+#ifdef DEBUG
+/* check for memory leaks */
+#undef malloc
+#undef free
+void *malloc(size_t size);
+void free(void *ptr);
+#define max 100000
+static int n=0;
+static void *m[max];
+static char *mm[max];
+
+void mix3_leaks(void) {
+ int i, ok=1;
+ for (i = 0; i < n; i++)
+ if (m[i]) {
+ fprintf(stderr, "Leak [%d] %s\n", i, mm[i]);
+ ok = 0;
+ }
+ if (ok)
+ fprintf(stderr, "No memory leaks.\n");
+}
+
+void *mix3_malloc(size_t size) {
+ void *ptr;
+ if (n == 0)
+ atexit(mix3_leaks);
+ ptr = malloc(size);
+ if (n >= max) abort();
+ m[n++] = ptr;
+ mm[n] = "?";
+ return(ptr);
+}
+
+void mix3_free(void *ptr) {
+ int i;
+ for (i = 0; i < n; i++)
+ if (m[i] == ptr) {
+ m[i] = 0;
+ break;
+ }
+ free(ptr);
+}
+
+BUFFER *mix3_bufnew(char *file, int line, char *func) {
+ mm[n] = malloc(strlen(file) + strlen(func) + 15);
+ sprintf(mm[n], "in %s %s:%d", func, file, line);
+ return(buf_new());
+}
+#endif /* DEBUG */
diff --git a/Src/chain.c b/Src/chain.c
@@ -0,0 +1,384 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Prepare messages for remailer chain
+ $Id: chain.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdlib.h>
+
+void clienterr(BUFFER *msgbuf, char *err)
+{
+ if (msgbuf) {
+ buf_sets(msgbuf, "Error: ");
+ buf_appends(msgbuf, err);
+ } else
+ errlog(ERRORMSG, "%s\n", err);
+}
+
+void parse_badchains(int badchains[MAXREM][MAXREM], char *file, char *startindicator, REMAILER *remailer, int maxrem) {
+ int i,j;
+ FILE *list;
+ char line[LINELEN];
+
+ if (!badchains)
+ return;
+
+ for (i = 0; i < maxrem; i++ )
+ for (j = 0; j < maxrem; j++ )
+ badchains[i][j] = 0;
+ list = mix_openfile(TYPE2REL, "r");
+ if (list != NULL) {
+ while (fgets(line, sizeof(line), list) != NULL &&
+ !strleft(line, startindicator)) ;
+ while (fgets(line, sizeof(line), list) != NULL &&
+ strleft(line, "(")) {
+ char *left, *right, *tmp;
+ int lefti, righti;
+
+ left = line + 1;
+ while (*left == ' ')
+ left ++;
+
+ tmp = left + 1;
+ while (*tmp != ' ' && *tmp != '\0' && *tmp != ')')
+ tmp ++;
+ if (*tmp == '\0' || *tmp == ')')
+ /* parsing this line failed */
+ continue;
+ *tmp = '\0';
+
+ right = tmp+1;
+ while (*right == ' ')
+ right ++;
+ tmp = right + 1;
+ while (*tmp != ' ' && *tmp != '\0' && *tmp != ')')
+ tmp ++;
+ if (*tmp == '\0')
+ /* parsing this line failed */
+ continue;
+ *tmp = '\0';
+
+ lefti = -1;
+ righti = -1;
+ for (i = 1; i < maxrem; i++) {
+ if (strcmp(remailer[i].name, left) == 0)
+ lefti = i;
+ if (strcmp(remailer[i].name, right) == 0)
+ righti = i;
+ }
+ if (strcmp(left, "*") == 0)
+ lefti = 0;
+ if (strcmp(right, "*") == 0)
+ righti = 0;
+
+ if (lefti == -1 || righti == -1)
+ /* we don't know about one or both remailers */
+ continue;
+ badchains[lefti][righti] = 1;
+ }
+ fclose(list);
+ /* If some broken chain includes all remailers (*) mark it broken for
+ * every single remailer - this simplifies handling in other places */
+ for (i=1; i < maxrem; i++ ) {
+ if (badchains[0][i])
+ for (j=1; j < maxrem; j++ )
+ badchains[j][i] = 1;
+ if (badchains[i][0])
+ for (j=1; j < maxrem; j++ )
+ badchains[i][j] = 1;
+ }
+ }
+}
+
+
+int chain_select(int hop[], char *chainstr, int maxrem, REMAILER *remailer,
+ int type, BUFFER *feedback)
+{
+ int len = 0;
+ int i, j, k;
+ BUFFER *chain, *selected, *addr;
+ chain = buf_new();
+ selected = buf_new();
+ addr = buf_new();
+
+ if (chainstr == NULL || chainstr[0] == '\0')
+ buf_sets(chain, CHAIN);
+ else
+ buf_sets(chain, chainstr);
+
+ /* put the chain backwards: final hop is in hop[0] */
+
+ for (i = chain->length; i >= 0; i--)
+ if (i == 0 || chain->data[i - 1] == ','
+ || chain->data[i - 1] == ';' || chain->data[i - 1] == ':') {
+ for (j = i; isspace(chain->data[j]);) /* ignore whitespace */
+ j++;
+ if (chain->data[j] == '\0')
+ break;
+
+ if (chain->data[j] == '*')
+ k = 0;
+#if 0
+ else if (isdigit(chain->data[j]))
+ k = atoi(chain->data + j);
+#endif /* 0 */
+ else {
+ buf_sets(selected, chain->data + j);
+ rfc822_addr(selected, addr);
+ buf_clear(selected);
+ buf_getline(addr, selected);
+ if (!selected->length)
+ buf_sets(selected, chain->data + j);
+
+ for (k = 0; k < maxrem; k++)
+ if (((remailer[k].flags.mix && type == 0) ||
+ (remailer[k].flags.cpunk && type == 1) ||
+ (remailer[k].flags.newnym && type == 2)) &&
+ (streq(remailer[k].name, selected->data) ||
+ strieq(remailer[k].addr, selected->data) ||
+ (selected->data[0] == '@' && strifind(remailer[k].addr,
+ selected->data))))
+ break;
+ }
+ if (k < 0 || k >= maxrem) {
+ if (feedback != NULL) {
+ buf_appendf(feedback, "No such remailer: %b", selected);
+ buf_nl(feedback);
+ }
+#if 0
+ k = 0;
+#else /* end of 0 */
+ len = -1;
+ goto end;
+#endif /* else not 0 */
+ }
+ hop[len++] = k;
+ if (len >= 20) { /* array passed in is has length 20 */
+ if (feedback != NULL) {
+ buf_appends(feedback, "Chain too long.\n");
+ }
+ break;
+ }
+ if (i > 0)
+ chain->data[i - 1] = '\0';
+ }
+end:
+ buf_free(chain);
+ buf_free(selected);
+ buf_free(addr);
+ return len;
+}
+
+int chain_randfinal(int type, REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem, int rtype, int chain[], int chainlen, int ignore_constraints_if_necessary)
+{
+ int randavail;
+ int i;
+ int t;
+ int select[MAXREM];
+ int secondtolasthop = (chainlen <= 1 ? -1 : chain[1]);
+ int constraints_ignored = 0;
+
+ t = rtype;
+ if (rtype == 2)
+ t = 1;
+
+start:
+ randavail = 0;
+ /* select a random final hop */
+ for (i = 1; i < maxrem; i++) {
+ select[i] =
+ ((remailer[i].flags.mix && rtype == 0) || /* remailer supports type */
+ (remailer[i].flags.pgp && remailer[i].flags.ek && rtype == 1) ||
+ (remailer[i].flags.newnym && rtype == 2)) &&
+ (remailer[i].info[t].reliability >= 100 * RELFINAL || constraints_ignored ) && /* remailer has sufficient reliability */
+ (remailer[i].info[t].latency <= MAXLAT || constraints_ignored ) && /* remailer has low enough latency */
+ (remailer[i].info[t].latency >= MINLAT || constraints_ignored ) && /* remailer has high enough latency */
+ (type == MSG_NULL || !remailer[i].flags.middle) && /* remailer is not middleman */
+ !remailer[i].flags.star_ex && /* remailer is not excluded from random selection */
+ (remailer[i].flags.post || type != MSG_POST) && /* remailer supports post when this is a post */
+ ((secondtolasthop == -1) || !badchains[secondtolasthop][i]);
+ /* we only have hop or the previous one can send to this (may be random) */
+ randavail += select[i];
+ }
+
+ for (i = 1; i <= DISTANCE; i++)
+ if (i < chainlen && select[chain[i]] && chain[i]) {
+ select[chain[i]] = 0;
+ randavail--;
+ }
+
+ assert(randavail >= 0);
+ if (randavail == 0) {
+ if (ignore_constraints_if_necessary && !constraints_ignored) {
+ errlog(WARNING, "No reliable remailers. Ignoring for randhop\n");
+ constraints_ignored = 1;
+ goto start;
+ };
+ i = -1;
+ } else {
+ do
+ i = rnd_number(maxrem - 1) + 1;
+ while (!select[i]);
+ }
+ return (i);
+}
+
+int chain_rand(REMAILER *remailer, int badchains[MAXREM][MAXREM], int maxrem,
+ int thischain[], int chainlen, int t, int ignore_constraints_if_necessary)
+ /* set random chain. returns 0 if not random, 1 if random, -1 on error */
+/* t... 0 for mixmaster Type II
+ * 1 for cypherpunk Type I
+ */
+{
+ int hop;
+ int err = 0;
+ int constraints_ignored = 0;
+
+ assert(t == 0 || t == 1);
+
+start:
+ for (hop = 0; hop < chainlen; hop++)
+ if (thischain[hop] == 0) {
+ int select[MAXREM];
+ int randavail = 0;
+ int i;
+
+ err = 1;
+ if (hop > 0)
+ assert(thischain[hop-1]); /* we already should have chosen a remailer after this one */
+ for (i = 1; i < maxrem; i++) {
+ select[i] = ((remailer[i].flags.mix && t == 0) || /* remailer supports type */
+ (remailer[i].flags.pgp && remailer[i].flags.ek && t == 1)) &&
+ (remailer[i].info[t].reliability >= 100 * MINREL || constraints_ignored ) && /* remailer has sufficient reliability */
+ (remailer[i].info[t].latency <= MAXLAT || constraints_ignored ) && /* remailer has low enough latency */
+ (remailer[i].info[t].latency >= MINLAT || constraints_ignored ) && /* remailer has high enough latency */
+ !remailer[i].flags.star_ex && /* remailer is not excluded from random selection */
+ !badchains[i][0] && !badchains[i][thischain[hop-1]] && /* remailer can send to the next one */
+ (hop == chainlen-1 || !badchains[thischain[hop+1]][i]);
+ /* we are at the first hop or the previous one can send to this (may be random) */
+ randavail += select[i];
+ }
+
+ for (i = hop - DISTANCE; i <= hop + DISTANCE; i++)
+ if (i >= 0 && i < chainlen && select[thischain[i]] && thischain[i]) {
+ select[thischain[i]] = 0;
+ randavail--;
+ }
+
+
+ assert(randavail >= 0);
+ if (randavail < 1) {
+ if (ignore_constraints_if_necessary && !constraints_ignored) {
+ errlog(WARNING, "No reliable remailers. Ignoring for randhop\n");
+ constraints_ignored = 1;
+ goto start;
+ };
+ err = -1;
+ goto end;
+ }
+ do
+ thischain[hop] = rnd_number(maxrem - 1) + 1;
+ while (!select[thischain[hop]]);
+ }
+end:
+ return (err);
+}
+
+int mix_encrypt(int type, BUFFER *message, char *chainstr, int numcopies,
+ BUFFER *chainlist)
+{
+ return (mix2_encrypt(type, message, chainstr, numcopies, 0, chainlist));
+}
+
+/* float chain_reliablity(char *chain, int chaintype,
+ char *reliability_string);
+ *
+ * Compute reliablity of a chain.
+ *
+ * We get the reliablity of the chain by multiplying the reliablity of
+ * every remailer in the chain. The return value is the reliablity of
+ * the chain, or a negative number if the reliablity can not be
+ * calculated. There are two reasons why may not be able to calculated
+ * the reliablity: A remailer in the chain is selected randomly, or we
+ * don't have statistics about one of the remailers in the chain.
+ * remailer_type indicates the remailer type:
+ * 0 = Mixmaster, 1 = Cypherpunk
+ *
+ * If reliability_string is non-NULL, the reliability is also returned
+ * as a string in this variable. The size of the string must be at
+ * least 9 characters!
+ *
+ * This function has been added by Gerd Beuster. (gb@uni-koblenz.de)
+ *--------------------------------------------------------------------*/
+
+float chain_reliability(char *chain, int chaintype,
+ char *reliability_string){
+
+ float acc_reliability = 1; /* Accumulated reliablity */
+ char *name_start, *name_end; /* temporary pointers used
+ in string scanning */
+ char remailer_name[20]; /* The length of the array is taken from mix3.h. */
+ int error = 0;
+ int maxrem;
+ int i;
+ int previous = -1;
+ REMAILER remailer[MAXREM];
+ int badchains[MAXREM][MAXREM];
+
+ /* chaintype 0=mix 1=ek 2=newnym */
+ assert((chaintype == 0) || (chaintype == 1));
+ maxrem = (chaintype == 0 ? mix2_rlist(remailer, badchains) : t1_rlist(remailer, badchains));
+
+ /* Dissect chain */
+ name_start = chain;
+ name_end = chain;
+ while(*name_end != '\0'){ /* While string not scanned completely */
+ do /* Get next remailer */
+ name_end+=sizeof(char);
+ while( (*name_end != ',') && (*name_end != '\0'));
+ strncpy(remailer_name, name_start,
+ (name_end - name_start) / sizeof(char) + 1*sizeof(char));
+ remailer_name[name_end-name_start]='\0';
+ /* Lookup reliablity for remailer remailer_name */
+ for(i=0;
+ (i < maxrem) && (strcmp(remailer[i].name, remailer_name) != 0);
+ i++);
+ if(!strcmp(remailer[i].name, remailer_name)) { /* Found it! */
+ acc_reliability *=
+ ((float) remailer[i].info[chaintype].reliability) / 10000;
+ if (previous != -1) {
+ if (badchains[previous][i] || badchains[0][i])
+ acc_reliability = 0;
+ }
+ previous = i;
+ } else
+ error = 1; /* Did not find this remailer. We can't calculate
+ the reliablity for the whole chain. */
+ name_start = name_end+sizeof(char);
+ }
+
+ if(error || (name_start==name_end))
+ acc_reliability = -1;
+
+ /* Convert reliability into string, if appropriate */
+ if(reliability_string){
+ if(acc_reliability < 0)
+ sprintf(reliability_string, " n/a ");
+ else{
+ sprintf(reliability_string, "%6.2f", acc_reliability*100);
+ *(reliability_string+6*sizeof(char)) = '%';
+ }
+ }
+
+ return acc_reliability;
+}
+
diff --git a/Src/chain1.c b/Src/chain1.c
@@ -0,0 +1,301 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Encrypt message for Cypherpunk remailer chain
+ $Id: chain1.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include "pgp.h"
+#include <string.h>
+#include <ctype.h>
+
+#define N(X) (isdigit(X) ? (X)-'0' : 0)
+
+int t1_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM])
+{
+ FILE *list, *excl;
+ int i, listed = 0;
+ int n = 0;
+ char line[2 * LINELEN], l2[LINELEN], name[LINELEN], *flags;
+ BUFFER *starex;
+
+ starex = buf_new();
+ excl = mix_openfile(STAREX, "r");
+ if (excl != NULL) {
+ buf_read(starex, excl);
+ fclose(excl);
+ }
+
+ list = mix_openfile(TYPE1LIST, "r");
+ if (list == NULL) {
+ buf_free(starex);
+ return (-1);
+ }
+
+ while (fgets(line, sizeof(line), list) != NULL && n < MAXREM) {
+ if (strleft(line, "$remailer") &&
+ strchr(line, '<') && strchr(line, '>') &&
+ strchr(line, '{') && strchr(line, '{') + 4 < strchr(line, '}')) {
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+ if (line[strlen(line) - 1] == '\r')
+ line[strlen(line) - 1] = '\0';
+ while (line[strlen(line) - 1] == ' ')
+ line[strlen(line) - 1] = '\0';
+ if (line[strlen(line) - 1] != ';'
+ && fgets(l2, sizeof(l2), list) != NULL)
+ strcatn(line, l2, LINELEN);
+ flags = strchr(line, '>');
+ strncpy(name, strchr(line, '{') + 2,
+ strchr(line, '}') - strchr(line, '{') - 3);
+ name[strchr(line, '}') - strchr(line, '{') - 3] = '\0';
+ name[20] = '\0';
+
+ for (i = 1; i <= n; i++)
+ if (streq(name, remailer[i].name))
+ break;
+ if (i > n) {
+ /* not in mix list */
+ n++;
+ strcpy(remailer[i].name, name);
+ strncpy(remailer[i].addr, strchr(line, '<') + 1,
+ strchr(line, '>') - strchr(line, '<'));
+ remailer[i].addr[strchr(line, '>') - strchr(line, '<') - 1]
+ = '\0';
+ remailer[i].flags.mix = 0;
+ remailer[i].flags.post = strifind(flags, " post");
+ }
+ remailer[i].flags.cpunk = strfind(flags, " cpunk");
+ remailer[i].flags.pgp = strfind(flags, " pgp");
+ remailer[i].flags.pgponly = strfind(flags, " pgponly");
+ remailer[i].flags.latent = strfind(flags, " latent");
+ remailer[i].flags.middle = strfind(flags, " middle");
+ remailer[i].flags.ek = strfind(flags, " ek");
+ remailer[i].flags.esub = strfind(flags, " esub");
+ remailer[i].flags.newnym = strfind(flags, " newnym");
+ remailer[i].flags.nym = strfind(flags, " nym");
+ remailer[i].info[1].reliability = 0;
+ remailer[i].info[1].latency = 0;
+ remailer[i].info[1].history[0] = '\0';
+ remailer[i].flags.star_ex = bufifind(starex, name);
+ }
+ if (strleft(line,
+ "-----------------------------------------------------------------------"))
+ break;
+ }
+ n++; /* ?? */
+ while (fgets(line, sizeof(line), list) != NULL) {
+ if (strlen(line) >= 72 && strlen(line) <= 73)
+ for (i = 1; i < n; i++)
+ if (strleft(line, remailer[i].name) &&
+ line[strlen(remailer[i].name)] == ' ') {
+ strncpy(remailer[i].info[1].history, line + 42, 12);
+ remailer[i].info[1].history[12] = '\0';
+ remailer[i].info[1].reliability = 10000 * N(line[64])
+ + 1000 * N(line[65]) + 100 * N(line[66])
+ + 10 * N(line[68]) + N(line[69]);
+ remailer[i].info[1].latency = 36000 * N(line[55])
+ + 3600 * N(line[56]) + 600 * N(line[58])
+ + 60 * N(line[59]) + 10 * N(line[61])
+ + N(line[62]);
+ listed++;
+ }
+ }
+ fclose(list);
+ parse_badchains(badchains, TYPE1LIST, "Broken type-I remailer chains", remailer, n);
+ if (listed < 4) /* we have no valid reliability info */
+ for (i = 1; i < n; i++)
+ remailer[i].info[1].reliability = 10000;
+
+#ifdef USE_PGP
+ pgp_rlist(remailer, n);
+#endif /* USE_PGP */
+ buf_free(starex);
+ return (n);
+}
+
+int t1_ek(BUFFER *key, BUFFER *seed, int num)
+{
+ buf_reset(key);
+ buf_appendc(key, (byte) num);
+ buf_cat(key, seed);
+ digest_md5(key, key);
+ encode(key, 0);
+#ifdef DEBUG
+ fprintf(stderr, "passphrase=%s (%2X%2X%2X%2X %d)\n", key->data,
+ seed->data[0], seed->data[1], seed->data[2], seed->data[3], num);
+#endif /* DEBUG */
+ return (0);
+}
+
+int t1_encrypt(int type, BUFFER *message, char *chainstr, int latency,
+ BUFFER *ek, BUFFER *feedback)
+{
+ BUFFER *b, *rem, *dest, *line, *field, *content;
+ REMAILER remailer[MAXREM];
+ int badchains[MAXREM][MAXREM];
+ int maxrem, chainlen = 0;
+ int chain[20];
+ int hop;
+ int hashmark = 0;
+ int err = 0;
+
+ b = buf_new();
+ rem = buf_new();
+ dest = buf_new();
+ line = buf_new();
+ field = buf_new();
+ content = buf_new();
+
+ maxrem = t1_rlist(remailer, badchains);
+ if (maxrem < 1) {
+ clienterr(feedback, "No remailer list!");
+ err = -1;
+ goto end;
+ }
+ chainlen = chain_select(chain, chainstr, maxrem, remailer, 1, line);
+ if (chainlen < 1) {
+ if (line->length)
+ clienterr(feedback, line->data);
+ else
+ clienterr(feedback, "Invalid remailer chain!");
+ err = -1;
+ goto end;
+ }
+ if (chain[0] == 0)
+ chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 1, chain, chainlen, 0);
+
+ if (chain[0] == -1) {
+ clienterr(feedback, "Invalid remailer chain!");
+ err = -1;
+ goto end;
+ }
+ if (chain_rand(remailer, badchains, maxrem, chain, chainlen, 1, 0) == -1) {
+ clienterr(feedback, "No reliable remailers!");
+ err = -1;
+ goto end;
+ }
+ while (buf_getheader(message, field, content) == 0) {
+ hdr_encode(content, 0);
+ if (type == MSG_POST && bufieq(field, "newsgroups") &&
+ remailer[chain[0]].flags.post) {
+ buf_appendf(dest, "Anon-Post-To: %b\n", content);
+ } else if (type == MSG_MAIL && bufieq(field, "to")) {
+ buf_appendf(dest, "Anon-To: %b\n", content);
+ } else {
+ /* paste header */
+ if (type == MSG_POST && bufieq(field, "newsgroups"))
+ buf_appendf(dest, "Anon-To: %s\n", MAILtoNEWS);
+ if (hashmark == 0) {
+ buf_appends(b, "##\n");
+ hashmark = 1;
+ }
+ buf_appendheader(b, field, content);
+ }
+ }
+ buf_nl(b);
+ buf_rest(b, message);
+ buf_move(message, b);
+
+ if (type != MSG_NULL && dest->length == 0) {
+ clienterr(feedback, "No destination address!");
+ err = -1;
+ goto end;
+ }
+ if (type == MSG_NULL) {
+ buf_sets(dest, "Null:\n");
+ }
+ for (hop = 0; hop < chainlen; hop++) {
+ if (hop == 0) {
+ buf_sets(b, "::\n");
+ buf_cat(b, dest);
+ } else {
+ buf_sets(b, "::\nAnon-To: ");
+ buf_appends(b, remailer[chain[hop - 1]].addr);
+ buf_nl(b);
+ }
+ if (remailer[chain[hop]].flags.latent && latency > 0)
+ buf_appendf(b, "Latent-Time: +%d:00r\n", latency);
+ if (ek && remailer[chain[hop]].flags.ek) {
+ t1_ek(line, ek, hop);
+ buf_appendf(b, "Encrypt-Key: %b\n", line);
+ }
+ buf_nl(b);
+ buf_cat(b, message);
+#ifdef USE_PGP
+ if (remailer[chain[hop]].flags.pgp) {
+ buf_clear(message);
+ buf_clear(rem);
+ buf_setf(rem, "<%s>", remailer[chain[hop]].addr);
+ err = pgp_encrypt(PGP_ENCRYPT | PGP_REMAIL | PGP_TEXT, b, rem,
+ NULL, NULL, NULL, NULL);
+ if (err < 0) {
+ buf_setf(line, "No PGP key for remailer %s!\n",
+ remailer[chain[hop]].name);
+ clienterr(feedback, line->data);
+ goto end;
+ }
+ buf_appends(message, "::\nEncrypted: PGP\n\n");
+ buf_cat(message, b);
+ } else
+#endif /* USE_PGP */
+ {
+ if (remailer[chain[hop]].flags.pgponly) {
+ buf_setf(line, "PGP encryption needed for remailer %s!\n",
+ remailer[chain[hop]].name);
+ clienterr(feedback, line->data);
+ goto end;
+ }
+ buf_move(message, b);
+ }
+ if (ek && remailer[chain[hop]].flags.ek)
+ buf_appends(message, "\n**\n");
+ }
+ buf_clear(b);
+ if (chainlen == 0) {
+ buf_appends(b, "::\n");
+ buf_cat(b, dest);
+ } else {
+ buf_appendf(b, "%s: %s\n", ek ? "::\nAnon-To" : "To",
+ remailer[chain[chainlen - 1]].addr);
+ }
+ buf_nl(b);
+ buf_cat(b, message);
+ buf_move(message, b);
+end:
+ buf_free(b);
+ buf_free(rem);
+ buf_free(dest);
+ buf_free(line);
+ buf_free(field);
+ buf_free(content);
+ return (err);
+}
+
+#ifdef USE_PGP
+int t1_getreply(BUFFER *msg, BUFFER *ek, int len)
+{
+ BUFFER *key, *decrypt;
+ int err = -1;
+ int hop = 0;
+
+ key = buf_new();
+ decrypt = buf_new();
+
+ do {
+ t1_ek(key, ek, hop);
+ buf_set(decrypt, msg);
+ if (pgp_decrypt(decrypt, key, NULL, NULL, NULL) == 0
+ && decrypt->data != NULL)
+ err = 0, buf_move(msg, decrypt);
+ }
+ while (hop++ < len);
+ return (err);
+}
+
+#endif /* USE_PGP */
diff --git a/Src/chain2.c b/Src/chain2.c
@@ -0,0 +1,685 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Encrypt message for Mixmaster chain
+ $Id: chain2.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#define N(X) (isdigit(X) ? (X)-'0' : 0)
+
+int prepare_type2list(BUFFER *out)
+{
+ FILE *list;
+ char line[LINELEN], name[LINELEN], addr[LINELEN], keyid[LINELEN],
+ version[LINELEN], flags[LINELEN], createdstr[LINELEN], expiresstr[LINELEN];
+ int assigned;
+ time_t created, expires;
+
+ list = mix_openfile(PUBRING, "r");
+ if (list == NULL)
+ return (-1);
+ while (fgets(line, sizeof(line), list) != NULL) {
+ if (strleft(line, begin_key)) {
+ while (fgets(line, sizeof(line), list) != NULL &&
+ !strleft(line, end_key)) ;
+ } else if (strlen(line) > 36 && line[0] != '#') {
+ assigned = sscanf(line, "%127s %127s %127s %127s %127s %127s %127s",
+ name, addr, keyid, version, flags, createdstr, expiresstr);
+ if (assigned < 4)
+ continue;
+ if (assigned >= 6) {
+ created = parse_yearmonthday(createdstr);
+ if (created == 0 || created == -1) {
+ errlog(WARNING, "Cannot parse creation date of key %s.\n", keyid);
+ continue;
+ };
+ if (created > time(NULL)) {
+ errlog(WARNING, "Key %s created in the future.\n", keyid);
+ continue;
+ };
+ }
+ if (assigned >= 7) {
+ expires = parse_yearmonthday(expiresstr);
+ if (expires == 0 || expires == -1) {
+ errlog(WARNING, "Cannot parse expiration date of key %s.\n", keyid);
+ continue;
+ };
+ if (expires < time(NULL)) {
+ errlog(WARNING, "Key %s has expired.\n", keyid);
+ continue;
+ };
+ }
+ buf_appends(out, line);
+ }
+ }
+ fclose(list);
+ return (0);
+}
+
+int mix2_rlist(REMAILER remailer[], int badchains[MAXREM][MAXREM])
+{
+ FILE *list, *excl;
+ int n, i, listed = 0;
+
+ char line[LINELEN], name[LINELEN], addr[LINELEN], keyid[LINELEN],
+ version[LINELEN], flags[LINELEN], createdstr[LINELEN], expiresstr[LINELEN];
+ int assigned;
+ time_t created, expires;
+ BUFFER *starex;
+
+ starex = buf_new();
+ excl = mix_openfile(STAREX, "r");
+ if (excl != NULL) {
+ buf_read(starex, excl);
+ fclose(excl);
+ }
+
+ list = mix_openfile(PUBRING, "r");
+ if (list == NULL) {
+ buf_free(starex);
+ return (-1);
+ }
+ for (n = 1; fgets(line, sizeof(line), list) != NULL && n < MAXREM;)
+ if (strleft(line, begin_key)) {
+ while (fgets(line, sizeof(line), list) != NULL &&
+ !strleft(line, end_key)) ;
+ } else if (strlen(line) > 36 && line[0] != '#') {
+ flags[0] = '\0';
+ assigned = sscanf(line, "%127s %127s %127s %127s %127s %127s %127s",
+ name, addr, keyid, version, flags, createdstr, expiresstr);
+ if (assigned < 4)
+ continue;
+ if (assigned >= 6) {
+ created = parse_yearmonthday(createdstr);
+ if (created == 0 || created == -1) {
+ errlog(WARNING, "Cannot parse creation date of key %s.\n", keyid);
+ continue;
+ };
+ if (created > time(NULL)) {
+ errlog(WARNING, "Key %s created in the future.\n", keyid);
+ continue;
+ };
+ }
+ if (assigned >= 7) {
+ expires = parse_yearmonthday(expiresstr);
+ if (expires == 0 || expires == -1) {
+ errlog(WARNING, "Cannot parse expiration date of key %s.\n", keyid);
+ continue;
+ };
+ if (expires < time(NULL)) {
+ errlog(WARNING, "Key %s has expired.\n", keyid);
+ continue;
+ };
+ }
+ strncpy(remailer[n].name, name, sizeof(remailer[n].name));
+ remailer[n].name[sizeof(remailer[n].name) - 1] = '\0';
+ strncpy(remailer[n].addr, addr, sizeof(remailer[n].addr));
+ remailer[n].addr[sizeof(remailer[n].addr) - 1] = '\0';
+ remailer[n].flags.mix = 1;
+ remailer[n].flags.cpunk = 0;
+ remailer[n].flags.nym = 0;
+ remailer[n].flags.newnym = 0;
+ id_decode(keyid, remailer[n].keyid);
+ remailer[n].version = N(version[0]);
+ remailer[n].flags.compress = strfind(flags, "C");
+ remailer[n].flags.post = strfind(flags, "N");
+ remailer[n].flags.middle = strfind(flags, "M");
+ remailer[n].info[0].reliability = 0;
+ remailer[n].info[0].latency = 0;
+ remailer[n].info[0].history[0] = '\0';
+ remailer[n].flags.star_ex = bufifind(starex, name);
+ n++;
+ }
+ fclose(list);
+ list = mix_openfile(TYPE2REL, "r");
+ if (list != NULL) {
+ while (fgets(line, sizeof(line), list) != NULL &&
+ !strleft(line, "--------------------------------------------")) {
+ if (strleft(line, "Last update:")) {
+ int generated;
+ int now = time(NULL);
+ char *tmp = line + strlen("Last update:") + 1;
+ generated = parsedate(tmp);
+ if (generated == -1) {
+ /* For some weird reason, this isn't rfc822 */
+ if (strleft(tmp, "Mon") ||
+ strleft(tmp, "Tue") ||
+ strleft(tmp, "Wed") ||
+ strleft(tmp, "Thu") ||
+ strleft(tmp, "Fri") ||
+ strleft(tmp, "Sat") ||
+ strleft(tmp, "Sun"))
+ tmp += 3;
+ generated = parsedate(tmp);
+ }
+ now = time(NULL);
+ if (generated != -1 && generated < now - SECONDSPERDAY)
+ errlog(WARNING, "Remailer Reliability Statistics are older than one day (check your clock?).\n");
+ if (generated != -1 && generated > now)
+ errlog(WARNING, "Remailer Reliability Statistics are from the future (check your clock?).\n");
+ }
+ };
+ while (fgets(line, sizeof(line), list) != NULL &&
+ !strleft(line, "</PRE>"))
+ if (strlen(line) >= 44 && strlen(line) <= 46)
+ for (i = 1; i < n; i++)
+ if (strleft(line, remailer[i].name) &&
+ line[strlen(remailer[i].name)] == ' ') {
+ strncpy(remailer[i].info[0].history, line + 15, 12);
+ remailer[i].info[0].history[12] = '\0';
+ remailer[i].info[0].reliability = 10000 * N(line[37])
+ + 1000 * N(line[38]) + 100 * N(line[39])
+ + 10 * N(line[41]) + N(line[42]);
+ remailer[i].info[0].latency = 36000 * N(line[28])
+ + 3600 * N(line[29]) + 600 * N(line[31])
+ + 60 * N(line[32]) + 10 * N(line[34])
+ + N(line[35]);
+ listed++;
+ }
+ fclose(list);
+ }
+
+ parse_badchains(badchains, TYPE2REL, "Broken type-II remailer chains", remailer, n);
+ if (listed < 4) /* we have no valid reliability info */
+ for (i = 1; i < n; i++)
+ remailer[i].info[0].reliability = 10000;
+ buf_free(starex);
+ return (n);
+}
+
+static int send_packet(int numcopies, BUFFER *packet, int chain[],
+ int chainlen, int packetnum, int numpackets,
+ BUFFER *mid, REMAILER remailer[], int badchains[MAXREM][MAXREM],
+ int maxrem, char *redirect_to, int ignore_constraints_if_necessary,
+ BUFFER *feedback)
+/*
+ * Puts a mix packet in the pool.
+ *
+ * numcopies ... how often to put this packet into the pool
+ * i.e. send it. required that random remailers are in the chain.
+ * packet ... the payload, 10240 bytes in size.
+ * chain ... the chain to send this message along
+ * chainlen ... length of the chain
+ * packetnum ... in multi-packet messages (fragmented) the serial of this packet
+ * numpackets ... the total number of packets
+ * mid ... the message ID (required for fragmented packets
+ * remailer ... information about remailers, their reliabilities, capabilities, etc.
+ * badchains ... broken chain information
+ * maxrem ... the number of remailers in remailer[] and badchains[]
+ * redirect_to ... if this is not-null it needs to be an email address.
+ * in this case packet needs to be not only the body, but a
+ * complete mixmaster packet of 20480 bytes in size (20 headers + body).
+ * the chain given is prepended to the one already encrypted in
+ * the existing message. If this exceeds the allowed 20 hops in total
+ * the message is corrupted, the last node will realize this.
+ * This is useful if you want to reroute an existing mixmaster message
+ * that has foo as the next hop via a chain so that the packet will
+ * actually flow hop1,hop2,hop3,foo,....
+ * ignore_constraints_if_necessary .. to be used when randhopping messages.
+ * if a chain can not be constructed otherwhise, maxlat, minlat,
+ * and minrel are ignored.
+ * feedback ... a buffer to write feedback to
+ */
+{
+ BUFFER *pid, *out, *header, *other, *encrypted, *key, *body;
+ BUFFER *iv, *ivarray, *temp;
+ BUFFER *pubkey;
+ char addr[LINELEN];
+ int thischain[20];
+ int hop;
+ int c, i;
+ int timestamp = 0;
+ int israndom = 0;
+ int err = 1;
+
+ body = buf_new();
+ pid = buf_new();
+ out = buf_new();
+ header = buf_new();
+ other = buf_new();
+ key = buf_new();
+ encrypted = buf_new();
+ iv = buf_new();
+ ivarray = buf_new();
+ temp = buf_new();
+
+ if (redirect_to != NULL) {
+ assert(packet->length == 20480);
+ buf_append(header, packet->data, 10240);
+ buf_append(temp, packet->data + 10240, 10240);
+ buf_clear(packet);
+ buf_cat(packet, temp);
+ } else
+ assert(packet->length == 10240);
+
+ buf_setrnd(pid, 16);
+
+ for (c = 0; c < numcopies; c++) {
+ buf_set(body, packet);
+
+ for (hop = 0; hop < chainlen; hop++)
+ thischain[hop] = chain[hop];
+
+ israndom = chain_rand(remailer, badchains, maxrem, thischain, chainlen, 0, ignore_constraints_if_necessary);
+ if (israndom == -1) {
+ err = -1;
+ clienterr(feedback, "No reliable remailers!");
+ }
+ if ((numcopies > 1 || numpackets > 1) && !israndom && (chainlen != 1)) {
+ clienterr(feedback,
+ "Multi-packet message without random remailers!");
+ err = -1;
+ goto end;
+ }
+ for (hop = 0; hop < chainlen; hop++) {
+ switch (remailer[thischain[hop]].version) {
+ case 2:
+ case 3: /* not implemented yet; fall back to version 2 */
+ /* create header chart to be encrypted with the session key */
+ if (numcopies > 1 && hop == 0 && redirect_to == NULL)
+ buf_set(encrypted, pid); /* same ID only at final hop */
+ else
+ buf_setrnd(encrypted, 16);
+ buf_setrnd(key, 24); /* key for encrypting the body */
+ buf_cat(encrypted, key);
+ buf_setrnd(iv, 8); /* IV for encrypting the body */
+
+ if (hop > 0 || redirect_to != NULL) {
+ /* IVs for header chart encryption */
+ buf_setrnd(ivarray, 18 * 8);
+ buf_cat(ivarray, iv); /* 19th IV equals the body IV */
+
+ buf_appendc(encrypted, 0);
+ buf_cat(encrypted, ivarray);
+ memset(addr, 0, 80);
+ if (hop == 0) {
+ assert(redirect_to != NULL);
+ strncpy(addr, redirect_to, 80);
+ } else {
+ assert(hop > 0);
+ strcpy(addr, remailer[thischain[hop - 1]].addr);
+ };
+ buf_append(encrypted, addr, 80);
+ } else {
+ if (numpackets == 1)
+ buf_appendc(encrypted, 1);
+ else {
+ buf_appendc(encrypted, 2);
+ buf_appendc(encrypted, (byte) packetnum);
+ buf_appendc(encrypted, (byte) numpackets);
+ }
+ buf_cat(encrypted, mid);
+ buf_cat(encrypted, iv); /* body encryption IV */
+ }
+
+ /* timestamp */
+ buf_appends(encrypted, "0000");
+ buf_appendc(encrypted, '\0'); /* timestamp magic */
+ timestamp = time(NULL) / SECONDSPERDAY - rnd_number(4);
+ buf_appendi_lo(encrypted, timestamp);
+
+ /* message digest for this header */
+ digest_md5(encrypted, temp);
+ buf_cat(encrypted, temp);
+ buf_pad(encrypted, 328);
+
+ /* encrypt message body */
+ buf_crypt(body, key, iv, ENCRYPT);
+
+ if (hop > 0 || redirect_to != NULL) {
+ /* encrypt the other header charts */
+ buf_clear(other);
+ for (i = 0; i < 19; i++) {
+ buf_clear(iv);
+ buf_clear(temp);
+ buf_append(iv, ivarray->data + 8 * i, 8);
+ buf_append(temp, header->data + 512 * i, 512);
+ buf_crypt(temp, key, iv, ENCRYPT);
+ buf_cat(other, temp);
+ }
+ } else
+ buf_setrnd(other, 19 * 512); /* fill with random data */
+
+ /* create session key and IV to encrypt the header ... */
+ buf_setrnd(key, 24);
+ buf_setrnd(iv, 8);
+ buf_crypt(encrypted, key, iv, ENCRYPT);
+ pubkey = buf_new();
+ err = db_getpubkey(remailer[thischain[hop]].keyid, pubkey);
+ if (err == -1)
+ goto end;
+ err = pk_encrypt(key, pubkey); /* ... and encrypt the
+ session key */
+ buf_free(pubkey);
+ if (err == -1 || key->length != 128) {
+ clienterr(feedback, "Encryption failed!");
+ err = -1;
+ goto end;
+ }
+ /* now build the new header */
+ buf_clear(header);
+ buf_append(header, remailer[thischain[hop]].keyid, 16);
+ buf_appendc(header, 128);
+ buf_cat(header, key);
+ buf_cat(header, iv);
+ buf_cat(header, encrypted);
+ buf_pad(header, 512);
+ buf_cat(header, other);
+ break;
+ default:
+ err = -1;
+ goto end;
+ }
+ }
+
+ /* build the message */
+ buf_sets(out, remailer[thischain[chainlen - 1]].addr);
+ buf_nl(out);
+ buf_cat(out, header);
+ buf_cat(out, body);
+ assert(header->length == 10240 && body->length == 10240);
+ mix_pool(out, INTERMEDIATE, -1);
+
+ if (feedback) {
+ for (hop = chainlen - 1; hop >= 0; hop--) {
+ buf_appends(feedback, remailer[thischain[hop]].name);
+ if (hop > 0)
+ buf_appendc(feedback, ',');
+ }
+ buf_nl(feedback);
+ }
+ }
+end:
+ buf_free(pid);
+ buf_free(body);
+ buf_free(out);
+ buf_free(header);
+ buf_free(temp);
+ buf_free(other);
+ buf_free(key);
+ buf_free(encrypted);
+ buf_free(iv);
+ buf_free(ivarray);
+ return (err);
+}
+
+int redirect_message(BUFFER *sendmsg, char *chainstr, int numcopies, BUFFER *feedback)
+{
+ BUFFER *field;
+ BUFFER *content;
+ BUFFER *line;
+ char recipient[80] = "";
+ int num = 0;
+ int err = 0;
+ int c;
+ int hop;
+
+ REMAILER remailer[MAXREM];
+ int chain[20];
+ int thischain[20];
+ int chainlen;
+ int badchains[MAXREM][MAXREM];
+ int maxrem;
+ int tempchain[20];
+ int tempchainlen;
+ int israndom;
+
+ field = buf_new();
+ content = buf_new();
+ line = buf_new();
+
+ if (numcopies == 0)
+ numcopies = NUMCOPIES;
+ if (numcopies > 10)
+ numcopies = 10;
+
+ /* Find the recipient */
+ while (buf_getheader(sendmsg, field, content) == 0)
+ if (bufieq(field, "to")) {
+ strncpy(recipient, content->data, sizeof(recipient));
+ num++;
+ };
+ if (num != 1) {
+ clienterr(feedback, "Did not find exactly one To: address!");
+ err = -1;
+ goto end;
+ };
+
+ /* Dearmor the message */
+ err = mix_dearmor(sendmsg, sendmsg);
+ if (err == -1)
+ goto end;
+ assert (sendmsg->length == 20480);
+
+ /* Check the chain */
+ maxrem = mix2_rlist(remailer, badchains);
+ if (maxrem < 1) {
+ clienterr(feedback, "No remailer list!");
+ err = -1;
+ goto end;
+ }
+ chainlen = chain_select(chain, chainstr, maxrem, remailer, 0, line);
+ if (chainlen < 1) {
+ if (line->length)
+ clienterr(feedback, line->data);
+ else
+ clienterr(feedback, "Invalid remailer chain!");
+ err = -1;
+ goto end;
+ } else if (chainlen >= 20) {
+ clienterr(feedback, "A chainlength of 20 will certainly destroy the message!");
+ err = -1;
+ goto end;
+ };
+
+
+ for (c = 0; c < numcopies; c++) {
+ /* if our recipient is a remailer we want to make sure we're not using a known broken chain.
+ * therefore we need to pick the final remailer with care */
+ for (hop = 0; hop < chainlen; hop++)
+ thischain[hop] = chain[hop];
+ if (thischain[0] == 0) {
+ /* Find out, if recipient is a remailer */
+ tempchainlen = chain_select(tempchain, recipient, maxrem, remailer, 0, line);
+ if (tempchainlen < 1 && line->length == 0) {
+ /* recipient is apparently not a remailer we know about */
+ ;
+ } else {
+ /* Build a new chain, based on the one we already selected but
+ * with the recipient as the final hop.
+ * This is so that chain_rand properly selects nodes based on
+ * broken chains and DISTANCE */
+ assert(chainlen < 20);
+ for (hop = 0; hop < chainlen; hop++)
+ thischain[hop+1] = thischain[hop];
+ thischain[0] = tempchain[0];
+
+ israndom = chain_rand(remailer, badchains, maxrem, thischain, chainlen + 1, 0, 0);
+ if (israndom == -1) {
+ err = -1;
+ clienterr(feedback, "No reliable remailers!");
+ goto end;
+ }
+
+ /* Remove the added recipient hop */
+ for (hop = 0; hop < chainlen; hop++)
+ thischain[hop] = thischain[hop + 1];
+ };
+ };
+
+ /* queue the packet */
+ if (send_packet(1, sendmsg, thischain, chainlen,
+ -1, -1, NULL,
+ remailer, badchains, maxrem, recipient, 0, feedback) == -1)
+ err = -1;
+ };
+
+end:
+ buf_free(field);
+ buf_free(content);
+ buf_free(line);
+ return (err);
+}
+
+int mix2_encrypt(int type, BUFFER *message, char *chainstr, int numcopies,
+ int ignore_constraints_if_necessary,
+ BUFFER *feedback)
+{
+ /* returns 0 on success, -1 on error. feedback contains the selected
+ remailer chain or an error message
+
+ ignore_constraints_if_necessary .. to be used when randhopping messages.
+ if a chain can not be constructed otherwhise,
+ maxlat, minlat, and minrel are ignored.
+ */
+
+ REMAILER remailer[MAXREM];
+ int badchains[MAXREM][MAXREM];
+ int maxrem;
+ BUFFER *line, *field, *content, *header, *msgdest, *msgheader, *body,
+ *temp, *mid;
+ byte numdest = 0, numhdr = 0;
+ char hdrline[LINELEN];
+ BUFFER *packet;
+ int chain[20];
+ int chainlen;
+ int i;
+ int err = 0;
+
+ mix_init(NULL);
+ packet = buf_new();
+ line = buf_new();
+ field = buf_new();
+ content = buf_new();
+ msgheader = buf_new();
+ msgdest = buf_new();
+ body = buf_new();
+ temp = buf_new();
+ mid = buf_new();
+ header = buf_new();
+ if (feedback)
+ buf_reset(feedback);
+
+ if (numcopies == 0)
+ numcopies = NUMCOPIES;
+ if (numcopies > 10)
+ numcopies = 10;
+
+ maxrem = mix2_rlist(remailer, badchains);
+ if (maxrem < 1) {
+ clienterr(feedback, "No remailer list!");
+ err = -1;
+ goto end;
+ }
+ chainlen = chain_select(chain, chainstr, maxrem, remailer, 0, line);
+ if (chainlen < 1) {
+ if (line->length)
+ clienterr(feedback, line->data);
+ else
+ clienterr(feedback, "Invalid remailer chain!");
+ err = -1;
+ goto end;
+ }
+ if (chain[0] == 0)
+ chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 0, chain, chainlen, ignore_constraints_if_necessary);
+
+ if (chain[0] == -1) {
+ clienterr(feedback, "No reliable remailers!");
+ err = -1;
+ goto end;
+ }
+ switch (remailer[chain[0]].version) {
+ case 2:
+ if (type == MSG_NULL) {
+ memset(hdrline, 0, 80);
+ strcpy(hdrline, "null:");
+ buf_append(msgdest, hdrline, 80);
+ numdest++;
+ } else
+ while (buf_getheader(message, field, content) == 0) {
+ if (bufieq(field, "to")) {
+ memset(hdrline, 0, 80);
+ strncpy(hdrline, content->data, 80);
+ buf_append(msgdest, hdrline, 80);
+ numdest++;
+ } else if (type == MSG_POST && bufieq(field, "newsgroups")) {
+ memset(hdrline, 0, 80);
+ strcpy(hdrline, "post: ");
+ strcatn(hdrline, content->data, 80);
+ buf_append(msgdest, hdrline, 80);
+ numdest++;
+ } else {
+ buf_clear(header);
+ buf_appendheader(header, field, content);
+ hdr_encode(header, 80);
+ while (buf_getline(header, line) == 0) {
+ /* paste in encoded header entry */
+ memset(hdrline, 0, 80);
+ strncpy(hdrline, line->data, 80);
+ buf_append(msgheader, hdrline, 80);
+ numhdr++;
+ }
+ }
+ }
+ buf_appendc(body, numdest);
+ buf_cat(body, msgdest);
+ buf_appendc(body, numhdr);
+ buf_cat(body, msgheader);
+
+ if (type != MSG_NULL) {
+ buf_rest(temp, message);
+ if (temp->length > 10236 && remailer[chain[0]].flags.compress)
+ buf_compress(temp);
+ buf_cat(body, temp);
+ buf_reset(temp);
+ }
+ buf_setrnd(mid, 16); /* message ID */
+ for (i = 0; i <= body->length / 10236; i++) {
+ long length;
+
+ length = body->length - i * 10236;
+ if (length > 10236)
+ length = 10236;
+ buf_clear(packet);
+ buf_appendl_lo(packet, length);
+ buf_append(packet, body->data + i * 10236, length);
+ buf_pad(packet, 10240);
+ if (send_packet(numcopies, packet, chain, chainlen,
+ i + 1, body->length / 10236 + 1,
+ mid, remailer, badchains, maxrem, NULL, ignore_constraints_if_necessary, feedback) == -1)
+ err = -1;
+ }
+ break;
+ case 3:
+ NOT_IMPLEMENTED;
+ break;
+ default:
+ fprintf(stderr, "%d\n", chain[0]);
+ clienterr(feedback, "Unknown remailer version!");
+ err = -1;
+ }
+
+end:
+ buf_free(packet);
+ buf_free(line);
+ buf_free(field);
+ buf_free(content);
+ buf_free(header);
+ buf_free(msgheader);
+ buf_free(msgdest);
+ buf_free(body);
+ buf_free(temp);
+ buf_free(mid);
+ return (err);
+}
diff --git a/Src/compress.c b/Src/compress.c
@@ -0,0 +1,210 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Buffer compression (interface to zlib)
+ $Id: compress.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <stdio.h>
+#include <assert.h>
+
+static byte gz_magic[2] =
+{0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01
+#define HEAD_CRC 0x02
+#define EXTRA_FIELD 0x04
+#define ORIG_NAME 0x08
+#define COMMENT 0x10
+#define RESERVED 0xE0
+#define Z_DEFLATED 8
+
+#ifdef USE_ZLIB
+#include "zlib.h"
+
+int buf_unzip(BUFFER *in, int type)
+{
+ BUFFER *out;
+ z_stream s;
+ long outstart;
+ int err;
+ int ret = 0;
+
+ out = buf_new();
+
+ s.zalloc = (alloc_func) 0;
+ s.zfree = (free_func) 0;
+ s.opaque = (voidpf) 0;
+
+ s.next_in = in->data + in->ptr;
+ s.avail_in = in->length + 1 - in->ptr; /* terminating 0 byte as "dummy" */
+ s.next_out = NULL;
+
+ if (type == 1)
+ err = inflateInit(&s); /* zlib */
+ else
+ err = inflateInit2(&s, -MAX_WBITS);
+ if (err != Z_OK) {
+ ret = -1;
+ goto end;
+ }
+ outstart = 0;
+ buf_append(out, NULL, in->length * 15 / 10);
+
+ for (;;) {
+ s.next_out = out->data + s.total_out + outstart;
+ s.avail_out = out->length - outstart - s.total_out;
+ err = inflate(&s, Z_PARTIAL_FLUSH);
+ out->length -= s.avail_out;
+ if (err != Z_OK)
+ break;
+ buf_append(out, NULL, BUFSIZE);
+ }
+ if (err != Z_STREAM_END)
+ errlog(WARNING, "Decompression error %d\n", err);
+
+ err = inflateEnd(&s);
+ if (err != Z_OK)
+ ret = -1;
+end:
+ if (ret != 0)
+ switch (err) {
+ case Z_STREAM_ERROR:
+ errlog(ERRORMSG, "Decompression error Z_STREAM_ERROR.\n", err);
+ break;
+ case Z_MEM_ERROR:
+ errlog(ERRORMSG, "Decompression error Z_MEM_ERROR.\n", err);
+ break;
+ case Z_BUF_ERROR:
+ errlog(ERRORMSG, "Decompression error Z_BUF_ERROR.\n", err);
+ break;
+ case Z_VERSION_ERROR:
+ errlog(ERRORMSG, "Decompression error Z_VERSION_ERROR.\n", err);
+ break;
+ default:
+ errlog(ERRORMSG, "Decompression error %d.\n", err);
+ }
+ buf_move(in, out);
+ buf_free(out);
+ return (ret);
+}
+
+int buf_zip(BUFFER *out, BUFFER *in, int bits)
+{
+ z_stream s;
+ long outstart;
+ int err = -1;
+
+ assert(in != out);
+
+ s.zalloc = (alloc_func) 0;
+ s.zfree = (free_func) 0;
+ s.opaque = (voidpf) 0;
+ s.next_in = NULL;
+
+ if (bits == 0)
+ bits = MAX_WBITS;
+
+ if (deflateInit2(&s, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -bits, 8, 0) != Z_OK)
+ goto end;
+
+ outstart = out->length;
+ /* 12 is overhead, 1.01 is maximum expansion, and 1 is there to force a round-up */
+ buf_append(out, NULL, (int)13+in->length*1.01); /* fit it in one chunk */
+
+ s.next_in = in->data;
+ s.avail_in = in->length;
+
+ for (;;) {
+ s.next_out = out->data + s.total_out + outstart;
+ s.avail_out = out->length - outstart - s.total_out;
+ err = deflate(&s, Z_FINISH);
+ out->length -= s.avail_out;
+ if (err != Z_OK)
+ break;
+ errlog(ERRORMSG, "Compressed data did not fit in one chunk.\n");
+ buf_append(out, NULL, BUFSIZE);
+ }
+ if (deflateEnd(&s) != Z_OK || err != Z_STREAM_END)
+ err = -1;
+ else
+ err = 0;
+end:
+ if (err != 0)
+ errlog(ERRORMSG, "Compression error.\n");
+ return (err);
+}
+
+#else /* end of USE_ZLIB */
+int buf_zip(BUFFER *out, BUFFER *in, int bits)
+{
+ return (-1);
+}
+
+int buf_unzip(BUFFER *b, int type)
+{
+ errlog(ERRORMSG, "Can't uncompress: no zlib\n");
+ return (-1);
+}
+#endif /* else not USE_ZLIB */
+
+int compressed(BUFFER *b)
+{
+ return (b->length >= 10 && b->data[0] == gz_magic[0] &&
+ b->data[1] == gz_magic[1]);
+}
+
+int buf_uncompress(BUFFER *in)
+{
+ int type;
+ int err = -1;
+ unsigned int len;
+
+ if (!compressed(in))
+ return (0);
+ type = in->data[3];
+ if (in->data[2] != Z_DEFLATED || (type & RESERVED) == 0) {
+ in->ptr = 10;
+ if ((type & EXTRA_FIELD) != 0) {
+ len = buf_geti(in);
+ in->ptr += len;
+ }
+ if ((type & ORIG_NAME) != 0)
+ while (buf_getc(in) > 0) ;
+ if ((type & COMMENT) != 0)
+ while (buf_getc(in) > 0) ;
+ if ((type & HEAD_CRC) != 0)
+ buf_geti(in);
+ err = buf_unzip(in, 0);
+ }
+ return (err);
+}
+
+int buf_compress(BUFFER *in)
+{
+ BUFFER *out;
+ int err;
+
+ if (compressed(in))
+ return (0);
+
+ out = buf_new();
+ buf_appendc(out, gz_magic[0]);
+ buf_appendc(out, gz_magic[1]);
+ buf_appendc(out, Z_DEFLATED);
+ buf_appendc(out, 0); /* flags */
+ buf_appendl(out, 0); /* time */
+ buf_appendc(out, 0); /* xflags */
+ buf_appendc(out, 3); /* Unix */
+ err = buf_zip(out, in, 0);
+ if (err == 0)
+ buf_move(in, out);
+ buf_free(out);
+ return (err);
+}
diff --git a/Src/config.h b/Src/config.h
@@ -0,0 +1,403 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2008 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Configuration
+ $Id: config.h 973 2008-03-03 16:55:38Z rabbi $ */
+
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "version.h"
+#ifndef WIN32
+#include "sys/param.h"
+#endif /* WIN32 */
+
+/* Disclaimer to be inserted in all anonymous messages: */
+#define DISCLAIMER \
+ "Comments: This message did not originate from the Sender address above.\n" \
+ "\tIt was remailed automatically by anonymizing remailer software.\n" \
+ "\tPlease report problems or inappropriate use to the\n" \
+ "\tremailer administrator at <%s>.\n" /* (%s is the complaints address) */
+
+/* Additional disclaimer to be inserted in the body of messages with
+ * user-supplied From lines, e.g.
+ * "NOTE: The above From: line has not been authenticated!\n\n" */
+#define FROMDISCLAIMER ""
+
+/* Additional disclaimer to be inserted at the bottom of the body of all
+ * messages */
+#define MSGFOOTER ""
+
+/* Comment to be inserted when a binary attachment is filtered out: */
+#define BINDISCLAIMER \
+ "[...]"
+
+/* Character set for MIME-encoded mail header lines */
+#define MIMECHARSET "iso-8859-1"
+#if 1
+#define DEFLTENTITY ""
+#else
+#define DEFLTENTITY "text/plain; charset=" MIMECHARSET
+#endif
+
+#ifdef WIN32
+/* Use the PCRE regular expression library for destination blocking? */
+#define USE_PCRE
+/* Use zlib for compression? */
+#define USE_ZLIB
+/* Use ncurses? */
+#define USE_NCURSES
+/* Use the WIN GUI? */
+#define USE_WINGUI
+/* Use sockets to deliver mail */
+#define USE_SOCK
+/* Compile in Win32 service support */
+#define WIN32SERVICE
+#endif /* WIN32 */
+
+/** System dependencies **********************************************/
+/* Macros: UNIX for Unix-style systems
+ POSIX for systems with POSIX header files (including DJGPP)
+ MSDOS for 32 bit DOS
+ WIN32 for Windows 95/NT */
+
+#if defined(_WIN32) && !defined(WIN32)
+#define WIN32
+#endif
+
+#if defined(__RSXNT__) && !defined(WIN32)
+#define WIN32
+#endif
+
+#if !defined(UNIX) && !defined(WIN32) && !defined(MSDOS)
+#define UNIX
+#endif
+
+#if defined(UNIX) && !defined(POSIX)
+#define POSIX
+#endif
+
+#ifdef UNIX
+#define DEV_URANDOM "/dev/urandom"
+#ifdef __OpenBSD__
+#define DEV_RANDOM "/dev/arandom"
+#else
+#define DEV_RANDOM "/dev/random"
+#endif
+#endif
+
+#ifdef POSIX
+# define HAVE_TERMIOS
+#endif /* POSIX */
+
+#ifdef MSDOS
+#define SHORTNAMES
+#ifndef WIN32
+#define HAVE_GETKEY
+#undef USE_SOCK
+#endif
+#endif
+
+#if defined(USE_WINGUI) && !defined(WIN32)
+#error "The GUI requires Win32!"
+#endif
+
+#if defined(WIN32) && !defined(_USRDLL)
+#define DLLIMPORT __declspec(dllimport)
+#else
+#define DLLIMPORT
+#endif
+
+/* This block includes the config.h created by autoconf/configure.
+ * Eventually this old config.h stuff should be merged with the autoconf
+ * stuff perhaps. */
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#else /* End of HAVE_CONFIG_H */
+
+/* Setup for stuff that happens when autoconf isn't run. This should be
+ * removed once we finally nuke that damn Install script. */
+
+/** Libraries and library functions **********************************/
+
+/* Use the OpenSSL crypto library (required) */
+#define USE_OPENSSL
+/* Use IDEA algorithm? (See file idea.txt) */
+/* #define USE_IDEA */
+/* Use AES algorithm? - should be handled by Install script setting compiler option -DUSE_AES */
+/* #define USE_AES */
+/* Support the OpenPGP message format? */
+#define USE_PGP
+
+#ifdef UNIX
+# define HAVE_UNAME
+# define HAVE_GECOS
+#endif
+
+#if defined(POSIX) || defined(USE_SOCK)
+# define HAVE_GETHOSTNAME
+#endif
+
+#ifdef POSIX
+/* not a POSIX function, but avaiable on virtually all Unix systems */
+# define HAVE_GETTIMEOFDAY
+#endif
+
+#ifdef linux
+# define HAVE_GETDOMAINNAME
+#endif
+
+#ifdef WIN32
+# ifdef _MSC_VER
+#pragma warning(disable: 4018) /* signed/unsigned mismatch */
+#pragma warning(disable: 4761) /* integral size mismatch */
+# endif
+#endif
+
+
+#endif /* End of not HAVE_CONFIG_H */
+
+/** Constants *********************************************************/
+
+/* Give up if a file is larger than BUFFER_MAX bytes: */
+/* #define BUFFER_MAX 64*1024*1024 */
+
+#ifdef MAXPATHLEN
+#define PATHMAX MAXPATHLEN
+#else /* MAXPATHLEN */
+#ifdef _MSC
+#define PATHMAX MAX_PATH
+#else /* _MSC */
+#define PATHMAX 512
+#endif /* not _MSC */
+#endif /* not MAXPATHLEN */
+#define LINELEN 128
+#define BUFSIZE 4096
+
+/** if it is a systemwide installation defined GLOBALMIXCONF **********/
+/* #define GLOBALMIXCONF "/etc/mix.cfg" */
+
+/* The path to append to a user's homedirectory for his local Mix dir */
+#ifndef HOMEMIXDIR
+#define HOMEMIXDIR "Mix"
+#endif
+
+/** file names ********************************************************/
+
+#ifdef WIN32
+#define DEFAULT_MIXCONF "mix.cfg" /* change to mix.ini eventually */
+#else
+#define DEFAULT_MIXCONF "mix.cfg" /* mixmaster configuration file */
+#endif
+#define DEFAULT_DISCLAIMFILE "disclaim.txt"
+#define DEFAULT_FROMDSCLFILE "fromdscl.txt"
+#define DEFAULT_MSGFOOTERFILE "footer.txt"
+#ifdef WIN32
+#define DEFAULT_POP3CONF "pop3.cfg" /* change to pop3.ini eventually */
+#else
+#define DEFAULT_POP3CONF "pop3.cfg"
+#endif
+#define DEFAULT_HELPFILE "help.txt"
+#define DEFAULT_REQUESTDIR "requests"
+#define DEFAULT_ABUSEFILE "abuse.txt"
+#define DEFAULT_REPLYFILE "reply.txt"
+#define DEFAULT_USAGEFILE "usage.txt"
+#define DEFAULT_USAGELOG "usage.log"
+#define DEFAULT_BLOCKFILE "blocked.txt"
+#define DEFAULT_ADMKEYFILE "adminkey.txt"
+#define DEFAULT_KEYFILE "key.txt"
+#define DEFAULT_PGPKEY "pgpkey.txt"
+#define DEFAULT_DSAPARAMS "dsaparam.mix"
+#define DEFAULT_DHPARAMS "dhparam.mix"
+#define DEFAULT_MIXRAND "mixrand.bin"
+#define DEFAULT_SECRING "secring.mix"
+#define DEFAULT_PUBRING "pubring.mix"
+#define DEFAULT_IDLOG "id.log"
+#define DEFAULT_STATS "stats.log"
+#define DEFAULT_PGPMAXCOUNT "pgpmaxcount.log"
+/* To enable multiple dest.blk files, edit the following line. */
+/* Filenames must be seperated by one space. */
+#define DEFAULT_DESTBLOCK "dest.blk rab.blk"
+#define DEFAULT_DESTALLOW "dest.alw"
+#define DEFAULT_DESTALLOW2 "dest.alw.nonpublished"
+#define DEFAULT_SOURCEBLOCK "source.blk"
+#define DEFAULT_HDRFILTER "header.blk"
+#define DEFAULT_REGULAR "time.log"
+#define DEFAULT_POOL "pool" /* remailer pool subdirectory */
+#define DEFAULT_TYPE1LIST "rlist.txt"
+#define DEFAULT_TYPE2REL "mlist.txt"
+#define DEFAULT_PIDFILE "mixmaster.pid"
+#define DEFAULT_STATSSRC "stats-src.txt"
+
+#define DEFAULT_PGPREMPUBRING "pubring.pgp"
+#define DEFAULT_PGPREMPUBASC "pubring.asc"
+#define DEFAULT_PGPREMSECRING "secring.pgp"
+#define DEFAULT_NYMSECRING "nymsec.pgp"
+#define DEFAULT_NYMDB "secrets.mix"
+#define DEFAULT_STAREX "starex.txt"
+#define DEFAULT_ALLPINGERSURL "http://www.noreply.org/allpingers/allpingers.txt"
+#define DEFAULT_ALLPINGERSFILE "allpingers.txt"
+#define DEFAULT_WGET "wget"
+
+DLLIMPORT extern char MIXCONF[];
+extern char DISCLAIMFILE[];
+extern char FROMDSCLFILE[];
+extern char MSGFOOTERFILE[];
+extern char POP3CONF[];
+extern char HELPFILE[];
+extern char REQUESTDIR[];
+extern char ABUSEFILE[];
+extern char REPLYFILE[];
+extern char USAGEFILE[];
+extern char USAGELOG[];
+extern char BLOCKFILE[];
+extern char ADMKEYFILE[];
+extern char KEYFILE[];
+extern char PGPKEY[];
+extern char DSAPARAMS[];
+extern char DHPARAMS[];
+extern char MIXRAND[];
+extern char SECRING[];
+extern char PUBRING[];
+extern char IDLOG[];
+extern char STATS[];
+extern char PGPMAXCOUNT[];
+extern char DESTBLOCK[];
+extern char DESTALLOW[];
+extern char DESTALLOW2[];
+extern char SOURCEBLOCK[];
+extern char HDRFILTER[];
+extern char REGULAR[];
+extern char POOL[];
+extern char TYPE1LIST[];
+extern char TYPE2REL[];
+extern char PIDFILE[];
+extern char STAREX[];
+
+extern char PGPREMPUBRING[];
+extern char PGPREMPUBASC[];
+extern char PGPREMSECRING[];
+DLLIMPORT extern char NYMSECRING[];
+extern char NYMDB[];
+
+/* string constants */
+#define remailer_type "Remailer-Type: Mixmaster "
+#define mixmaster_protocol "2"
+#define begin_remailer "-----BEGIN REMAILER MESSAGE-----"
+#define end_remailer "-----END REMAILER MESSAGE-----"
+#define begin_key "-----Begin Mix Key-----"
+#define end_key "-----End Mix Key-----"
+#define begin_pgp "-----BEGIN PGP "
+#define end_pgp "-----END PGP "
+#define begin_pgpmsg "-----BEGIN PGP MESSAGE-----"
+#define end_pgpmsg "-----END PGP MESSAGE-----"
+#define begin_pgpkey "-----BEGIN PGP PUBLIC KEY BLOCK-----"
+#define end_pgpkey "-----END PGP PUBLIC KEY BLOCK-----"
+#define begin_pgpseckey "-----BEGIN PGP PRIVATE KEY BLOCK-----"
+#define end_pgpseckey "-----END PGP PRIVATE KEY BLOCK-----"
+#define begin_pgpsigned "-----BEGIN PGP SIGNED MESSAGE-----"
+#define begin_pgpsig "-----BEGIN PGP SIGNATURE-----"
+#define end_pgpsig "-----END PGP SIGNATURE-----"
+#define info_beginpgp "=====BEGIN PGP MESSAGE====="
+#define info_endpgp "=====END PGP MESSAGE====="
+#define info_pgpsig "=====Sig: "
+
+
+/***********************************************************************
+ * The following variables are read from mix.cfg, with default values
+ * defined in mix.c */
+
+int REMAIL;
+int MIX;
+int PGP;
+int UNENCRYPTED;
+int REMIX;
+int REPGP;
+extern char MIXDIR[];
+extern char POOLDIR[];
+extern char EXTFLAGS[];
+extern char SENDMAIL[];
+extern char SENDANONMAIL[];
+extern char PRECEDENCE[];
+extern char SMTPRELAY[];
+extern char SMTPUSERNAME[];
+extern char SMTPPASSWORD[];
+extern char NEWS[];
+extern char MAILtoNEWS[];
+extern char ORGANIZATION[];
+extern char MID[];
+extern char TYPE1[];
+extern char ERRLOG[];
+extern char NAME[];
+extern char ADDRESS[];
+extern char REMAILERADDR[];
+extern char ANONADDR[];
+extern char REMAILERNAME[];
+extern char ANONNAME[];
+extern char COMPLAINTS[];
+extern int AUTOREPLY;
+extern char HELONAME[];
+extern char ENVFROM[];
+extern char SHORTNAME[];
+extern int POOLSIZE;
+DLLIMPORT extern int RATE;
+extern int INDUMMYP;
+extern int OUTDUMMYP;
+extern int MIDDLEMAN;
+extern int AUTOBLOCK;
+extern int STATSDETAILS;
+extern char FORWARDTO[];
+extern int SIZELIMIT;
+extern int INFLATEMAX;
+extern int MAXRANDHOPS;
+extern int BINFILTER;
+extern int LISTSUPPORTED;
+extern long PACKETEXP;
+extern long IDEXP;
+DLLIMPORT extern int VERBOSE;
+DLLIMPORT extern long SENDPOOLTIME;
+extern long MAILINTIME;
+extern long KEYLIFETIME;
+extern long KEYOVERLAPPERIOD;
+extern long KEYGRACEPERIOD;
+extern int NUMCOPIES;
+extern char CHAIN[];
+extern int DISTANCE;
+extern int MINREL;
+extern int RELFINAL;
+extern long MAXLAT;
+extern long MINLAT;
+DLLIMPORT extern char PGPPUBRING[];
+DLLIMPORT extern char PGPSECRING[];
+DLLIMPORT extern char PASSPHRASE[];
+extern long POP3TIME;
+extern int POP3DEL;
+extern int POP3SIZELIMIT;
+extern char MAILBOX[];
+extern char MAILIN[];
+extern char MAILABUSE[];
+extern char MAILBLOCK[];
+extern char MAILUSAGE[];
+extern char MAILANON[];
+extern char MAILERROR[];
+extern char MAILBOUNCE[];
+DLLIMPORT extern int CLIENTAUTOFLUSH;
+extern int MAXRECIPIENTS;
+extern long TIMESKEW_FORWARD;
+extern long TIMESKEW_BACK;
+extern int TEMP_FAIL;
+extern char ALLPINGERSURL[];
+extern char ALLPINGERSFILE[];
+
+extern char WGET[];
+extern char STATSSRC[];
+extern int STATSAUTOUPDATE;
+extern long STATSINTERVAL;
+
+DLLIMPORT extern char ENTEREDPASSPHRASE[LINELEN];
+
+#endif
diff --git a/Src/crypto.c b/Src/crypto.c
@@ -0,0 +1,492 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Interface to cryptographic library
+ $Id: crypto.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include "crypto.h"
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef USE_OPENSSL
+int digestmem_md5(byte *b, int n, BUFFER *md)
+{
+ byte m[MD5_DIGEST_LENGTH];
+
+ MD5(b, n, m);
+ buf_reset(md);
+ buf_append(md, m, MD5_DIGEST_LENGTH);
+ return (0);
+}
+
+int digest_md5(BUFFER *b, BUFFER *md)
+{
+ return (digestmem_md5(b->data, b->length, md));
+}
+
+int isdigest_md5(BUFFER *b, BUFFER *md)
+{
+ int ret;
+ BUFFER *newmd;
+
+ newmd = buf_new();
+ digest_md5(b, newmd);
+ ret = buf_eq(md, newmd);
+ buf_free(newmd);
+ return (ret);
+}
+
+static int digestmem_sha1(byte *b, int n, BUFFER *md)
+{
+ byte m[SHA_DIGEST_LENGTH];
+
+ SHA1(b, n, m);
+ buf_reset(md);
+ buf_append(md, m, SHA_DIGEST_LENGTH);
+ return (0);
+}
+
+int digest_sha1(BUFFER *b, BUFFER *md)
+{
+ return (digestmem_sha1(b->data, b->length, md));
+}
+
+static int digestmem_rmd160(byte *b, int n, BUFFER *md)
+{
+ byte m[RIPEMD160_DIGEST_LENGTH];
+
+ RIPEMD160(b, n, m);
+ buf_reset(md);
+ buf_append(md, m, RIPEMD160_DIGEST_LENGTH);
+ return (0);
+}
+
+int digest_rmd160(BUFFER *b, BUFFER *md)
+{
+ return (digestmem_rmd160(b->data, b->length, md));
+}
+
+#define MAX_RSA_MODULUS_LEN 128
+
+static int read_seckey(BUFFER *buf, SECKEY *key, const byte id[])
+{
+ BUFFER *md;
+ int bits;
+ int len, plen;
+ byte *ptr;
+ int err = 0;
+
+ md = buf_new();
+ bits = buf->data[0] + 256 * buf->data[1];
+ len = (bits + 7) / 8;
+ plen = (len + 1) / 2;
+
+ /* due to encryption, buffer size is multiple of 8 */
+ if (3 * len + 5 * plen + 8 < buf->length || 3 * len + 5 * plen > buf->length)
+ return (-1);
+
+ ptr = buf->data + 2;
+
+ key->n = BN_bin2bn(ptr, len, NULL);
+ buf_append(md, ptr, len);
+ ptr += len;
+
+ key->e = BN_bin2bn(ptr, len, NULL);
+ buf_append(md, ptr, len);
+ ptr += len;
+
+ key->d = BN_bin2bn(ptr, len, NULL);
+ ptr += len;
+
+ key->p = BN_bin2bn(ptr, plen, NULL);
+ ptr += plen;
+
+ key->q = BN_bin2bn(ptr, plen, NULL);
+ ptr += plen;
+
+ key->dmp1 = BN_bin2bn(ptr, plen, NULL);
+ ptr += plen;
+
+ key->dmq1 = BN_bin2bn(ptr, plen, NULL);
+ ptr += plen;
+
+ key->iqmp = BN_bin2bn(ptr, plen, NULL);
+ ptr += plen;
+
+ digest_md5(md, md);
+ if (id)
+ err = (memcmp(id, md->data, 16) == 0) ? 0 : -1;
+ buf_free(md);
+ return (err);
+}
+
+static int read_pubkey(BUFFER *buf, PUBKEY *key, const byte id[])
+{
+ BUFFER *md;
+ int bits;
+ int len;
+ byte *ptr;
+ int err = 0;
+
+ md = buf_new();
+ bits = buf->data[0] + 256 * buf->data[1];
+ len = (bits + 7) / 8;
+
+ if (2 * len + 2 != buf->length)
+ return (-1);
+
+ ptr = buf->data + 2;
+
+ key->n = BN_bin2bn(ptr, len, NULL);
+ buf_append(md, ptr, len);
+ ptr += len;
+
+ key->e = BN_bin2bn(ptr, len, NULL);
+ buf_append(md, ptr, len);
+ ptr += len;
+
+ digest_md5(md, md);
+ if (id)
+ err = (memcmp(id, md->data, 16) == 0) ? 0 : -1;
+ buf_free(md);
+ return (err);
+}
+
+static int write_seckey(BUFFER *sk, SECKEY *key, byte keyid[])
+{
+ byte l[128];
+ int n;
+ BUFFER *b, *temp;
+
+ b = buf_new();
+ temp = buf_new();
+
+ n = BN_bn2bin(key->n, l);
+ assert(n <= 128);
+ if (n < 128)
+ buf_appendzero(b, 128 - n);
+ buf_append(b, l, n);
+
+ n = BN_bn2bin(key->e, l);
+ assert(n <= 128);
+ if (n < 128)
+ buf_appendzero(b, 128 - n);
+ buf_append(b, l, n);
+
+ digest_md5(b, temp);
+ memcpy(keyid, temp->data, 16);
+
+ buf_appendc(sk, 0);
+ buf_appendc(sk, 4);
+ buf_cat(sk, b);
+
+ n = BN_bn2bin(key->d, l);
+ assert(n <= 128);
+ if (n < 128)
+ buf_appendzero(sk, 128 - n);
+ buf_append(sk, l, n);
+
+ n = BN_bn2bin(key->p, l);
+ assert(n <= 64);
+ if (n < 64)
+ buf_appendzero(sk, 64 - n);
+ buf_append(sk, l, n);
+
+ n = BN_bn2bin(key->q, l);
+ assert(n <= 64);
+ if (n < 64)
+ buf_appendzero(sk, 64 - n);
+ buf_append(sk, l, n);
+
+ n = BN_bn2bin(key->dmp1, l);
+ assert(n <= 64);
+ if (n < 64)
+ buf_appendzero(sk, 64 - n);
+ buf_append(sk, l, n);
+
+ n = BN_bn2bin(key->dmq1, l);
+ assert(n <= 64);
+ if (n < 64)
+ buf_appendzero(sk, 64 - n);
+ buf_append(sk, l, n);
+
+ n = BN_bn2bin(key->iqmp, l);
+ assert(n <= 64);
+ if (n < 64)
+ buf_appendzero(sk, 64 - n);
+ buf_append(sk, l, n);
+
+ buf_pad(sk, 712); /* encrypt needs a block size multiple of 8 */
+
+ buf_free(temp);
+ buf_free(b);
+ return (0);
+}
+
+static int write_pubkey(BUFFER *pk, PUBKEY *key, byte keyid[])
+{
+ byte l[128];
+ int n;
+
+ buf_appendc(pk, 0);
+ buf_appendc(pk, 4);
+ n = BN_bn2bin(key->n, l);
+ assert(n <= 128);
+ if (n < 128)
+ buf_appendzero(pk, 128 - n);
+ buf_append(pk, l, n);
+ n = BN_bn2bin(key->e, l);
+ assert(n <= 128);
+ if (n < 128)
+ buf_appendzero(pk, 128 - n);
+ buf_append(pk, l, n);
+ return (0);
+}
+
+int seckeytopub(BUFFER *pub, BUFFER *sec, byte keyid[])
+{
+ RSA *k;
+ int err = 0;
+
+ k = RSA_new();
+ err = read_seckey(sec, k, keyid);
+ if (err == 0)
+ err = write_pubkey(pub, k, keyid);
+ RSA_free(k);
+ return (err);
+}
+
+int check_pubkey(BUFFER *buf, const byte id[])
+{
+ RSA *tmp;
+ int ret;
+
+ tmp = RSA_new();
+ ret = read_pubkey(buf, tmp, id);
+ RSA_free(tmp);
+ return (ret);
+}
+
+int check_seckey(BUFFER *buf, const byte id[])
+{
+ RSA *tmp;
+ int ret;
+
+ tmp = RSA_new();
+ ret = read_seckey(buf, tmp, id);
+ RSA_free(tmp);
+ return (ret);
+}
+
+int v2createkey(void)
+{
+ RSA *k;
+ BUFFER *b, *ek, *iv;
+ int err;
+ FILE *f;
+ byte keyid[16];
+ char line[33];
+
+ b = buf_new();
+ ek = buf_new();
+ iv = buf_new();
+
+ errlog(NOTICE, "Generating RSA key.\n");
+ k = RSA_generate_key(1024, 65537, NULL, NULL);
+ err = write_seckey(b, k, keyid);
+ RSA_free(k);
+ if (err == 0) {
+ f = mix_openfile(SECRING, "a");
+ if (f != NULL) {
+ time_t now = time(NULL);
+ struct tm *gt;
+ gt = gmtime(&now);
+ strftime(line, LINELEN, "%Y-%m-%d", gt);
+ fprintf(f, "%s\nCreated: %s\n", begin_key, line);
+ if (KEYLIFETIME) {
+ now += KEYLIFETIME;
+ gt = gmtime(&now);
+ strftime(line, LINELEN, "%Y-%m-%d", gt);
+ fprintf(f, "Expires: %s\n", line);
+ }
+ id_encode(keyid, line);
+ buf_appends(ek, PASSPHRASE);
+ digest_md5(ek, ek);
+ buf_setrnd(iv, 8);
+ buf_crypt(b, ek, iv, ENCRYPT);
+ encode(b, 40);
+ encode(iv, 0);
+ fprintf(f, "%s\n0\n%s\n", line, iv->data);
+ buf_write(b, f);
+ fprintf(f, "%s\n\n", end_key);
+ fclose(f);
+ } else
+ err = -1;
+ }
+ if (err != 0)
+ errlog(ERRORMSG, "Key generation failed.\n");
+
+ buf_free(b);
+ buf_free(ek);
+ buf_free(iv);
+ return (err);
+}
+
+int pk_decrypt(BUFFER *in, BUFFER *keybuf)
+{
+ int err = 0;
+ BUFFER *out;
+ RSA *key;
+
+ out = buf_new();
+ key = RSA_new();
+ read_seckey(keybuf, key, NULL);
+
+ buf_prepare(out, in->length);
+ out->length = RSA_private_decrypt(in->length, in->data, out->data, key,
+ RSA_PKCS1_PADDING);
+ if (out->length == -1)
+ err = -1, out->length = 0;
+
+ RSA_free(key);
+ buf_move(in, out);
+ buf_free(out);
+ return (err);
+}
+
+int pk_encrypt(BUFFER *in, BUFFER *keybuf)
+{
+ BUFFER *out;
+ RSA *key;
+ int err = 0;
+
+ out = buf_new();
+ key = RSA_new();
+ read_pubkey(keybuf, key, NULL);
+
+ buf_prepare(out, RSA_size(key));
+ out->length = RSA_public_encrypt(in->length, in->data, out->data, key,
+ RSA_PKCS1_PADDING);
+ if (out->length == -1)
+ out->length = 0, err = -1;
+ buf_move(in, out);
+ buf_free(out);
+ RSA_free(key);
+ return (err);
+}
+int buf_crypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc)
+{
+ des_key_schedule ks1;
+ des_key_schedule ks2;
+ des_key_schedule ks3;
+ des_cblock i;
+
+ assert(enc == ENCRYPT || enc == DECRYPT);
+ assert((key->length == 16 || key->length == 24) && iv->length == 8);
+ assert(buf->length % 8 == 0);
+
+ memcpy(i, iv->data, 8); /* leave iv buffer unchanged */
+ des_set_key((const_des_cblock *) key->data, ks1);
+ des_set_key((const_des_cblock *) (key->data + 8), ks2);
+ if (key->length == 16)
+ des_set_key((const_des_cblock *) key->data, ks3);
+ else
+ des_set_key((const_des_cblock *) (key->data + 16), ks3);
+ des_ede3_cbc_encrypt(buf->data, buf->data, buf->length, ks1, ks2, ks3,
+ &i, enc);
+ return (0);
+}
+
+int buf_3descrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc)
+{
+ int n = 0;
+ des_key_schedule ks1;
+ des_key_schedule ks2;
+ des_key_schedule ks3;
+
+ assert(enc == ENCRYPT || enc == DECRYPT);
+ assert(key->length == 24 && iv->length == 8);
+
+ des_set_key((const_des_cblock *) key->data, ks1);
+ des_set_key((const_des_cblock *) (key->data + 8), ks2);
+ des_set_key((const_des_cblock *) (key->data + 16), ks3);
+ des_ede3_cfb64_encrypt(buf->data, buf->data, buf->length, ks1, ks2, ks3,
+ (des_cblock *) iv->data, &n, enc);
+ return (0);
+}
+
+int buf_bfcrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc)
+{
+ int n = 0;
+ BF_KEY ks;
+
+ if (key == NULL || key->length == 0)
+ return (-1);
+
+ assert(enc == ENCRYPT || enc == DECRYPT);
+ assert(key->length == 16 && iv->length == 8);
+ BF_set_key(&ks, key->length, key->data);
+ BF_cfb64_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n,
+ enc == ENCRYPT ? BF_ENCRYPT : BF_DECRYPT);
+ return (0);
+}
+
+int buf_castcrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc)
+{
+ int n = 0;
+ CAST_KEY ks;
+
+ if (key == NULL || key->length == 0)
+ return (-1);
+
+ assert(enc == ENCRYPT || enc == DECRYPT);
+ assert(key->length == 16 && iv->length == 8);
+ CAST_set_key(&ks, 16, key->data);
+ CAST_cfb64_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n,
+ enc == ENCRYPT ? CAST_ENCRYPT : CAST_DECRYPT);
+ return (0);
+}
+
+#ifdef USE_AES
+int buf_aescrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc)
+{
+ int n = 0;
+ AES_KEY ks;
+
+ if (key == NULL || key->length == 0)
+ return (-1);
+
+ assert(enc == ENCRYPT || enc == DECRYPT);
+ assert((key->length == 16 || key->length == 24 || key->length == 32) && iv->length == 16);
+ AES_set_encrypt_key(key->data, key->length<<3, &ks);
+ AES_cfb128_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n,
+ enc == ENCRYPT ? AES_ENCRYPT : AES_DECRYPT);
+ return (0);
+}
+#endif /* USE_AES */
+
+#ifdef USE_IDEA
+int buf_ideacrypt(BUFFER *buf, BUFFER *key, BUFFER *iv, int enc)
+{
+ int n = 0;
+ IDEA_KEY_SCHEDULE ks;
+
+ if (key == NULL || key->length == 0)
+ return (-1);
+
+ assert(enc == ENCRYPT || enc == DECRYPT);
+ assert(key->length == 16 && iv->length == 8);
+ idea_set_encrypt_key(key->data, &ks);
+ idea_cfb64_encrypt(buf->data, buf->data, buf->length, &ks, iv->data, &n,
+ enc == ENCRYPT ? IDEA_ENCRYPT : IDEA_DECRYPT);
+ return (0);
+}
+#endif /* USE_IDEA */
+#endif /* USE_OPENSSL */
diff --git a/Src/crypto.h b/Src/crypto.h
@@ -0,0 +1,48 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Interface to cryptographic library
+ $Id: crypto.h 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#ifndef _CRYPTO_H
+#define _CRYPTO_H
+#include "mix3.h"
+
+#ifdef USE_OPENSSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER < 0x0903100)
+#error "This version of OpenSSL is not supported. Please get a more current version from http://www.openssl.org"
+#endif /* version check */
+#include <openssl/des.h>
+#include <openssl/blowfish.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#ifdef USE_IDEA
+#include <openssl/idea.h>
+#endif /* USE_IDEA */
+#ifdef USE_AES
+#include <openssl/aes.h>
+#endif /* USE_AES */
+#include <openssl/cast.h>
+#include <openssl/rand.h>
+
+typedef RSA PUBKEY;
+typedef RSA SECKEY;
+
+#else /* end of USE_OPENSSL */
+/* #error "No crypto library." */
+typedef void PUBKEY;
+typedef void SECKEY;
+#endif /* else not USE_OPENSSL */
+
+#endif /* ifndef _CRYPTO_H */
diff --git a/Src/dllmain.c b/Src/dllmain.c
@@ -0,0 +1,35 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Mixmaster DLL startup
+ $Id: dllmain.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#ifdef WIN32
+int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
+{
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ if(!is_nt_service()) {
+ rnd_state = RND_WILLSEED;
+ mix_init(NULL);
+ if (rnd_state == RND_WILLSEED)
+ rnd_state = RND_NOTSEEDED;
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ if(!is_nt_service())
+ mix_exit();
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ return(0);
+ }
+ return(1);
+}
+#endif /* WIN32 */
diff --git a/Src/dummy.c b/Src/dummy.c
@@ -0,0 +1,16 @@
+/* Dummy function for programs that don't use menuutil.c */
+
+#include "mix3.h"
+
+int menu_getuserpass(BUFFER *b, int i)
+{
+ return -1;
+}
+
+void cl(int y, int x)
+{}
+
+int download_stats(char *sourcename)
+{
+ return -1;
+}
diff --git a/Src/keymgt.c b/Src/keymgt.c
@@ -0,0 +1,434 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Key management
+ $Id: keymgt.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+int getv2seckey(byte keyid[], BUFFER *key);
+static int getv2pubkey(byte keyid[], BUFFER *key);
+
+int db_getseckey(byte keyid[], BUFFER *key)
+{
+ if (getv2seckey(keyid, key) == -1)
+ return (-1);
+ else
+ return (0);
+}
+
+int db_getpubkey(byte keyid[], BUFFER *key)
+{
+ if (getv2pubkey(keyid, key) == -1)
+ return (-1);
+ else
+ return (0);
+}
+
+/* now accepts NULL keyid too, with NULL keyid any key
+ * will be matched, with valid passphrase of course */
+int getv2seckey(byte keyid[], BUFFER *key)
+{
+ FILE *keyring;
+ BUFFER *iv, *pass, *temp;
+ char idstr[KEY_ID_LEN+2];
+ char line[LINELEN];
+ int err = -1;
+ char *res;
+ time_t created, expires;
+
+ pass = buf_new();
+ iv = buf_new();
+ temp = buf_new();
+ if (keyid)
+ id_encode(keyid, idstr);
+ else
+ idstr[0] = 0;
+ strcat(idstr, "\n");
+ if ((keyring = mix_openfile(SECRING, "r")) == NULL) {
+ errlog(ERRORMSG, "No secret key file!\n");
+ } else {
+ while (err == -1) {
+ buf_clear(key);
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ if (strleft(line, begin_key)) {
+ expires = 0;
+ created = 0;
+ do {
+ res = fgets(line, sizeof(line), keyring);
+ if (strileft(line, "created:")) {
+ created = parse_yearmonthday(strchr(line, ':')+1);
+ if (created == -1)
+ created = 0;
+ } else if (strileft(line, "expires:")) {
+ expires = parse_yearmonthday(strchr(line, ':')+1);
+ if (expires == -1)
+ expires = 0;
+ }
+ /* Fetch lines until we fail or get a non-header line */
+ } while ( res != NULL && strchr(line, ':') != NULL );
+ if (res == NULL)
+ break;
+ if (keyid && (strncmp(line, idstr, KEY_ID_LEN) != 0))
+ continue;
+ if (created != 0 && (created > time(NULL))) {
+ errlog(ERRORMSG, "Key is not valid yet (creation date in the future): %s", idstr);
+ break;
+ }
+ if (expires != 0 && (expires + KEYGRACEPERIOD < time(NULL))) {
+ errlog(ERRORMSG, "Key is expired: %s", idstr);
+ break;
+ }
+ fgets(line, sizeof(line), keyring);
+ fgets(line, sizeof(line), keyring);
+ buf_sets(iv, line);
+ decode(iv, iv);
+ for (;;) {
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ if (strleft(line, end_key)) {
+ if (decode(key, key) == -1) {
+ errlog(ERRORMSG, "Corrupt secret key.\n");
+ break;
+ }
+ buf_sets(pass, PASSPHRASE);
+ digest_md5(pass, pass);
+ buf_crypt(key, pass, iv, DECRYPT);
+ err = check_seckey(key, keyid);
+ if (err == -1)
+ errlog(ERRORMSG, "Corrupt secret key. Bad passphrase?\n");
+ break;
+ }
+ buf_append(key, line, strlen(line) - 1);
+ }
+ break;
+ }
+ }
+ fclose(keyring);
+ }
+
+ buf_free(pass);
+ buf_free(iv);
+ buf_free(temp);
+ return (err);
+}
+
+static int getv2pubkey(byte keyid[], BUFFER *key)
+{
+ FILE *keyring;
+ BUFFER *b, *temp, *iv;
+ char idstr[KEY_ID_LEN+2];
+ char line[LINELEN];
+ int err = 0;
+
+ b = buf_new();
+ iv = buf_new();
+ temp = buf_new();
+ id_encode(keyid, idstr);
+ if ((keyring = mix_openfile(PUBRING, "r")) == NULL) {
+ errlog(ERRORMSG, "Can't open %s!\n", PUBRING);
+ err = -1;
+ goto end;
+ }
+ for (;;) {
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ if (strleft(line, begin_key)) {
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ if ((strlen(line) > 0) && (line[strlen(line)-1] == '\n'))
+ line[strlen(line)-1] = '\0';
+ if ((strlen(line) > 0) && (line[strlen(line)-1] == '\r'))
+ line[strlen(line)-1] = '\0';
+ if (strncmp(line, idstr, KEY_ID_LEN) != 0)
+ continue;
+ fgets(line, sizeof(line), keyring); /* ignore length */
+ for (;;) {
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ goto done;
+ if (strleft(line, end_key))
+ goto done;
+ buf_append(key, line, strlen(line));
+ }
+ break;
+ }
+ }
+done:
+ fclose(keyring);
+
+ if (key->length == 0) {
+ errlog(ERRORMSG, "No such public key: %s\n", idstr);
+ err = -1;
+ goto end;
+ }
+ err = decode(key, key);
+ if (err != -1)
+ err = check_pubkey(key, keyid);
+ if (err == -1)
+ errlog(ERRORMSG, "Corrupt public key %s\n", idstr);
+end:
+ buf_free(b);
+ buf_free(iv);
+ buf_free(temp);
+ return (err);
+}
+
+int key(BUFFER *out)
+{
+ int err = -1;
+ FILE *f;
+ BUFFER *tmpkey;
+
+ tmpkey = buf_new();
+
+ buf_sets(out, "Subject: Remailer key for ");
+ buf_appends(out, SHORTNAME);
+ buf_appends(out, "\n\n");
+
+ keymgt(0);
+
+ conf_premail(out);
+ buf_nl(out);
+
+#ifdef USE_PGP
+ if (PGP) {
+ if (pgp_latestkeys(tmpkey, PGP_ES_RSA) == 0) {
+ buf_appends(out, "Here is the RSA PGP key:\n\n");
+ buf_cat(out, tmpkey);
+ buf_nl(out);
+ err = 0;
+ }
+ if (pgp_latestkeys(tmpkey, PGP_S_DSA) == 0) {
+ buf_appends(out, "Here is the DSA PGP key:\n\n");
+ buf_cat(out, tmpkey);
+ buf_nl(out);
+ err = 0;
+ }
+ }
+#endif /* USE_PGP */
+ if (MIX) {
+ if ((f = mix_openfile(KEYFILE, "r")) != NULL) {
+ buf_appends(out, "Here is the Mixmaster key:\n\n");
+ buf_appends(out, "=-=-=-=-=-=-=-=-=-=-=-=\n");
+ buf_read(out, f);
+ buf_nl(out);
+ fclose(f);
+ err = 0;
+ }
+ }
+ if (err == -1 && UNENCRYPTED) {
+ buf_appends(out, "The remailer accepts unencrypted messages.\n");
+ err = 0;
+ }
+ if (err == -1)
+ errlog(ERRORMSG, "Cannot create remailer keys!");
+
+ buf_free(tmpkey);
+
+ return (err);
+}
+
+int adminkey(BUFFER *out)
+{
+ int err = -1;
+ FILE *f;
+
+ buf_sets( out, "Subject: Admin key for the " );
+ buf_appends( out, SHORTNAME );
+ buf_appends( out, " remailer\n\n" );
+
+ if ( (f = mix_openfile( ADMKEYFILE, "r" )) != NULL ) {
+ buf_read( out, f );
+ buf_nl( out );
+ fclose( f );
+ err = 0;
+ }
+
+ if ( err == -1 )
+ errlog( ERRORMSG, "Can not read admin key file!\n" );
+
+ return err;
+}
+
+int v2keymgt(int force)
+/*
+ * Mixmaster v2 Key Management
+ *
+ * This function triggers creation of mix keys (see parameter force) which are
+ * stored in secring.mix. One public mix key is also written to key.txt. This
+ * is the key with the latest expiration date (keys with no expiration date
+ * are always considered newer if they appear later in the secret mix file
+ * - key creation appends keys).
+ *
+ * force:
+ * 0, 1: create key when necessary:
+ * - no key exists as of yet
+ * - old keys are due to expire/already expired
+ * 2: always create a new mix key.
+ *
+ * (force = 0 is used in mix_daily, and before remailer-key replies)
+ * (force = 1 is used by mixmaster -K)
+ * (force = 2 is used by mixmaster -G)
+ */
+{
+ FILE *keyring, *f;
+ char line[LINELEN];
+ byte k1[16], k1_found[16];
+ BUFFER *b, *temp, *iv, *pass, *pk, *pk_found;
+ int err = 0;
+ int found, foundnonexpiring;
+ time_t created, expires, created_found, expires_found;
+ char *res;
+
+ b = buf_new();
+ temp = buf_new();
+ iv = buf_new();
+ pass = buf_new();
+ pk = buf_new();
+ pk_found = buf_new();
+
+ foundnonexpiring = 0;
+ for (;;) {
+ found = 0;
+ created_found = 0;
+ expires_found = 0;
+
+ keyring = mix_openfile(SECRING, "r");
+ if (keyring != NULL) {
+ for (;;) {
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ if (strleft(line, begin_key)) {
+ expires = 0;
+ created = 0;
+ do {
+ res = fgets(line, sizeof(line), keyring);
+ if (strileft(line, "created:")) {
+ created = parse_yearmonthday(strchr(line, ':')+1);
+ if (created == -1)
+ created = 0;
+ } else if (strileft(line, "expires:")) {
+ expires = parse_yearmonthday(strchr(line, ':')+1);
+ if (expires == -1)
+ expires = 0;
+ }
+ /* Fetch lines until we fail or get a non-header line */
+ } while ( res != NULL && strchr(line, ':') != NULL );
+ if (res == NULL)
+ break;
+ if (((created != 0) && (created > time(NULL))) ||
+ ((expires != 0) && (expires < time(NULL)))) {
+ /* Key already is expired or has creation date in the future */
+ continue;
+ }
+ id_decode(line, k1);
+ fgets(line, sizeof(line), keyring);
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ buf_sets(iv, line);
+ decode(iv, iv);
+ buf_reset(b);
+ for (;;) {
+ if (fgets(line, sizeof(line), keyring) == NULL)
+ break;
+ if (strleft(line, end_key))
+ break;
+ buf_append(b, line, strlen(line) - 1);
+ }
+ if (decode(b, b) == -1)
+ break;
+ buf_sets(temp, PASSPHRASE);
+ digest_md5(temp, pass);
+ buf_crypt(b, pass, iv, DECRYPT);
+ buf_clear(pk);
+ if (seckeytopub(pk, b, k1) == 0) {
+ found = 1;
+ if (expires == 0 || (expires - KEYOVERLAPPERIOD >= time(NULL)))
+ foundnonexpiring = 1;
+ if (expires == 0 || (expires_found <= expires)) {
+ buf_clear(pk_found);
+ buf_cat(pk_found, pk);
+ memcpy(&k1_found, &k1, sizeof(k1));
+ expires_found = expires;
+ created_found = created;
+ }
+ }
+ }
+ }
+ fclose(keyring);
+ }
+
+ if (!foundnonexpiring || (force == 2)) {
+ v2createkey();
+ foundnonexpiring = 1;
+ force = 1;
+ } else
+ break;
+ };
+
+ if (found) {
+ if ((f = mix_openfile(KEYFILE, "w")) != NULL) {
+ id_encode(k1_found, line);
+ fprintf(f, "%s %s %s %s:%s %s%s", SHORTNAME,
+ REMAILERADDR, line, mixmaster_protocol, VERSION,
+ MIDDLEMAN ? "M" : "",
+ NEWS[0] == '\0' ? "C" : (strchr(NEWS, '@') ? "CNm" : "CNp"));
+ if (created_found) {
+ struct tm *gt;
+ gt = gmtime(&created_found);
+ strftime(line, LINELEN, "%Y-%m-%d", gt);
+ fprintf(f, " %s", line);
+ if (expires_found) {
+ struct tm *gt;
+ gt = gmtime(&expires_found);
+ strftime(line, LINELEN, "%Y-%m-%d", gt);
+ fprintf(f, " %s", line);
+ }
+ }
+ fprintf(f, "\n\n%s\n", begin_key);
+ id_encode(k1_found, line);
+ fprintf(f, "%s\n258\n", line);
+ encode(pk_found, 40);
+ buf_write(pk_found, f);
+ fprintf(f, "%s\n\n", end_key);
+ fclose(f);
+ }
+ } else
+ err = -1;
+
+ buf_free(b);
+ buf_free(temp);
+ buf_free(iv);
+ buf_free(pass);
+ buf_free(pk);
+ buf_free(pk_found);
+
+ return (err);
+}
+
+int keymgt(int force)
+{
+ /* force = 0: write key file if there is none
+ force = 1: update key file
+ force = 2: generate new key */
+ int err = 0;
+
+ if (REMAIL || force == 2) {
+ if (MIX && (err = v2keymgt(force)) == -1)
+ err = -1;
+#ifdef USE_PGP
+ if (PGP && (err = pgp_keymgt(force)) == -1)
+ err = -1;
+#endif /* USE_PGP */
+ }
+ return (err);
+}
diff --git a/Src/mail.c b/Src/mail.c
@@ -0,0 +1,898 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Socket-based mail transport services
+ $Id: mail.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(UNIX) && defined(USE_SOCK)
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif /* defined(UNIX) && defined(USE_SOCK) */
+
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+
+int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header)
+{
+ FILE *f = NULL, *log = NULL;
+ BUFFER *msg, *addr;
+ char line[LINELEN];
+ int ret = -1;
+
+ if (bufeq(address, ANONNAME))
+ return (0); /* don't reply to our own anon messages */
+ f = mix_openfile(name, "r");
+ if (f == NULL)
+ return (-1);
+
+ addr = buf_new();
+ rfc822_addr(address, addr);
+ if (addr->length == 0)
+ buf_set(addr, address), buf_nl(addr);
+
+ if (logname != NULL) {
+ if ((log = mix_openfile(logname, "r+")) != NULL) {
+ /* log recipients to prevent mail loop */
+ while (fgets(line, sizeof(line), log) != NULL)
+ if (strieq(line, addr->data))
+ goto end;
+ } else if ((log = mix_openfile(logname, "w")) == NULL) {
+ errlog(ERRORMSG, "Can't create %s.\n", logname);
+ ret = -1;
+ goto end;
+ }
+ fprintf(log, "%s", addr->data);
+ }
+ msg = buf_new();
+ if (header)
+ buf_cat(msg, header), buf_nl(msg);
+ while (fgets(line, sizeof(line), f) != NULL) {
+ if (streq(line, "DESTINATION-BLOCK\n"))
+ buf_appendf(msg, "destination-block %b", addr);
+ else
+ buf_appends(msg, line);
+ }
+ ret = sendmail(msg, REMAILERNAME, address);
+ buf_free(msg);
+end:
+ if (f)
+ fclose(f);
+ if (log)
+ fclose(log);
+ buf_free(addr);
+ return (ret);
+}
+
+int smtpsend(BUFFER *head, BUFFER *message, char *from);
+
+
+int sendmail_loop(BUFFER *message, char *from, BUFFER *address)
+{
+ BUFFER *msg;
+ int err;
+
+ msg = buf_new();
+ buf_appendf(msg, "X-Loop: %s\n", REMAILERADDR);
+ buf_cat(msg, message);
+ err = sendmail(msg, from, address);
+ buf_free(msg);
+
+ return(err);
+}
+
+/* Returns true if more than one of the recipients in the
+ * rcpt buffer is a remailer
+ */
+int has_more_than_one_remailer(BUFFER *rcpts)
+{
+ BUFFER *newlinelist;
+ BUFFER *line;
+ int remailers = 0;
+ REMAILER type1[MAXREM];
+ REMAILER type2[MAXREM];
+ int num1;
+ int num2;
+ int i;
+
+ newlinelist = buf_new();
+ line = buf_new();
+
+ num1 = t1_rlist(type1, NULL);
+ num2 = mix2_rlist(type2, NULL);
+
+ rfc822_addr(rcpts, newlinelist);
+
+ while (buf_getline(newlinelist, line) != -1) {
+ int found = 0;
+ printf("%s\n", line->data);
+
+ for (i = 0; i < num2; i++)
+ if (strcmp(type2[i].addr, line->data) == 0) {
+ found = 1;
+ break;
+ }
+ if (!found)
+ for (i = 0; i < num1; i++)
+ if (strcmp(type1[i].addr, line->data) == 0) {
+ found = 1;
+ break;
+ }
+ if (found)
+ remailers++;
+ }
+ printf("found %d\n", remailers);
+
+ buf_free(newlinelist);
+ buf_free(line);
+
+ return(remailers > 1);
+}
+
+int sendmail(BUFFER *message, char *from, BUFFER *address)
+{
+ /* returns: 0: ok 1: problem, try again -1: failed */
+
+ BUFFER *head, *block, *rcpt;
+ FILE *f;
+ int err = -1;
+ int rcpt_cnt;
+
+ head = buf_new();
+ rcpt = buf_new();
+
+ block = readdestblk( );
+ if ( !block ) block = buf_new( );
+
+ if (address != NULL &&
+ (address->length == 0 || doblock(address, block, 1) == -1))
+ goto end;
+
+ if (from != NULL) {
+ buf_setf(head, "From: %s", from);
+ hdr_encode(head, 255);
+ buf_nl(head);
+ }
+ if (address != NULL)
+ buf_appendf(head, "To: %b\n", address);
+
+ if (PRECEDENCE[0])
+ buf_appendf(head, "Precedence: %s\n", PRECEDENCE);
+
+ buf_rewind(message);
+
+ /* search recipient addresses */
+ if (address == NULL) {
+ BUFFER *field, *content;
+ field = buf_new();
+ content = buf_new();
+
+ rcpt_cnt = 0;
+ while (buf_getheader(message, field, content) == 0) {
+ if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
+ int thislinercpts = 1;
+ char *tmp = content->data;
+ while ((tmp = strchr(tmp+1, ',')))
+ thislinercpts ++;
+ rcpt_cnt += thislinercpts;
+
+ if ( rcpt->data[0] )
+ buf_appends(rcpt, ", ");
+ buf_cat(rcpt, content);
+ }
+ }
+ buf_free(field);
+ buf_free(content);
+ } else if (address->data[0]) {
+ char *tmp = address->data;
+ rcpt_cnt = 1;
+ while ((tmp = strchr(tmp+1, ',')))
+ rcpt_cnt ++;
+
+ buf_set(rcpt, address);
+ } else
+ rcpt_cnt = 0;
+
+ buf_rewind(message);
+
+ if ( ! rcpt_cnt ) {
+ errlog(NOTICE, "No recipients found.\n");
+ err = 0;
+ } else if ( rcpt_cnt > MAXRECIPIENTS ) {
+ errlog(NOTICE, "Too many recipients. Dropping message.\n");
+ err = 0;
+ } else if ( rcpt_cnt > 1 && has_more_than_one_remailer(rcpt) ) {
+ errlog(NOTICE, "Message is destined to more than one remailer. Dropping.\n");
+ err = 0;
+ } else if ( REMAIL && strcmp(REMAILERADDR, rcpt->data) == 0) {
+ buf_cat(head, message);
+ errlog(LOG, "Message loops back to us; storing in pool rather than sending it.\n");
+ err = pool_add(head, "inf");
+ } else if (SMTPRELAY[0])
+ err = smtpsend(head, message, from);
+ else if (strieq(SENDMAIL, "outfile")) {
+ char path[PATHMAX];
+ FILE *f = NULL;
+#ifdef SHORTNAMES
+ int i;
+ for (i = 0; i < 10000; i++) {
+ snprintf(path, PATHMAX, "%s%cout%i.txt", POOLDIR, DIRSEP, i);
+ f = fopen(path, "r");
+ if (f)
+ fclose(f);
+ else
+ break;
+ }
+ f = fopen(path, "w");
+#else /* end of SHORTNAMES */
+ static unsigned long namecounter = 0;
+ struct stat statbuf;
+ int count;
+ char hostname[64];
+
+ hostname[0] = '\0';
+ gethostname(hostname, 63);
+ hostname[63] = '\0';
+
+ /* Step 2: Stat the file. Wait for ENOENT as a response. */
+ for (count = 0;; count++) {
+ snprintf(path, PATHMAX, "%s%cout.%lu.%u_%lu.%s,S=%lu.txt",
+ POOLDIR, DIRSEP, time(NULL), getpid(), namecounter++, hostname, head->length + message->length);
+
+ if (stat(path, &statbuf) == 0)
+ errno = EEXIST;
+ else if (errno == ENOENT) { /* create the file (at least try) */
+ f = fopen(path, "w");
+ if (f != NULL)
+ break; /* we managed to open the file */
+ }
+ if (count > 5)
+ break; /* Too many retries - give up */
+ sleep(2); /* sleep and retry */
+ }
+#endif /* else not SHORTNAMES */
+ if (f != NULL) {
+ err = buf_write(head, f);
+ err = buf_write(message, f);
+ fclose(f);
+ } else
+ errlog(ERRORMSG, "Can't create %s!\n", path);
+ } else {
+ if (SENDANONMAIL[0] != '\0' && (from == NULL || streq(from, ANONNAME)))
+ f = openpipe(SENDANONMAIL);
+ else
+ f = openpipe(SENDMAIL);
+ if (f != NULL) {
+ err = buf_write(head, f);
+ err = buf_write(message, f);
+ closepipe(f);
+ }
+ }
+ if (err != 0) {
+ errlog(ERRORMSG, "Unable to execute sendmail. Check path!\n");
+ err = 1; /* error while sending, retry later */
+ }
+
+end:
+ buf_free(block);
+ buf_free(head);
+ buf_free(rcpt);
+ return (err);
+}
+
+/* socket communication **********************************************/
+
+#ifdef USE_SOCK
+#ifdef WIN32
+WSADATA w;
+
+int sock_init()
+{
+ if (WSAStartup(MAKEWORD(2, 0), &w) != 0) {
+ errlog(ERRORMSG, "Unable to initialize WINSOCK.\n");
+ return 0;
+ }
+ return 1;
+}
+
+void sock_exit(void)
+{
+ WSACleanup();
+}
+#endif /* WIN32 */
+
+SOCKET opensocket(char *hostname, int port)
+{
+ struct hostent *hp;
+ struct sockaddr_in server;
+ SOCKET s;
+
+ if ((hp = gethostbyname(hostname)) == NULL)
+ return (INVALID_SOCKET);
+
+ memset((char *) &server, 0, sizeof(server));
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = *(unsigned long *) hp->h_addr;
+ server.sin_port = htons((unsigned short) port);
+
+ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s != INVALID_SOCKET)
+ if (connect(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
+ closesocket(s);
+ return (INVALID_SOCKET);
+ }
+ return (s);
+}
+
+#ifndef WIN32
+int closesocket(SOCKET s)
+{
+ return (close(s));
+}
+#endif /* ifndef WIN32 */
+
+int sock_getline(SOCKET s, BUFFER *line)
+{
+ char c;
+ int ok;
+
+ buf_clear(line);
+ while ((ok = recv(s, &c, 1, 0)) > 0) {
+ if (c == '\n')
+ break;
+ if (c != '\r')
+ buf_appendc(line, c);
+ }
+ if (ok <= 0)
+ return (-1);
+ if (line->length == 0)
+ return (1);
+ return (0);
+}
+
+int sock_cat(SOCKET s, BUFFER *b)
+{
+ int p = 0, n;
+
+ do {
+ n = send(s, b->data, b->length, 0);
+ if (n < 0)
+ return (-1);
+ p += n;
+ } while (p < b->length);
+ return (0);
+}
+#else /* end of USE_SOCK */
+SOCKET opensocket(char *hostname, int port)
+{
+ return (INVALID_SOCKET);
+}
+
+int closesocket(SOCKET s)
+{
+ return (INVALID_SOCKET);
+}
+
+int sock_getline(SOCKET s, BUFFER *line)
+{
+ return (-1);
+}
+
+int sock_cat(SOCKET s, BUFFER *b)
+{
+ return (-1);
+}
+#endif /* else not USE_SOCK */
+
+/* send messages by SMTP ************************************************/
+
+static int sock_getsmtp(SOCKET s, BUFFER *response)
+{
+ int ret;
+ BUFFER *line;
+ line = buf_new();
+
+ buf_clear(response);
+ do {
+ ret = sock_getline(s, line);
+ buf_cat(response, line);
+ } while (line->length >= 4 && line->data[3] == '-');
+ buf_free(line);
+ return (ret);
+}
+
+SOCKET smtp_open(void)
+{
+ int s = INVALID_SOCKET;
+ int esmtp = 0;
+ BUFFER *line;
+
+#ifdef USE_SOCK
+ if (SMTPRELAY[0] != '\0')
+ s = opensocket(SMTPRELAY, 25);
+ if (s != INVALID_SOCKET) {
+ line = buf_new();
+ sock_getsmtp(s, line);
+ if (bufifind(line, "ESMTP"))
+ esmtp = 1;
+ if (line->data[0] != '2') {
+ errlog(ERRORMSG, "SMTP relay not ready. %b\n", line);
+ closesocket(s);
+ s = INVALID_SOCKET;
+ } else {
+ errlog(DEBUGINFO, "Opening SMTP connection.\n");
+ if (esmtp)
+ buf_sets(line, "EHLO ");
+ else
+ buf_sets(line, "HELO ");
+ if (HELONAME[0])
+ buf_appends(line, HELONAME);
+ else if (strchr(ENVFROM, '@'))
+ buf_appends(line, strchr(ENVFROM, '@') + 1);
+ else {
+ struct sockaddr_in sa;
+ int len = sizeof(sa);
+ struct hostent *hp;
+
+ if (getsockname(s, (struct sockaddr *) &sa, &len) == 0 &&
+ (hp = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr),
+ AF_INET)) != NULL)
+ buf_appends(line, (char *) hp->h_name);
+ else if (strchr(REMAILERADDR, '@'))
+ buf_appends(line, strchr(REMAILERADDR, '@') + 1);
+ else
+ buf_appends(line, SHORTNAME);
+ }
+ buf_chop(line);
+ buf_appends(line, "\r\n");
+ sock_cat(s, line);
+ sock_getsmtp(s, line);
+ if (line->data[0] != '2') {
+ errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line);
+ closesocket(s);
+ s = INVALID_SOCKET;
+ } else if (SMTPUSERNAME[0] && esmtp && bufifind(line, "AUTH") && bufifind(line, "LOGIN")) {
+ buf_sets(line, "AUTH LOGIN\r\n");
+ sock_cat(s, line);
+ sock_getsmtp(s, line);
+ if (!bufleft(line, "334")) {
+ errlog(ERRORMSG, "SMTP AUTH fails: %b\n", line);
+ goto err;
+ }
+ buf_sets(line, SMTPUSERNAME);
+ encode(line, 0);
+ buf_appends(line, "\r\n");
+ sock_cat(s, line);
+ sock_getsmtp(s, line);
+ if (!bufleft(line, "334")) {
+ errlog(ERRORMSG, "SMTP username rejected: %b\n", line);
+ goto err;
+ }
+ buf_sets(line, SMTPPASSWORD);
+ encode(line, 0);
+ buf_appends(line, "\r\n");
+ sock_cat(s, line);
+ sock_getsmtp(s, line);
+ if (!bufleft(line, "235"))
+ errlog(ERRORMSG, "SMTP authentication failed: %b\n", line);
+ }
+ }
+err:
+ buf_free(line);
+ }
+#endif /* USE_SOCK */
+ return (s);
+}
+
+int smtp_close(SOCKET s)
+{
+ BUFFER *line;
+ int ret = -1;
+
+#ifdef USE_SOCK
+ line = buf_new();
+ buf_sets(line, "QUIT\r\n");
+ sock_cat(s, line);
+ if (sock_getsmtp(s, line) == 0 && line->data[0] == '2') {
+ errlog(DEBUGINFO, "Closing SMTP connection.\n");
+ ret = 0;
+ } else
+ errlog(WARNING, "SMTP quit failed: %b\n", line);
+ closesocket(s);
+ buf_free(line);
+#endif /* USE_SOCK */
+ return (ret);
+}
+
+int smtp_send(SOCKET relay, BUFFER *head, BUFFER *message, char *from)
+{
+ BUFFER *rcpt, *line, *field, *content;
+ int ret = -1;
+
+#ifdef USE_SOCK
+ line = buf_new();
+ field = buf_new();
+ content = buf_new();
+ rcpt = buf_new();
+
+ while (buf_getheader(head, field, content) == 0)
+ if (bufieq(field, "to"))
+#ifdef BROKEN_MTA
+ if (!bufifind(rcpt, content->data))
+ /* Do not add the same recipient twice.
+ Needed for brain-dead MTAs. */
+#endif /* BROKEN_MTA */
+ rfc822_addr(content, rcpt);
+ buf_rewind(head);
+
+ while (buf_isheader(message) && buf_getheader(message, field, content) == 0) {
+ if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
+#ifdef BROKEN_MTA
+ if (!bufifind(rcpt, content->data))
+ /* Do not add the same recipient twice.
+ Needed for brain-dead MTAs. */
+#endif /* BROKEN_MTA */
+ rfc822_addr(content, rcpt);
+ }
+ if (!bufieq(field, "bcc"))
+ buf_appendheader(head, field, content);
+ }
+ buf_nl(head);
+
+ buf_clear(content);
+ if (from) {
+ buf_sets(line, from);
+ rfc822_addr(line, content);
+ buf_chop(content);
+ }
+ if (bufieq(content, REMAILERADDR) || bufieq(content, ANONADDR))
+ buf_clear(content);
+ if (content->length == 0)
+ buf_sets(content, ENVFROM[0] ? ENVFROM : ANONADDR);
+
+ buf_setf(line, "MAIL FROM:<%b>\r\n", content);
+ sock_cat(relay, line);
+ sock_getsmtp(relay, line);
+ if (!line->data[0] == '2') {
+ errlog(ERRORMSG, "SMTP relay does not accept mail: %b\n", line);
+ goto end;
+ }
+ while (buf_getline(rcpt, content) == 0) {
+ buf_setf(line, "RCPT TO:<%b>\r\n", content);
+ sock_cat(relay, line);
+ sock_getsmtp(relay, line);
+ if (bufleft(line, "421")) {
+ errlog(ERRORMSG, "SMTP relay error: %b\n", line);
+ goto end;
+ }
+ if (bufleft(line, "530")) {
+ errlog(ERRORMSG, "SMTP authentication required: %b\n", line);
+ goto end;
+ }
+ }
+
+ buf_sets(line, "DATA\r\n");
+ sock_cat(relay, line);
+ sock_getsmtp(relay, line);
+ if (!bufleft(line, "354")) {
+ errlog(WARNING, "SMTP relay does not accept message: %b\n", line);
+ goto end;
+ }
+ while (buf_getline(head, line) >= 0) {
+ buf_appends(line, "\r\n");
+ if (bufleft(line, ".")) {
+ buf_setf(content, ".%b", line);
+ buf_move(line, content);
+ }
+ sock_cat(relay, line);
+ }
+ while (buf_getline(message, line) >= 0) {
+ buf_appends(line, "\r\n");
+ if (bufleft(line, ".")) {
+ buf_setf(content, ".%b", line);
+ buf_move(line, content);
+ }
+ sock_cat(relay, line);
+ }
+ buf_sets(line, ".\r\n");
+ sock_cat(relay, line);
+ sock_getsmtp(relay, line);
+ if (bufleft(line, "2"))
+ ret = 0;
+ else
+ errlog(WARNING, "SMTP relay will not send message: %b\n", line);
+end:
+ buf_free(line);
+ buf_free(field);
+ buf_free(content);
+ buf_free(rcpt);
+#endif /* USE_SOCK */
+ return (ret);
+}
+
+static SOCKET sendmail_state = INVALID_SOCKET;
+
+void sendmail_begin(void)
+{
+ /* begin mail sending session */
+ if (sendmail_state == INVALID_SOCKET)
+ sendmail_state = smtp_open();
+}
+void sendmail_end(void)
+{
+ /* end mail sending session */
+ if (sendmail_state != INVALID_SOCKET) {
+ smtp_close(sendmail_state);
+ sendmail_state = INVALID_SOCKET;
+ }
+}
+
+int smtpsend(BUFFER *head, BUFFER *message, char *from)
+{
+ SOCKET s;
+ int ret = -1;
+
+ if (sendmail_state != INVALID_SOCKET)
+ ret = smtp_send(sendmail_state, head, message, from);
+ else {
+ s = smtp_open();
+ if (s != INVALID_SOCKET) {
+ ret = smtp_send(s, head, message, from);
+ smtp_close(s);
+ }
+ }
+ return (ret);
+}
+
+/* retrieve mail with POP3 **********************************************/
+#ifdef USE_SOCK
+int pop3_close(SOCKET s);
+
+#define POP3_ANY 0
+#define POP3_APOP 1
+#define POP3_PASS 2
+
+SOCKET pop3_open(char *user, char *host, char *pass, int auth)
+{
+ SOCKET server = INVALID_SOCKET;
+ BUFFER *line;
+ int authenticated = 0;
+ char md[33];
+ int c;
+
+ line = buf_new();
+ server = opensocket(host, 110);
+ if (server == INVALID_SOCKET)
+ errlog(NOTICE, "Can't connect to POP3 server %s.\n", host);
+ else {
+ sock_getline(server, line);
+ if (!bufleft(line, "+")) {
+ errlog(WARNING, "No POP3 service at %s.\n", host);
+ closesocket(server);
+ server = INVALID_SOCKET;
+ }
+ }
+ if (server != INVALID_SOCKET) {
+ errlog(DEBUGINFO, "Opening POP3 connection to %s.\n", host);
+ do
+ c = buf_getc(line);
+ while (c != '<' && c != -1);
+ while (c != '>' && c != -1) {
+ buf_appendc(line, c);
+ c = buf_getc(line);
+ }
+ if (c == '>' && (auth == POP3_ANY || auth == POP3_APOP)) {
+ buf_appendc(line, c);
+ buf_appends(line, pass);
+ digest_md5(line, line);
+ id_encode(line->data, md);
+ buf_setf(line, "APOP %s %s\r\n", user, md);
+ sock_cat(server, line);
+ sock_getline(server, line);
+ if (bufleft(line, "+"))
+ authenticated = 1;
+ else {
+ errlog(auth == POP3_APOP ? ERRORMSG : NOTICE,
+ "POP3 APOP auth at %s failed: %b\n", host, line);
+ buf_sets(line, "QUIT\r\n");
+ sock_cat(server, line);
+ closesocket(server);
+ server = pop3_open(user, host, pass, POP3_PASS);
+ goto end;
+ }
+ }
+ if (!authenticated) {
+ buf_setf(line, "USER %s\r\n", user);
+ sock_cat(server, line);
+ sock_getline(server, line);
+ if (!bufleft(line, "+"))
+ errlog(ERRORMSG, "POP3 USER command at %s failed: %b\n", host, line);
+ else {
+ buf_setf(line, "PASS %s\r\n", pass);
+ sock_cat(server, line);
+ sock_getline(server, line);
+ if (bufleft(line, "+"))
+ authenticated = 1;
+ else
+ errlog(ERRORMSG, "POP3 auth at %s failed: %b\n", host, line);
+ }
+ }
+ if (!authenticated) {
+ pop3_close(server);
+ closesocket(server);
+ server = INVALID_SOCKET;
+ }
+ }
+ end:
+ buf_free(line);
+ return (server);
+}
+
+int pop3_close(SOCKET s)
+{
+ BUFFER *line;
+ int ret = -1;
+
+ line = buf_new();
+ buf_sets(line, "QUIT\r\n");
+ sock_cat(s, line);
+ sock_getline(s, line);
+ if (bufleft(line, "+")) {
+ ret = 0;
+ errlog(DEBUGINFO, "Closing POP3 connection.\n");
+ } else
+ errlog(ERRORMSG, "POP3 QUIT failed:\n", line->data);
+ buf_free(line);
+ return (ret);
+}
+
+int pop3_stat(SOCKET s)
+{
+ BUFFER *line;
+ int val = -1;
+
+ line = buf_new();
+ buf_sets(line, "STAT\r\n");
+ sock_cat(s, line);
+ sock_getline(s, line);
+ if (bufleft(line, "+"))
+ sscanf(line->data, "+%*s %d", &val);
+ buf_free(line);
+ return (val);
+}
+
+int pop3_list(SOCKET s, int n)
+{
+ BUFFER *line;
+ int val = -1;
+
+ line = buf_new();
+ buf_setf(line, "LIST %d\r\n", n);
+ sock_cat(s, line);
+ sock_getline(s, line);
+ if (bufleft(line, "+"))
+ sscanf(line->data, "+%*s %d", &val);
+ buf_free(line);
+ return (val);
+}
+
+int pop3_dele(SOCKET s, int n)
+{
+ BUFFER *line;
+ int ret = 0;
+
+ line = buf_new();
+ buf_setf(line, "DELE %d\r\n", n);
+ sock_cat(s, line);
+ sock_getline(s, line);
+ if (!bufleft(line, "+"))
+ ret = -1;
+ buf_free(line);
+ return (ret);
+}
+
+int pop3_retr(SOCKET s, int n, BUFFER *msg)
+{
+ BUFFER *line;
+ int ret = -1;
+
+ line = buf_new();
+ buf_clear(msg);
+ buf_setf(line, "RETR %d\r\n", n);
+ sock_cat(s, line);
+ sock_getline(s, line);
+ if (bufleft(line, "+")) {
+ for (;;) {
+ if (sock_getline(s, line) == -1)
+ break;
+ if (bufeq(line, ".")) {
+ ret = 0;
+ break;
+ } else if (bufleft(line, ".")) {
+ buf_append(msg, line->data + 1, line->length - 1);
+ } else
+ buf_cat(msg, line);
+ buf_nl(msg);
+ }
+ }
+ buf_free(line);
+ return (ret);
+}
+
+void pop3get(void)
+{
+ FILE *f;
+ char cfg[LINELEN], user[LINELEN], host[LINELEN], pass[LINELEN], auth[5];
+ SOCKET server;
+ BUFFER *line, *msg;
+ int i = 0, num = 0;
+
+ line = buf_new();
+ msg = buf_new();
+ f = mix_openfile(POP3CONF, "r");
+ if (f != NULL)
+ while (fgets(cfg, sizeof(cfg), f) != NULL) {
+ if (cfg[0] == '#')
+ continue;
+ if (strchr(cfg, '@'))
+ strchr(cfg, '@')[0] = ' ';
+ if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3)
+ continue;
+ i = POP3_ANY;
+ if (strileft(auth, "apop"))
+ i = POP3_APOP;
+ if (strileft(auth, "pass"))
+ i = POP3_PASS;
+ server = pop3_open(user, host, pass, i);
+ if (server != INVALID_SOCKET) {
+ num = pop3_stat(server);
+ if (num < 0)
+ errlog(WARNING, "POP3 protocol error at %s.\n", host);
+ else if (num == 0)
+ errlog(DEBUGINFO, "No mail at %s.\n", host);
+ else
+ for (i = 1; i <= num; i++) {
+ if (POP3SIZELIMIT > 0 &&
+ pop3_list(server, i) > POP3SIZELIMIT * 1024) {
+ errlog(WARNING, "Over size message on %s.", host);
+ if (POP3DEL == 1)
+ pop3_dele(server, i);
+ } else {
+ if (pop3_retr(server, i, msg) == 0 &&
+ pool_add(msg, "inf") == 0)
+ pop3_dele(server, i);
+ else {
+ errlog(WARNING, "POP3 error while getting mail from %s.",
+ host);
+ closesocket(server);
+ goto end;
+ }
+ }
+ }
+ pop3_close(server);
+ closesocket(server);
+ }
+ }
+ end:
+ if (f != NULL)
+ fclose(f);
+ buf_free(line);
+ buf_free(msg);
+}
+#endif /* USE_SOCK */
diff --git a/Src/maildir.c b/Src/maildir.c
@@ -0,0 +1,323 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Maildir support routines
+ $Id: $ */
+
+
+/* Maildir support for Mixmaster 3 - see
+ http://www.qmail.org/man/man5/maildir.html and
+ http://cr.yp.to/proto/maildir.html
+
+ Added by and (C) 2001 Doobee R. Tzeck
+ drt@un.bewaff.net - http://c0re.jp/
+
+ To test it try:
+ $ gcc maildir.c -DUNITTEST -o test_maildir
+ $ ./test_maildir
+ this should print a single line saying "OK"
+*/
+
+#include "mix3.h"
+
+#ifdef WIN32
+#include <io.h>
+#include <direct.h>
+#include <process.h>
+#define S_IWUSR _S_IWRITE
+#define S_IRUSR _S_IREAD
+#else /* end of WIN32 */
+#include <unistd.h>
+#endif /* else not WIN32 */
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if defined(S_IFDIR) && !defined(S_ISDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif /* defined(S_IFDIR) && !defined(S_ISDIR) */
+
+#ifndef SHORTNAMES
+
+static unsigned long namecounter = 0;
+
+int checkDirectory(char *dir, char *append, int create) {
+ char tmp[PATHMAX];
+ struct stat buf;
+ int err;
+
+ tmp[0] = '\0';
+ strcatn(tmp, dir, PATHMAX);
+ if (append)
+ strcatn(tmp, append, PATHMAX);
+
+ err = stat(tmp, &buf);
+ if (err == -1) {
+ if (create) {
+#ifndef POSIX
+ err = mkdir(tmp);
+#else /* end of not POSIX */
+ err = mkdir(tmp, S_IRWXU);
+#endif /* else if POSIX */
+ if (err == 0)
+ errlog(NOTICE, "Creating directory %s.\n", tmp);
+ } else
+ err = 1;
+ } else if (!S_ISDIR(buf.st_mode))
+ err = -1;
+
+ return err;
+}
+
+/* Write "message" to "maildir", retunr 0 on success, -1 on failure */
+#define MAX_BASENAME 113 /* actual length should be smaller than 111 bytes */
+#define MAX_SUBNAME 123 /* actual length should be smaller than 115 bytes */
+int maildirWrite(char *maildir, BUFFER *message, int create) {
+ int fd;
+ int count;
+ int returnValue;
+ char hostname[64];
+ struct stat statbuf;
+ char basename[MAX_BASENAME];
+ char tmpname[MAX_SUBNAME];
+ char newname[MAX_SUBNAME];
+ int messagesize;
+ char olddirectory[PATHMAX] = "";
+ char normalizedmaildir[PATHMAX];
+
+ /* Declare a handler for SIGALRM so we can time out. */
+ /* set_handler(SIGALRM, alarm_handler); */
+ /* alarm(86400); */
+
+ hostname[0] = '\0';
+ gethostname(hostname, 63);
+ hostname[63] = '\0';
+
+ mixfile(normalizedmaildir, maildir);
+ if ((checkDirectory(normalizedmaildir, NULL, create) != 0) ||
+ (checkDirectory(normalizedmaildir, "tmp", create) != 0) ||
+ (checkDirectory(normalizedmaildir, "cur", create) != 0) ||
+ (checkDirectory(normalizedmaildir, "new", create) != 0)) {
+ returnValue = -1;
+ goto realend;
+ }
+
+ messagesize = message->length;
+
+ /* Step 1: chdir to maildir (and save current dir) */
+ if (getcwd(olddirectory, PATHMAX) == NULL) {
+ returnValue = -1;
+ goto realend;
+ }
+ olddirectory[PATHMAX-1] = '\0';
+ if(chdir(normalizedmaildir) != 0) {
+ returnValue = -1;
+ goto functionExit;
+ }
+
+ /* Step 2: Stat the temporary file. Wait for ENOENT as a response. */
+ for (count = 0;; count++) {
+ tmpname[0] = '\0';
+ newname[0] = '\0';
+ snprintf(basename, MAX_BASENAME, "%lu.%u_%lu.%s,S=%u",
+ time(NULL), getpid(), namecounter++, hostname, messagesize);
+ basename[MAX_BASENAME-1] = '\0';
+ strcatn(tmpname, "tmp" DIRSEPSTR, MAX_SUBNAME);
+ strcatn(tmpname, basename, MAX_SUBNAME);
+ strcatn(newname, "new" DIRSEPSTR, MAX_SUBNAME);
+ strcatn(newname, basename, MAX_SUBNAME);
+
+ if (stat(tmpname, &statbuf) == 0)
+ errno = EEXIST;
+ else if (errno == ENOENT) {
+ /* Step 4: create the file (at least try) */
+ fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
+ if (fd >= 0)
+ break; /* we managed to open the file */
+ }
+
+ if (count > 5) {
+ /* Too many retries - give up */
+ errlog(ERRORMSG, "Can't create message in %s\n", maildir);
+ returnValue = -1;
+ goto functionExit;
+ }
+
+ /* Step 3: sleep and retry */
+ sleep(2);
+ }
+
+ /* Step 5: write file */
+ if(write(fd, message->data, message->length) != message->length) {
+ returnValue = -1;
+ goto functionExit;
+ }
+
+ /* on NFS this could fail */
+#ifndef WIN32
+ if((fsync(fd) != 0) || (close(fd) != 0)) {
+#else /* end of not WIN32 */
+ if((_commit(fd) != 0) || (close(fd) != 0)) {
+#endif /* else if WIN32 */
+ returnValue = -1;
+ goto functionExit;
+ }
+
+ /* Step 6: move message to 'cur' */
+#ifdef POSIX
+ for (count = 0;; count++) {
+ if(link(tmpname, newname) != 0) {
+ if (errno == EXDEV || errno == EPERM) {
+ /* We probably are on coda or some other filesystem that does not allow
+ * hardlinks. rename() the file instead of link() and unlink()
+ * I know, It's evil (PP).
+ */
+ if (rename(tmpname, newname) != 0) {
+ returnValue = -1;
+ goto functionExit;
+ };
+ break;
+ } else if (errno != EEXIST) {
+ returnValue = -1;
+ goto functionExit;
+ }
+ } else {
+ /* We successfully linked the message in new/. Now let's get
+ * rid of our tmp/ entry
+ */
+ if(unlink(tmpname) != 0) {
+ /* unlinking failed */
+ returnValue = -1;
+ goto functionExit;
+ }
+ break;
+ }
+
+ if (count > 5) {
+ /* Too many retries - give up */
+ errlog(ERRORMSG, "Can't move message to %s/new/\n", maildir);
+ returnValue = -1;
+ goto functionExit;
+ }
+
+ sleep(2);
+ newname[0] = '\0';
+ snprintf(basename, MAX_BASENAME, "%lu.%u_%lu.%s,S=%u",
+ time(NULL), getpid(), namecounter++, hostname, messagesize);
+ basename[MAX_BASENAME-1] = '\0';
+ strcatn(newname, "new" DIRSEPSTR, MAX_SUBNAME);
+ strcatn(newname, basename, MAX_SUBNAME);
+ }
+#else /* end of POSIX */
+ /* On non POSIX systems we simply use rename(). Let's hope DJB
+ * never finds out
+ */
+ if (rename(tmpname, newname) != 0) {
+ returnValue = -1;
+ goto functionExit;
+ };
+#endif /* else if not POSIX */
+
+ returnValue = 0;
+
+functionExit:
+ /* return to original directory */
+ assert(olddirectory[0] != '\0');
+ if(chdir(olddirectory) != 0)
+ returnValue = -1;
+
+realend:
+
+ return returnValue;
+}
+
+#else /* end of SHORTNAMES */
+int maildirWrite(char *maildir, BUFFER *message, int create) {
+{
+ errlog(ERRORMSG, "Maildir delivery does not work with SHORTNAMES.\n");
+ return -1;
+}
+#endif /* else if not SHORTNAMES */
+
+
+#ifdef UNITTEST
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif /* NDEBUG */
+
+#include <dirent.h>
+
+/* mock-up of errlog for unittest */
+void errlog(int type, char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+/* main for unittest */
+int main()
+{
+ int i, count = 23;
+ int fd;
+ DIR *d;
+ struct dirent *de;
+ BUFFER message;
+ char text[] = "From: nobody@un.bewaff.net\nTo: hackers@c0re.jp\nSubject: testing\n\nthis is just a test\n";
+ char buf[1024];
+
+ /* create buffer with test data */
+ message.data = text;
+ message.length = strlen(text);
+
+ /* write <count> messages to maildir */
+ for(i = 0; i < count; i++)
+ assert(maildirWrite("Maildir.test_maildir", message, 1) == 0);
+
+ /* read them back */
+ assert((d = opendir("Maildir.test_maildir/new")) != NULL);
+ for (i = 0; i < count + 2; i++)
+ {
+ de = readdir(d);
+ if(de->d_name[0] != '.')
+ {
+ buf[0] = '\0';
+ strcat(buf, "Maildir.test_maildir/new/");
+ strcat(buf, de->d_name);
+ fd = open(buf, O_RDONLY);
+ assert(unlink(buf) == 0);
+ assert(read(fd, buf, strlen(text)) == strlen(text));
+ buf[strlen(text)] = '\0';
+ /* check if they match the original message */
+ assert(strcmp(text, buf) == 0);
+ close(fd);
+ }
+ }
+
+ /* no files left in directory? */
+ assert(readdir(d) == NULL);
+
+ /* delete maildir */
+ assert(rmdir("Maildir.test_maildir/tmp") == 0);
+ assert(rmdir("Maildir.test_maildir/new") == 0);
+ assert(rmdir("Maildir.test_maildir/cur") == 0);
+ assert(rmdir("Maildir.test_maildir") == 0);
+
+ /* check if writing to a non existant maildir yilds an error */
+ assert(maildirWrite("Maildir.test_maildir", &message, 0) == -1);
+
+ puts("OK");
+}
+#endif /* UNITTEST */
diff --git a/Src/main.c b/Src/main.c
@@ -0,0 +1,820 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Command-line based frontend
+ $Id: main.c 937 2006-06-24 15:52:20Z colin $ */
+
+
+#include "mix3.h"
+#include "pgp.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifdef POSIX
+#include <unistd.h>
+#else /* end of POSIX */
+#include <io.h>
+#endif /* else if not POSIX */
+#include <assert.h>
+
+static char *largopt(char *p, char *opt, char *name, int *error);
+static void noarg(char *name, char p);
+static int check_get_pass(int force, int never_ask_for_passphrase);
+
+/** main *****************************************************************/
+
+/* Returns:
+ 0 successful operation
+ 1 command line error
+ 2 client error condition */
+
+#ifdef WIN32SERVICE
+int mix_main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif /* WIN32SERVICE */
+{
+ int error = 0, deflt = 1, help = 0, readmail = 0, send = -1, sendpool = 0,
+ header = 1, maint = 0, keygen = 0, verbose = 0, sign = 0, encrypt = 0,
+ redirect_mail = 0, about=0, version=0;
+ int daemon = 0, type_list = 0, nodetach = 0;
+ int update_stats = 0, update_pingerlist = 0;
+ int never_ask_for_passphrase = 0;
+
+#ifdef USE_SOCK
+ int pop3 = 0;
+
+#endif /* USE_SOCK */
+ char *filename = NULL;
+ int i;
+ int ret = 0;
+ char *p, *q;
+ char chain[1024] = "";
+ char nym[LINELEN] = "";
+ BUFFER *nymopt, *pseudonym, *attachments, *statssrc;
+ int numcopies = 0; /* default value set in mix.cfg */
+ BUFFER *msg, *chainlist, *field, *content;
+ FILE *f;
+ char pingpath[PATHMAX];
+
+ /* Check if parse_yearmonthday works */
+ assert(parse_yearmonthday("2003-04-01") == 1049155200);
+
+ mix_init(NULL);
+
+ msg = buf_new();
+ chainlist = buf_new();
+ nymopt = buf_new();
+ pseudonym = buf_new();
+ attachments = buf_new();
+ field = buf_new();
+ content = buf_new();
+ statssrc = buf_new();
+
+#ifdef USE_NCURSES
+ if (argc == 1) {
+ if (isatty(fileno(stdin)))
+ menu_main();
+ else
+ menu_folder(0, NULL);
+ goto clientpool;
+ }
+#endif /* USE_NCURSES */
+ if (argc > 1 && strleft(argv[1], "-f")) {
+ menu_folder(strlen(argv[1]) > 2 ? argv[1][2] : 0, argc < 3 ? NULL : argv[2]);
+ goto clientpool;
+ }
+ for (i = 1; i < argc; i++) {
+ p = argv[i];
+ if (p[0] == '-' && p[1] != '\0') {
+ if (p[1] == '-') {
+ p += 2;
+ if (strieq(p, "help"))
+ help = 1, deflt = 0;
+ else if (streq(p, "version"))
+ version = 1, deflt = 0;
+ else if (streq(p, "about"))
+ about = 1, deflt = 0;
+ else if (streq(p, "verbose"))
+ verbose = 1;
+ else if (streq(p, "type-list"))
+ type_list = 1;
+ else if (streq(p, "dummy"))
+ send = MSG_NULL, deflt = 0;
+ else if (streq(p, "remailer"))
+ maint = 1, deflt = 0;
+ else if (streq(p, "generate-key"))
+ keygen = 2, deflt = 0;
+ else if (streq(p, "update-keys"))
+ keygen = 1, deflt = 0;
+ else if (streq(p, "send"))
+ sendpool = 1, deflt = 0;
+ else if (streq(p, "read-mail"))
+ readmail = 1, deflt = 0;
+ else if (streq(p, "redirect"))
+ redirect_mail = 1, deflt = 0;
+ else if (streq(p, "store-mail"))
+ readmail = 2, deflt = 0;
+#ifdef USE_SOCK
+ else if (streq(p, "pop-mail"))
+ pop3 = 1, deflt = 0;
+#endif /* USE_SOCK */
+ else if (streq(p, "daemon"))
+ daemon = 1, deflt = 0;
+ else if (streq(p, "no-detach"))
+ nodetach = 1;
+ else if (streq(p, "post"))
+ send = MSG_POST;
+ else if (streq(p, "mail"))
+ send = MSG_MAIL;
+ else if (streq(p, "sign"))
+ sign = 1;
+ else if (streq(p, "encrypt"))
+ encrypt = 1;
+ else if (streq(p, "no-ask-passphrase"))
+ never_ask_for_passphrase = 1;
+ else if (streq(p, "update-pinger-list"))
+ update_pingerlist = 1;
+ else if (streq(p, "update-stats")) {
+ buf_clear(statssrc);
+ f = mix_openfile(STATSSRC, "r");
+ if (f != NULL) {
+ buf_read(statssrc, f);
+ fclose(f);
+ }
+ if (statssrc->length > 0) {
+ update_stats = 1;
+ } else {
+ deflt = 0;
+ fprintf(stderr, "%s: No current stats source --%s\n", argv[0], p);
+ }
+ } else if (strleft(p, "update-stats") && p[strlen("update-stats")] == '=') {
+ buf_clear(statssrc);
+ buf_appendf(statssrc, "%s", (p + strlen("update-stats") + 1));
+ if (statssrc->length > 0) {
+ update_stats = 1;
+ } else {
+ fprintf(stderr, "%s: No stats source specified --%s\n", argv[0], p);
+ }
+ } else if ((q = largopt(p, "to", argv[0], &error)) != NULL) {
+ header = 0;
+ buf_appendf(msg, "To: %s\n", q);
+ } else if ((q = largopt(p, "post-to", argv[0], &error)) != NULL) {
+ send = MSG_POST, header = 0;
+ buf_appendf(msg, "Newsgroups: %s\n", q);
+ } else if ((q = largopt(p, "subject", argv[0], &error)) != NULL) {
+ buf_appendf(msg, "Subject: %s\n", q);
+ } else if ((q = largopt(p, "header", argv[0], &error)) != NULL) {
+ buf_appendf(msg, "%s\n", q);
+ } else if ((q = largopt(p, "chain", argv[0], &error)) != NULL) {
+ buf_appendf(msg, "Chain: %s\n", q);
+ }
+#ifdef USE_PGP
+ else if ((q = largopt(p, "reply-chain", argv[0], &error)) != NULL) {
+ buf_appendf(msg, "Reply-Chain: %s\n", q);
+ } else if ((q = largopt(p, "latency", argv[0], &error)) != NULL) {
+ buf_appendf(msg, "Latency: %s\n", q);
+ } else if ((q = largopt(p, "attachment", argv[0], &error)) != NULL) {
+ buf_appendf(attachments, "%s\n", q);
+#ifdef NYMSUPPORT
+ } else if ((q = largopt(p, "nym-config", argv[0], &error)) != NULL) {
+ deflt = 0;
+ strncpy(nym, q, sizeof(nym));
+ if (i > argc && strileft(argv[i + 1], "name="))
+ buf_sets(pseudonym, argv[++i] + 5);
+ else if (i > argc && strileft(argv[i + 1], "opt="))
+ buf_appends(nymopt, argv[++i] + 5);
+ } else if ((q = largopt(p, "nym", argv[0], &error)) != NULL) {
+ buf_appendf(msg, "Nym: %s\n", q);
+#endif /* NYMSUPPORT */
+ }
+#endif /* USE_PGP */
+ else if ((q = largopt(p, "copies", argv[0], &error)) != NULL) {
+ sscanf(q, "%d", &numcopies);
+ } else if ((q = largopt(p, "config", argv[0], &error)) != NULL) {
+ strncpy(MIXCONF, q, PATHMAX);
+ MIXCONF[PATHMAX-1] = 0;
+ mix_config(); /* configuration file changed - reread it */
+ } else if (error == 0 && mix_configline(p) == 0) {
+ fprintf(stderr, "%s: Invalid option %s\n", argv[0], argv[i]);
+ error = 1;
+ }
+ } else {
+ while (*++p) {
+ switch (*p) {
+ case 'd':
+ send = MSG_NULL, deflt = 0;
+ break;
+ case 'R':
+ readmail = 1, deflt = 0;
+ break;
+ case 'I':
+ readmail = 2, deflt = 0;
+ break;
+ case 'S':
+ sendpool = 1, deflt = 0;
+ break;
+ case 'M':
+ maint = 1, deflt = 0;
+ break;
+#ifdef USE_SOCK
+ case 'P':
+ pop3 = 1, deflt = 0;
+ break;
+#endif /* USE_SOCK */
+ case 'D':
+ daemon = 1, deflt = 0;
+ break;
+ case 'G':
+ keygen = 2, deflt = 0;
+ break;
+ case 'K':
+ keygen = 1, deflt = 0;
+ break;
+ case 'L': /* backwards compatibility */
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'h':
+ help = 1, deflt = 0;
+ break;
+ case 'T':
+ type_list = 1;
+ break;
+ case 'V':
+ version = 1, deflt = 0;
+ break;
+ case 't':
+ if (*(p + 1) == 'o')
+ p++;
+ header = 0;
+ if (i < argc - 1)
+ buf_appendf(msg, "To: %s\n", argv[++i]);
+ else {
+ fprintf(stderr, "%s: Missing argument for option -to\n", argv[0]);
+ error = 1;
+ }
+ break;
+ case 's':
+ if (i < argc - 1)
+ buf_appendf(msg, "Subject: %s\n", argv[++i]);
+ else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+ case 'l':
+ if (i < argc - 1)
+ buf_appendf(msg, "Chain: %s\n", argv[++i]);
+ else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+ case 'r':
+ if (i < argc - 1)
+ buf_appendf(msg, "Reply-Chain: %s\n", argv[++i]);
+ else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+#ifdef USE_PGP
+ case 'n':
+ if (i < argc - 1)
+ buf_appendf(msg, "Nym: %s\n", argv[++i]);
+ else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+#endif /* USE_PGP */
+ case 'c':
+ if (i < argc - 1)
+ sscanf(argv[++i], "%d", &numcopies);
+ else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+ case 'p':
+ send = MSG_POST;
+ break;
+ case 'g':
+ if (i < argc - 1) {
+ send = MSG_POST, header = 0;
+ buf_appendf(msg, "Newsgroups: %s\n", argv[++i]);
+ } else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+ case 'a':
+ if (i < argc - 1)
+ buf_appendf(attachments, "%s\n", argv[++i]);
+ else {
+ noarg(argv[0], *p);
+ error = 1;
+ }
+ break;
+ case 'm':
+ send = MSG_MAIL;
+ break;
+ default:
+ fprintf(stderr, "%s: Invalid option -%c\n", argv[0], *p);
+ error = 1;
+ break;
+ }
+ }
+ }
+ } else {
+ if (strchr(argv[i], '@')) {
+ header = 0;
+ buf_appendf(msg, "To: %s\n", argv[i]);
+ } else {
+ if (filename == NULL)
+ filename = argv[i];
+ else {
+ fprintf(stderr, "%s: Error in command line: %s\n", argv[0], argv[i]);
+ error = 1;
+ }
+ }
+ }
+ }
+
+ if (error) {
+ ret = 1;
+ goto end;
+ }
+
+ if (type_list) {
+ BUFFER *type2list;
+ type2list = buf_new();
+ if (prepare_type2list(type2list) < 0) {
+ fprintf(stderr, "Cannot print type2.list.\n");
+ ret = 2;
+ } else {
+ printf("%s", type2list->data);
+ };
+ buf_free(type2list);
+ goto end;
+ }
+
+ if (version) {
+ printf("Mixmaster %s\n", VERSION);
+ ret = 0;
+ goto end;
+ }
+
+ if (update_pingerlist) {
+ mixfile(pingpath, ALLPINGERSFILE);
+ if (verbose) printf ("downloading %s...\n", ALLPINGERSURL);
+ if (url_download(ALLPINGERSURL, pingpath) < 0) {
+ printf(" Download failed... Try again later.\n");
+ errlog(ERRORMSG, "All Pingers File Download failed.\n");
+ } else {
+ if (verbose) printf(" Done.\n");
+ errlog(LOG, "All Pingers File Downloaded OK.\n");
+ }
+ ret = 0;
+ goto end;
+ }
+
+ if (update_stats) {
+ ret = download_stats(statssrc->data);
+ if (ret == -3) {
+ fprintf(stderr, "Stats source does not include all required files.\n");
+ } else if (ret == -2) {
+ fprintf(stderr, "Could not open stats source file for writing\n");
+ } else if (ret == -1) {
+ fprintf(stderr, "Stats source download failed.\n");
+ }
+ ret = 0;
+ goto end;
+ }
+
+#ifdef USE_NCURSES
+/* If we get here then it's possible we still want to use the NCURSES interface */
+ if (deflt && (send == -1) && isatty(fileno(stdin))) {
+ menu_main();
+ goto clientpool;
+ }
+#endif /* USE_NCURSES */
+
+ if (help ||about ||(isatty(fileno(stdin)) && isatty(fileno(stdout))))
+ fprintf(stderr, "Mixmaster %s\n", VERSION);
+ if (help ||about)
+ printf("\n\n");
+ if (about) {
+ printf("Many people have contributed to the source code for Mixmaster.\n");
+ printf("These contributors include:\n\n");
+ printf("Lance Cottrell\n");
+ printf("Janis Jagars\n");
+ printf("Ulf Moeller\n");
+ printf("Peter Palfrader\n");
+ printf("Len Sassaman\n");
+ printf("\nand others. For full information on copyright and license issues,\n");
+ printf("read the bundled file COPYRIGHT.\n\n");
+ ret = 0;
+ goto end;
+ }
+
+ if (help) {
+ printf("Usage: %s [options] [user@host] [filename]\n\n", argv[0]);
+ printf("Options:\n\
+\n\
+-h, --help summary of command line options\n\
+-V, --version print version information\n\
+ --about print authorship information\n\
+-T, --type-list list available remailers\n\
+-t, --to=user@host the recipient's address(es)\n\
+-g, --post-to=newsgroup newsgroup(s) to post to\n\
+-p, --post input is a Usenet article\n\
+-m, --mail input is a mail message\n\
+-s, --subject=subject message subject\n\
+ --header='header line' arbitrary message headers\n\
+-a, --attachment=file attach a file\n"
+#ifdef USE_PGP
+#ifdef NYMSUPPORT
+ "-n, --nym=yournym use pseudonym to send the message\n"
+#endif /* NYMSUPPORT */
+" --encrypt encrypt the message using the PGP format\n\
+ --sign sign the message using the PGP format\n"
+#endif /* USE_PGP */
+ "-l, --chain=mix1,mix2,mix3,... specify a remailer chain\n\
+-c, --copies=num send num copies to increase reliability\n\
+-d, --dummy generate a dummy message\n\
+-S, --send send the message(s) in the pool\n"
+#ifdef USE_PGP
+#ifdef NYMSUPPORT
+ " --nym-config=yournym generate a new pseudonym\n\
+ --latency=hours reply chain latency\n\
+ --reply-chain=rem1,rem2,... reply chain for the pseudonym\n"
+#endif /* NYMSUPPORT */
+#endif /* USE_PGP */
+ "-v, --verbose output informational messages\n\
+-f [file] read a mail folder\n\
+ --update-pinger-list Download an updated all pingers list file\n\
+ --update-stats[=source] Download updated stats\n"
+
+#ifndef USE_NCURSES
+ "\n-fr, -ff, -fg [file] send reply/followup/group reply to a message\n"
+#endif /* USE_NCURSES */
+ "\nThe input file is expected to contain mail headers if no address is\n\
+specified in the command line.\n\
+\n\
+Remailer:\n\
+\n\
+-R, --read-mail read remailer message from stdin\n\
+-I, --store-mail read remailer msg from stdin, do not decrypt\n\
+-M, --remailer process the remailer pool\n\
+-D, --daemon remailer as background process\n\
+ --no-detach do not detach from terminal as daemon\n"
+#ifdef USE_SOCK
+ "-S, --send force sending messages from the pool\n"
+#endif /* USE_SOCK */
+ "-P, --pop-mail force getting messages from POP3 servers\n\
+-G, --generate-key generate a new remailer key\n\
+-K, --update-keys generate remailer keys if necessary\n\
+ --config=file use alternate configuration file\n"
+#ifdef WIN32SERVICE
+ "\n\
+WinNT service:\n\
+\n\
+ --install-svc install the service\n\
+ --remove-svc remove the service\n\
+ --run-svc run as a service\n"
+#endif /* WIN32SERVICE */
+ );
+
+ ret = 0;
+ goto end;
+ }
+
+ if (deflt && send == -1)
+ send = MSG_MAIL;
+ if (nym[0] != 0)
+ send = -1;
+ if ((send == MSG_MAIL || send == MSG_POST) && filename == NULL &&
+ header == 1 && isatty(fileno(stdin))) {
+ /* we don't get here if USE_NCURSES is set */
+ printf("Run `%s -h' to view a summary of the command line options.\n\nEnter the message, complete with headers.\n",
+ argv[0]);
+#ifdef UNIX
+ printf("When done, press ^D.\n\n");
+#else
+ printf("When done, press ^Z.\n\n");
+#endif /* else not UNIX */
+ }
+ if (header == 0)
+ buf_nl(msg);
+
+ /* timeskew check */
+ if (REMAIL == 1)
+ mix_check_timeskew();
+
+ if (readmail || redirect_mail || send == MSG_MAIL || send == MSG_POST) {
+ if (filename == NULL || streq(filename, "-"))
+ f = stdin;
+ else {
+ f = fopen(filename, "r");
+ if (f == NULL)
+ fprintf(stderr, "Can't open %s.\n", filename);
+ }
+
+ if (f && buf_read(msg, f) != -1) {
+ if (readmail == 1) {
+ check_get_pass(1, never_ask_for_passphrase);
+ mix_decrypt(msg);
+ } else if (readmail == 2)
+ pool_add(msg, "inf");
+ if (send == MSG_MAIL || send == MSG_POST || redirect_mail) {
+ BUFFER *sendmsg;
+ int numdest = 0;
+
+ sendmsg = buf_new();
+
+ while (buf_getheader(msg, field, content) == 0) {
+ if (bufieq(field, "nym")) {
+ strncpy(nym, content->data, sizeof(nym));
+ } else if (bufieq(field, "chain"))
+ if (strchr(content->data, ';')) {
+ i = strchr(content->data, ';') - (char *)content->data;
+ strncpy(chain, content->data, i);
+ if (strstr(content->data + i, "copies=") != NULL) {
+ sscanf(strstr(content->data + i, "copies=") +
+ sizeof("copies=") - 1, "%d", &numcopies);
+ }
+ } else
+ strncpy(chain, content->data, sizeof(chain));
+ else { /* line goes into message */
+ if (((redirect_mail || send == MSG_MAIL) && bufieq(field, "to"))
+ || (send == MSG_POST && bufieq(field, "newsgroups")))
+ numdest++;
+ if (bufieq(field, "from") && !redirect_mail)
+ fprintf(stderr, "Warning: The message has a From: line.\n");
+ buf_appendheader(sendmsg, field, content);
+ }
+ }
+ buf_nl(sendmsg);
+ buf_rest(sendmsg, msg);
+
+ while (buf_getline(attachments, field) != -1)
+ if (attachfile(sendmsg, field) == -1) {
+ errlog(ERRORMSG, "Can't attach %b!\n", field);
+ ret = 2;
+ goto end;
+ }
+
+#ifdef USE_PGP
+ if (nym[0] != 0 && strchr(nym, '@') == NULL)
+ strcatn(nym, "@", sizeof(nym));
+ if (sign || encrypt) {
+ BUFFER *pass;
+
+ pass = buf_new();
+ user_pass(pass);
+ if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0) |
+ (nym[0] != 0 && sign ? PGP_SIGN : 0) |
+ PGP_TEXT | PGP_REMAIL, sendmsg, nym,
+ pass, NULL, NYMSECRING) != 0) {
+ fprintf(stderr, "Encryption failed: missing key!");
+ ret = 2;
+ goto end;
+ }
+ buf_free(pass);
+ }
+ if (nym[0] != 0) {
+#ifdef NYMSUPPORT
+ if (nym_encrypt(sendmsg, nym, send) == 0)
+ send = MSG_MAIL;
+ else
+#endif /* NYMSUPPORT */
+ fprintf(stderr, "Nym error, sending message anonymously.\n");
+ }
+#endif /* USE_PGP */
+ if (numdest == 0) {
+ fprintf(stderr, "No destination address given!\n");
+ ret = 2;
+ } else if (numcopies < 0 || numcopies > 10) {
+ fprintf(stderr, "Invalid number of copies!\n");
+ ret = 2;
+ } else {
+ if ( ( redirect_mail ?
+ redirect_message(sendmsg, chain, numcopies, chainlist) :
+ mix_encrypt(send, sendmsg, chain, numcopies, chainlist)
+ ) == -1) {
+ ret = 2;
+ if (chainlist->length)
+ fprintf(stderr, "%s\n", chainlist->data);
+ else
+ fprintf(stderr, "Failed!\n");
+ } else if (verbose) {
+ fprintf(stderr, "Chain: ");
+ buf_write(chainlist, stderr);
+ }
+ }
+
+ buf_free(sendmsg);
+ }
+ if (filename != NULL)
+ fclose(f);
+ } else
+ ret = 2;
+ }
+ if (send == MSG_NULL) {
+ if (msg->length) {
+ while (buf_getheader(msg, field, content) == 0) {
+ if (bufieq(field, "chain"))
+ strncpy(chain, content->data, sizeof(chain));
+ }
+ }
+ if (mix_encrypt(MSG_NULL, NULL, chain, numcopies, chainlist) == -1) {
+ ret = 2;
+ if (chainlist->length)
+ printf("%s\n", chainlist->data);
+ else
+ fprintf(stderr, "Failed!\n");
+ } else if (verbose) {
+ printf("Chain: ");
+ buf_write(chainlist, stdout);
+ }
+ }
+#ifdef USE_PGP
+#ifdef NYMSUPPORT
+ if (nym[0] != 0) {
+ char nymserver[LINELEN] = "*";
+ BUFFER *chains;
+
+ chains = buf_new();
+ if (numcopies < 1 || numcopies > 10)
+ numcopies = 1;
+ while (buf_getheader(msg, field, content) != -1) {
+ if (bufieq(field, "chain"))
+ strncpy(chain, content->data, sizeof(chain));
+ else if (bufieq(field, "reply-chain"))
+ buf_appendf(chains, "Chain: %b\n", content);
+ else if (field->length)
+ buf_appendheader(chains, field, content);
+ else
+ buf_nl(chains);
+ }
+ if (strrchr(nym, '@')) {
+ strncpy(nymserver, strrchr(nym, '@'), sizeof(nymserver));
+ *strrchr(nym, '@') = '\0';
+ }
+ if (nym_config(NYM_CREATE, nym, nymserver, pseudonym,
+ chain, numcopies, chains, nymopt) < 0) {
+ ret = 2;
+ fprintf(stderr, "Failed!\n");
+ }
+ user_delpass();
+ buf_free(chains);
+ }
+#endif /* NYMSUPPORT */
+#endif /* USE_PGP */
+
+ if (keygen) {
+ check_get_pass(0, never_ask_for_passphrase);
+ keymgt(keygen);
+ }
+ if (sendpool)
+ mix_send();
+#ifdef USE_SOCK
+ if (pop3)
+ pop3get();
+#endif /* USE_SOCK */
+ if (maint) {
+ check_get_pass(1, never_ask_for_passphrase);
+ mix_regular(0);
+ }
+
+clientpool:
+ if ((REMAIL == 0) && (CLIENTAUTOFLUSH == 1)) {
+ SENDPOOLTIME = 0;
+ RATE = 100;
+ mix_send();
+ };
+
+end:
+ buf_free(field);
+ buf_free(content);
+ buf_free(chainlist);
+ buf_free(msg);
+ buf_free(nymopt);
+ buf_free(pseudonym);
+ buf_free(attachments);
+ buf_free(statssrc);
+
+ if (daemon) {
+ check_get_pass(1, never_ask_for_passphrase);
+#ifdef UNIX
+ if (! nodetach) {
+ int pid;
+
+ fprintf(stderr, "Detaching.\n");
+ /* Detach as suggested by the Unix Programming FAQ */
+ pid = fork();
+ if (pid > 0)
+ exit(0);
+ if (setsid() < 0) {
+ /* This should never happen. */
+ fprintf(stderr, "setsid() failed.\n");
+ exit(1);
+ };
+ pid = fork();
+ if (pid > 0)
+ exit(0);
+ };
+ if (chdir(MIXDIR) < 0) {
+ if (chdir("/") < 0) {
+ fprintf(stderr, "Cannot chdir to mixdir or /.\n");
+ exit(1);
+ };
+ };
+ if (write_pidfile(PIDFILE)) {
+ fprintf(stderr, "Aborting.\n");
+ exit(1);
+ }
+ if (! nodetach) {
+ freopen ("/dev/null", "r", stdin);
+ freopen ("/dev/null", "w", stdout);
+ freopen ("/dev/null", "w", stderr);
+ }
+#endif /* UNIX */
+ mix_daemon();
+#ifdef UNIX
+/* ifdef this one too, so that we do not need to export it from windows dll */
+ clear_pidfile(PIDFILE);
+#endif /* UNIX */
+ }
+ mix_exit();
+ return (ret);
+}
+
+static char *largopt(char *p, char *opt, char *name, int *error)
+{
+ if (streq(p, opt)) {
+ fprintf(stderr, "%s: Missing argument for option --%s\n", name, p);
+ *error = 1;
+ } else if (strleft(p, opt) && p[strlen(opt)] == '=') {
+ return (p + strlen(opt) + 1);
+ }
+ return (NULL);
+}
+
+static void noarg(char *name, char p)
+{
+ fprintf(stderr, "%s: Missing argument for option -%c\n", name, p);
+}
+
+static int check_get_pass(int force, int never_ask_for_passphrase)
+/* get a passphrase and check against keys
+ * if force != 0 passphrase must match with some key */
+{
+ BUFFER *pass, *pass2, *key;
+ int n = 0;
+
+ if (PASSPHRASE[0] == '\0' && isatty(fileno(stdin)) && ! never_ask_for_passphrase) {
+ pass = buf_new();
+ pass2 = buf_new();
+ key = buf_new();
+ buf_sets(pass, PASSPHRASE);
+ while (
+#ifdef USE_PGP
+ pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, pass) < 0 &&
+ pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, pass) < 0 &&
+#endif /* USE_PGP */
+ getv2seckey(NULL, key) < 0)
+ {
+ user_delpass();
+ if (n)
+ fprintf(stderr, "re-");
+ user_pass(pass);
+ strncpy(PASSPHRASE, pass->data, LINELEN);
+ PASSPHRASE[LINELEN-1] = 0;
+ if (!force) {
+ if (n && buf_eq(pass, pass2))
+ break;
+ buf_set(pass2, pass);
+ }
+ n=1;
+ }
+ user_delpass();
+ buf_free(pass);
+ buf_free(pass2);
+ buf_free(key);
+
+ strncpy(ENTEREDPASSPHRASE, PASSPHRASE, LINELEN);
+ ENTEREDPASSPHRASE[LINELEN-1] = 0;
+ }
+ return 1;
+}
diff --git a/Src/menu.c b/Src/menu.c
@@ -0,0 +1,1003 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Menu-based user interface
+ $Id: menu.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "menu.h"
+#include "mix3.h"
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#ifdef POSIX
+#include <unistd.h>
+#else /* end of POSIX */
+#include <io.h>
+#endif /* else if not POSIX */
+#include <assert.h>
+
+void menu_folder(char command, char *foldername)
+{
+ mix_init(NULL);
+ if (foldername)
+ menu_init();
+ read_folder(command, foldername, ANON);
+ menu_exit();
+}
+
+void read_folder(char command, char *foldername, char *nym)
+{
+#ifdef USE_NCURSES
+ char path[PATHMAX] = "stdin", path_with_tilde[PATHMAX], l[LINELEN];
+#else /* end of USE_NCURSES */
+ char path[PATHMAX] = "stdin", l[LINELEN];
+#endif /* else if not USE_NCURSES */
+ char *h;
+ FILE *f;
+ BUFFER *folder;
+ BUFFER *line, *field, *content, *name;
+ BUFFER *index;
+ BUFFER *mail, *log;
+ int mailfolder = -1; /* -1 = unknown, 0 = no mailfolder, 1 = mailfolder */
+ int num = 0;
+ long from = -1, subject = -1;
+ int folder_has_changed;
+#ifdef USE_NCURSES
+ BUFFER *deleted_message;
+ BUFFER *new_folder;
+ BUFFER *new_index;
+ long length;
+ char sub[LINELEN], str[LINELEN], search[LINELEN] = "";
+ long p;
+ int display, range, selected, i, redraw, c, q;
+
+#endif /* USE_NCURSES */
+ int ispgp = 0, eof = 0;
+ folder_has_changed = 0;
+
+ line = buf_new();
+ field = buf_new();
+ content = buf_new();
+ index = buf_new();
+ mail = buf_new();
+ name = buf_new();
+ folder = buf_new();
+ log = buf_new();
+
+ if (foldername == NULL)
+ f = stdin;
+ else {
+ if (foldername[0] == '~' && (h = getenv("HOME")) != NULL) {
+ strncpy(path, h, PATHMAX);
+ strcatn(path, foldername + 1, PATHMAX);
+ } else
+ strncpy(path, foldername, PATHMAX);
+ f = fopen(path, "r");
+ }
+ if (f == NULL) {
+#ifdef USE_NCURSES
+ if (foldername)
+ beep();
+#endif /* USE_NCURSES */
+ mix_status("Can't read %s.\n", path);
+ goto end;
+ }
+ for (;;) {
+ if (fgets(l, sizeof(l), f) == NULL)
+ eof = 1;
+ else if (mailfolder == -1) {
+ if (strleft(l, "From "))
+ mailfolder = 1;
+ else if (strileft(l, "from:") || strileft(l, "path:")
+ || strileft(l, "xref:") || strileft(l, "return-path"))
+ mailfolder = 0;
+ else
+ break;
+ }
+ if (eof || (mailfolder && strleft(l, "From ")) ||
+ (mailfolder == 0 && from != -1 &&
+ (strileft(l, "path:") ||
+ strileft(l, "xref:") || strileft(l,"return-path")))) {
+ if (num > 1)
+ mix_status("Reading message %d", num);
+#ifdef USE_PGP
+ if (ispgp)
+#ifdef NYMSUPPORT
+ switch (nym_decrypt(mail, NULL, log)) {
+ case 2:
+ from = -1, subject = -1;
+ while (buf_getline(mail, line) == 0) {
+ if (bufileft(line, "from:"))
+ from = folder->length + mail->ptr - line->length - 1;
+ if (bufileft(line, "subject:"))
+ subject = folder->length + mail->ptr - line->length - 1;
+ }
+ folder_has_changed = 1;
+ break;
+ case -1:
+ buf_clear(mail);
+ from = -1, subject = -1;
+ continue;
+ default:
+ ;
+ }
+#else
+ if (!eof) {
+ buf_clear(mail);
+ from = -1, subject = -1;
+ continue;
+ }
+#endif /* NYMSUPPORT */
+#endif /* USE_PGP */
+ buf_cat(folder, mail);
+ buf_clear(mail);
+ ispgp = 0;
+ if (num > 0) {
+ buf_appendl(index, from);
+ buf_appendl(index, subject);
+ }
+ if (eof)
+ break;
+
+ buf_appendl(index, folder->length);
+ from = subject = -1;
+ num++;
+ }
+ if (from == -1 && strileft(l, "from:"))
+ from = folder->length + mail->length;
+
+ if (subject == -1 && strileft(l, "subject:"))
+ subject = folder->length + mail->length;
+
+ buf_appends(mail, l);
+ if (strleft(l, begin_pgp))
+ ispgp = 1;
+ }
+
+ if (foldername)
+ fclose(f);
+ else {
+ dup2(open("/dev/tty", O_RDWR), fileno(stdin));
+ menu_init();
+ }
+
+ mix_status("");
+ if (folder->length == 0) {
+#ifdef USE_NCURSES
+ clear();
+ beep();
+#endif /* USE_NCURSES */
+ mix_status("%s is empty.\n", path);
+ goto end;
+ }
+ if (mailfolder == -1) {
+#ifdef USE_NCURSES
+ clear();
+ beep();
+#endif /* USE_NCURSES */
+ mix_status("%s is not a mail folder.\n", path);
+ goto end;
+ }
+#ifndef USE_NCURSES
+ if (command == 0) {
+ buf_write(folder, stdout);
+ goto end;
+ }
+ if (num > 1) {
+ mix_status("Folder contains several messages.");
+ goto end;
+ }
+#endif /* not USE_NCURSES */
+
+ if (num < 2) {
+ folder->ptr = 0;
+ mimedecode(folder);
+
+ if (command != 0)
+ send_message(command, nym, folder);
+#ifdef USE_NCURSES
+ else
+ read_message(folder, nym);
+
+ clear();
+#endif /* USE_NCURSES */
+ goto end;
+ }
+#ifdef USE_NCURSES
+ display = selected = 0;
+ range = LINES - 3;
+ redraw = 2;
+
+ for (;;) {
+ if (selected < 0)
+ selected = 0;
+ if (selected >= num)
+ selected = num - 1;
+
+ if (selected < display) {
+ display = selected - range / 2;
+ redraw = 2;
+ }
+ if (selected >= display + range) {
+ display = selected - range / 2;
+ redraw = 2;
+ }
+ if (display >= num - 5)
+ display = num - 5;
+ if (display < 0)
+ display = 0;
+
+ if (redraw) {
+ if (redraw == 2) {
+ clear();
+ standout();
+ mvprintw(0, 0, "Mixmaster %s", VERSION);
+ printw(" %.20s reading %.50s", nym, path);
+ standend();
+ }
+ for (i = display; i < display + range; i++) {
+ if (i < num) {
+ index->ptr = 12 * i;
+ p = buf_getl(index);
+ buf_clear(name);
+ folder->ptr = buf_getl(index);
+ if (folder->ptr < 0)
+ folder->ptr = 0;
+ else {
+ buf_getheader(folder, field, line);
+ if (line->length) {
+ decode_header(line);
+ rfc822_name(line, name);
+ }
+ }
+ if (i == selected)
+ standout();
+
+ mvaddnstr(i - display + 2, 0, name->data, 18);
+
+ sub[0] = '\0';
+ folder->ptr = buf_getl(index);
+ if (folder->ptr < 0)
+ folder->ptr = 0;
+ else {
+ buf_getheader(folder, field, content);
+ if (content->length) {
+ decode_header(content);
+ strncpy(sub, content->data, sizeof(sub));
+ }
+ }
+ if (sub[0] == '\0')
+ strcpy(sub, "(no subject)");
+ mvaddnstr(i - display + 2, 20, sub, COLS - 21);
+
+ if (i == selected)
+ standend();
+ }
+ }
+ }
+ move(LINES - 1, COLS - 1);
+ refresh();
+ redraw = 0;
+
+ c = getch();
+ switch (c) {
+ case '\014':
+ display = selected - range / 2;
+ redraw = 2;
+ break;
+ case 'q':
+ clear();
+ goto end;
+ case '/':
+ echo();
+ cl(LINES - 1, 0);
+ printw("Search: ");
+ refresh();
+ wgetnstr(stdscr, str, LINELEN);
+ if (str[0] != '\0')
+ strncpy(search, str, LINELEN);
+ noecho();
+ for (i = (selected < num ? selected + 1 : 0); i < num; i++) {
+ index->ptr = 12 * i + 4;
+ folder->ptr = buf_getl(index);
+ if (folder->ptr < 0)
+ folder->ptr = 0;
+ else {
+ buf_getheader(folder, field, line);
+ if (line->length) {
+ decode_header(line);
+ if (bufifind(line, search))
+ break;
+ }
+ }
+ folder->ptr = buf_getl(index);
+ if (folder->ptr < 0)
+ folder->ptr = 0;
+ else {
+ buf_getheader(folder, field, line);
+ if (line->length) {
+ decode_header(line);
+ if (bufifind(line, search))
+ break;
+ }
+ }
+ }
+ if (i < num)
+ selected = i;
+ else
+ beep();
+ redraw = 1;
+ break;
+ case '\r': /* read message */
+ case '\n':
+ case 'r': /* reply to message */
+ case 'g':
+ case 'f':
+ case 'm':
+ case 'p':
+ case 's':
+ index->ptr = 12 * selected;
+ p = buf_getl(index);
+ if (selected < num - 1) {
+ index->ptr = 12 * (selected + 1);
+ q = buf_getl(index) - p;
+ } else
+ q = folder->length - p;
+ buf_clear(mail);
+ buf_append(mail, folder->data + p, q);
+ mimedecode(mail);
+ if(c == 's')
+ savemsg(mail);
+ else{
+ if (c == '\r' || c == '\n')
+ read_message(mail, nym);
+ else
+ send_message(c, nym, mail);
+ }
+ redraw = 2;
+ break;
+ case 'd': /* delete message */
+ /* Remove message from folder */
+ if(num > 0){
+ index->ptr = 12 * selected;
+ p = buf_getl(index);
+ if (selected < num - 1) {
+ index->ptr = 12 * (selected + 1);
+ q = buf_getl(index) - p;
+ } else
+ q = folder->length - p;
+ deleted_message = buf_new();
+ new_folder = buf_new();
+ buf_cut_out(folder, deleted_message, new_folder, p, q);
+ buf_free(deleted_message);
+ buf_free(folder);
+ folder = new_folder;
+ /* Update index file */
+ new_index = buf_new();
+ index->ptr = 0;
+ if(selected > 0)
+ buf_get(index, new_index, 12 * selected);
+ index->ptr = 12 * (selected + 1);
+ while((from = buf_getl(index)) != -1){
+ subject = buf_getl(index);
+ length = buf_getl(index);
+ buf_appendl(new_index, from - q);
+ buf_appendl(new_index, subject - q);
+ buf_appendl(new_index, length - q);
+ }
+ buf_free(index);
+ index = new_index;
+ /* Done */
+ num--;
+ folder_has_changed = 1;
+ }
+ redraw = 2;
+ break;
+ case KEY_UP:
+ selected--;
+ redraw = 1;
+ break;
+ case KEY_DOWN:
+ case 'n': /* nym ???? */
+ selected++;
+ redraw = 1;
+ break;
+ case KEY_PPAGE:
+ selected -= range;
+ redraw = 1;
+ break;
+ case KEY_NPAGE:
+ selected += range;
+ redraw = 1;
+ break;
+ default:
+ beep();
+ }
+ }
+#endif /* USE_NCURSES */
+
+end:
+#ifdef USE_NCURSES
+ /* If folder has changed, ask user about saving new folder. */
+ if (folder_has_changed && !streq(path, "stdin")) {
+ mvprintw(LINES - 2, 0, "Buffer has changed. Save [y/n]? ");
+ c = getch();
+ cl(LINES - 2, 0);
+ if ((c == 'y') || (c == 'Y')){
+ strncpy(path_with_tilde, path, PATHMAX-1);
+ strcat(path_with_tilde, "~");
+ rename(path, path_with_tilde); /* Rename folder to folder~ */
+ f = fopen(path, "w"); /* Write new folder */
+ if (f == NULL)
+ mix_status("Can't write to %s.", path);
+ else{
+ buf_write(folder, f);
+ mix_status("Wrote %s.", path);
+ fclose(f);
+ }
+ }
+ else{
+ mix_status("%s was not saved.", path);
+ }
+ }
+#endif /* USE_NCURSES */
+ buf_free(folder);
+ buf_free(line);
+ buf_free(field);
+ buf_free(content);
+ buf_free(index);
+ buf_free(mail);
+ buf_free(name);
+ buf_free(log);
+}
+
+#ifdef USE_NCURSES
+static int sortrel(const void *a, const void *b)
+{
+ int na, ra, nb, rb;
+
+ na = *(int *) a;
+ nb = *(int *) b;
+
+ ra = *((int *) a + 1);
+ rb = *((int *) b + 1);
+ return rb - ra;
+}
+
+void menu_main(void)
+{
+ int y, x;
+ int pool, n;
+ int c;
+ int space;
+ BUFFER *chainlist, *line;
+ char nym[LINELEN] = ANON;
+
+ chainlist = buf_new();
+ line = buf_new();
+
+ mix_init(NULL);
+ menu_init();
+
+menu_redraw:
+ clear();
+ for (;;) {
+ standout();
+ mvprintw(0, 0, "Mixmaster %s", VERSION);
+#if 0
+ mvprintw(0, COLS - sizeof(COPYRIGHT), COPYRIGHT);
+#endif
+ for (space = 0; space < (COLS - 10 - sizeof(VERSION)); space++) {
+ printw(" ");
+ };
+ standend();
+ mix_status(NULL);
+
+#ifdef NYMSUPPORT
+ mvprintw(8, 4, "n)ym: %s", nym);
+#endif /* NYMSUPPORT */
+ y = 12, x = 25;
+ mvprintw(y++, x, "m)ail");
+ mvprintw(y++, x, "p)ost to Usenet");
+ mvprintw(y++, x, "r)ead mail (or news article)");
+ mvprintw(y++, x, "d)ummy message");
+ mvprintw(y++, x, "s)end messages from pool");
+ mvprintw(y++, x, "e)dit configuration file");
+ mvprintw(y++, x, "u)pdate stats");
+ mvprintw(y++, x, "q)uit");
+
+ pool = pool_read(NULL);
+ if (pool == 1)
+ mvprintw(4, 2, "%3d outgoing message in the pool. \n", pool);
+ else
+ mvprintw(4, 2, "%3d outgoing messages in the pool.\n", pool);
+
+ move(LINES - 1, COLS - 1);
+ refresh();
+ c = getch();
+ if (c != ERR) {
+ mix_status("");
+ switch (c) {
+ case '\014':
+ mix_status("");
+ goto menu_redraw;
+#ifdef NYMSUPPORT
+ case 'n':
+ menu_nym(nym);
+ goto menu_redraw;
+#endif /* NYMSUPPORT */
+ case 'm':
+ case 'p':
+ send_message(c, nym, NULL);
+ break;
+ case 'd':
+ mix_status("Creating message...");
+ if (mix_encrypt(MSG_NULL, NULL, NULL, 1, chainlist) != 0) {
+ if (chainlist->length > 0)
+ mix_status("%s", chainlist->data);
+ else
+ mix_genericerror();
+ beep();
+ } else {
+ for (n = 0; buf_getline(chainlist, line) == 0; n++) ;
+ if (n > 1)
+ mix_status("Done (%d packets).", n);
+ else
+ mix_status("Chain: %s", chainlist->data);
+ }
+ break;
+ case 's':
+ mix_status("Mailing messages...");
+ mix_send();
+ mix_status("Done.");
+ break;
+ case 'r':
+ {
+ char name[LINELEN];
+
+ cl(LINES - 3, 0);
+ if (getenv("MAIL"))
+ printw("File name [%s]: ", getenv("MAIL"));
+ else
+ printw("File name: ");
+ echo();
+ wgetnstr(stdscr, name, LINELEN);
+ noecho();
+ cl(LINES - 3, 0);
+ if (name[0] == '\0') {
+ if (getenv("MAIL"))
+ read_folder(0, getenv("MAIL"), nym);
+ } else
+ read_folder(0, name, nym);
+ }
+ break;
+ case 'e':
+ do {
+ char path[PATHMAX];
+ mixfile(path, MIXCONF);
+ menu_spawn_editor(path, 0);
+ mix_config();
+ } while (0);
+ break;
+ case 'u':
+ update_stats();
+ break;
+ case 'q':
+ case 'Q':
+ goto quit;
+ default:
+ beep();
+ }
+ }
+ }
+
+quit:
+ menu_exit();
+ buf_free(chainlist);
+ buf_free(line);
+}
+
+void read_message(BUFFER *message, char *nym)
+{
+ int l = 0;
+ int c;
+ int inhdr = 1, txtbegin;
+ BUFFER *field, *content, *line, *hdr;
+ char sub[LINELEN] = "mail";
+ char thisnym[LINELEN] = "";
+
+ field = buf_new();
+ content = buf_new();
+ line = buf_new();
+ hdr = buf_new();
+
+ if (thisnym[0] == '\0')
+ strncpy(thisnym, nym, LINELEN);
+
+ if (bufleft(message, "From nymserver ")) {
+ /* select nym if Nym: pseudo header is in the first line */
+ buf_getline(message, line);
+ buf_getheader(message, field, content);
+ if (bufieq(field, "Nym"))
+ strncpy(thisnym, content->data, sizeof(thisnym));
+ buf_rewind(message);
+ }
+ while (buf_getheader(message, field, content) == 0) {
+ if (bufieq(field, "received") || bufleft(field, "From "))
+ continue;
+ if (bufieq(field, "subject"))
+ strncpy(sub, content->data, sizeof(sub));
+ buf_appendheader(hdr, field, content);
+ }
+ if (strlen(sub) > COLS - strlen(VERSION) - strlen(thisnym) - 23)
+ sub[COLS - strlen(VERSION) - strlen(thisnym) - 24] = '\0';
+ txtbegin = message->ptr;
+
+loop:
+ clear();
+ standout();
+ mvprintw(0, 0, "Mixmaster %s", VERSION);
+ printw(" %.20s reading %.50s\n", thisnym, sub);
+ standend();
+ mix_status(NULL);
+
+ while (l < LINES - 2) {
+ if (inhdr) {
+ if (buf_getline(hdr, line) == -1)
+ buf_clear(line), inhdr = 0;
+ } else {
+ if (buf_getline(message, line) == -1) {
+ standout();
+ mvprintw(LINES - 1, 0, "Command");
+ standend();
+ refresh();
+ for (;;) {
+ c = getch();
+ switch (c) {
+ case 'm':
+ case 'p':
+ case 'r':
+ case 'g':
+ case 'f':
+ send_message(c, thisnym, message);
+ goto end;
+ case 'u':
+ inhdr = 0;
+ message->ptr = txtbegin;
+ l = 0;
+ goto loop;
+ case 'h':
+ inhdr = 1;
+ hdr->ptr = 0;
+ message->ptr = txtbegin;
+ l = 0;
+ goto loop;
+ case 's':
+ savemsg(message);
+ /* fallthru */
+ case 'q':
+ case 'i':
+ case '\n':
+ case '\r':
+ goto end;
+ case '\014':
+ refresh();
+ continue;
+ default:
+ beep();
+ refresh();
+ }
+ }
+ }
+ }
+ mvprintw(l + 1, 0, "%s\n", line->data);
+ l += (line->length - 1) / COLS + 1;
+ }
+ standout();
+ mvprintw(LINES - 1, 0, "MORE");
+ standend();
+ refresh();
+ for (;;) {
+ c = getch();
+ switch (c) {
+ case 'm':
+ case 'p':
+ case 'r':
+ case 'g':
+ case 'f':
+ send_message(c, thisnym, message);
+ goto end;
+ case 'u':
+ inhdr = 0;
+ message->ptr = txtbegin;
+ l = 0;
+ goto loop;
+ case 'h':
+ inhdr = 1; /* show full header */
+ hdr->ptr = 0;
+ message->ptr = txtbegin;
+ l = 0;
+ goto loop;
+ case 's':
+ savemsg(message);
+ /* fallthru */
+ case 'q':
+ case 'i':
+ goto end;
+ case ' ':
+ case '\n':
+ case '\r':
+ l = 0;
+ goto loop;
+ case '\014':
+ refresh();
+ continue;
+ default:
+ beep();
+ refresh();
+ }
+ }
+end:
+ buf_free(field);
+ buf_free(content);
+ buf_free(line);
+ buf_free(hdr);
+}
+
+int menu_replychain(int *d, int *l, char *mdest, char *pdest, char *psub,
+ char *r)
+{
+ int c;
+ char line[LINELEN];
+ char reliability[9];
+
+redraw:
+ clear();
+ standout();
+ printw("Create a nym reply block:");
+ standend();
+ mix_status(NULL);
+
+ mvprintw(3, 0, "Type of reply block:\n");
+ if (*d == MSG_MAIL)
+ standout();
+ printw(" m)ail ");
+ if (*d == MSG_MAIL)
+ standend();
+
+ if (*d == MSG_POST)
+ standout();
+ printw(" Usenet message p)ool ");
+ if (*d == MSG_POST)
+ standend();
+
+ if (*d == MSG_NULL)
+ standout();
+ printw(" cover t)raffic ");
+ if (*d == MSG_NULL)
+ standend();
+
+ if (*d != MSG_NULL)
+ mvprintw(6, 0, "d)estination: %s", *d == MSG_MAIL ? mdest : pdest);
+ if (psub && *d == MSG_POST)
+ mvprintw(7, 0, "s)ubject: %s", psub);
+ chain_reliability(r, 1, reliability); /* chaintype 1=ek */
+ mvprintw(8, 0, "c)hain: %-39s (reliability: %s)", r, reliability);
+ mvprintw(10, 0, "l)atency: %d hours", *l);
+ move(LINES - 1, COLS - 1);
+
+ for (;;) {
+ refresh();
+ c = getch();
+ switch (c) {
+ case 'm':
+ *d = MSG_MAIL;
+ goto redraw;
+ case 'p':
+ *d = MSG_POST;
+ goto redraw;
+ case 't':
+ *d = MSG_NULL;
+ goto redraw;
+ case 'q':
+ return (-1);
+ case 'd':
+ cl(6, 0);
+ printw("d)estination: ");
+ echo();
+ wgetnstr(stdscr, *d == MSG_MAIL ? mdest : pdest, LINELEN);
+ noecho();
+ goto redraw;
+ case 'l':
+ cl(10, 0);
+ printw("l)atency: ");
+ echo();
+ wgetnstr(stdscr, line, LINELEN);
+ *l = strtol(line, NULL, 10);
+ if (*l < 0)
+ *l = 0;
+ noecho();
+ goto redraw;
+ case 'c':
+ menu_chain(r, 1, *d == MSG_POST);
+ goto redraw;
+ case '\014':
+ goto redraw;
+ case '\n':
+ case '\r':
+ return (0);
+ case 's':
+ if (*d == MSG_POST) {
+ cl(7, 0);
+ printw("s)ubject: ");
+ echo();
+ wgetnstr(stdscr, psub, LINELEN);
+ noecho();
+ goto redraw;
+ }
+ default:
+ beep();
+ }
+ }
+}
+
+void menu_chain(char *chainstr, int chaintype, int post)
+ /* chaintype 0=mix 1=ek 2=newnym */
+{
+ REMAILER remailer[MAXREM];
+ int badchains[MAXREM][MAXREM];
+ int rlist[2 * MAXREM];
+ char newchain[CHAINMAX];
+ char info[LINELEN];
+ int num = 0, i, middlemanlast=0, ok = 1;
+ int c, x, y;
+ int nymserv = 0;
+ int chain[20], chainlen = 0;
+ char reliability[9];
+
+ if (chaintype == 2)
+ nymserv = 1, chaintype = 1;
+ assert(chaintype == 0 || chaintype == 1);
+
+ clear();
+ standout();
+ if (nymserv)
+ printw("Select nym server:\n\n");
+ else
+ printw("Select remailer chain:\n\n");
+ standend();
+
+ if (chaintype == 1)
+ num = t1_rlist(remailer, badchains);
+ else
+ num = mix2_rlist(remailer, badchains);
+
+ if (num < 1) {
+ mix_status("Can't read remailer list.");
+ beep();
+ return;
+ }
+ for (i = 0; i < num; i++) {
+ rlist[2 * i] = i + 1;
+ rlist[2 * i + 1] = remailer[i + 1].info[chaintype].reliability -
+ remailer[i + 1].info[chaintype].latency / 3600;
+ if (remailer[i + 1].info[chaintype].history[0] == '\0')
+ rlist[2 * i + 1] = -1;
+ if ((nymserv && !remailer[i + 1].flags.newnym) ||
+ ((chaintype == 0 && !remailer[i + 1].flags.mix) ||
+ (chaintype == 1 && !nymserv && (!remailer[i + 1].flags.ek
+ || !remailer[i + 1].flags.pgp))))
+ rlist[2 * i] = 0, rlist[2 * i + 1] = -2;
+ }
+ qsort(rlist, num - 1, 2 * sizeof(int), sortrel);
+
+ for (i = 0; i < num; i++)
+ if (rlist[2 * i + 1] == -2) {
+ num = i;
+ break;
+ }
+ if (num < 1) {
+ mix_status("No remailers found!");
+ return;
+ }
+ if (num > 2 * (LINES - 6))
+ num = 2 * (LINES - 6);
+ if (num > 2 * 26)
+ num = 2 * 26;
+
+ for (i = 0; i < num && rlist[2 * i + 1] > -2; i++) {
+ y = i, x = 0;
+ if (y >= LINES - 6)
+ y -= LINES - 6, x += 40;
+ mvprintw(y + 2, x, "%c", i < 26 ? i + 'a' : i - 26 + 'A');
+ mvprintw(y + 2, x + 2, "%s", remailer[rlist[2 * i]].name);
+ mvprintw(y + 2, x + 16, "%s",
+ remailer[rlist[2 * i]].info[chaintype].history);
+ sprintf(info, "%3.2f",
+ remailer[rlist[2 * i]].info[chaintype].reliability / 100.0);
+ mvprintw(y + 2, x + 29 + 6 - strlen(info), "%s%%", info);
+ }
+ y = num + 3;
+ if (y > LINES - 4)
+ y = LINES - 4;
+ mvprintw(y, 0, "* select at random");
+
+ for (;;) {
+ newchain[0] = '\0';
+ for (i = 0; i < chainlen; i++) {
+ if (i)
+ strcatn(newchain, ",", CHAINMAX);
+ if (chain[i])
+ strcatn(newchain, remailer[chain[i]].name, CHAINMAX);
+ else
+ strcatn(newchain, "*", CHAINMAX);
+ }
+ if (chainlen > 0) {
+ ok = 1;
+ middlemanlast = remailer[chain[chainlen - 1]].flags.middle;
+ if (post && !remailer[chain[chainlen - 1]].flags.post && !(chain[chainlen - 1] == 0 /*randhop*/))
+ ok = 0;
+ } else
+ ok = 1;
+
+ mvprintw(LINES - 4, 40,
+ middlemanlast ?
+ "MIDDLEMAN " :
+ (ok ?
+ " " :
+ "NO POSTING "));
+ cl(LINES - 3, 0);
+ cl(LINES - 2, 0);
+ cl(LINES - 1, 0);
+ if(!nymserv){
+ chain_reliability(newchain, chaintype, reliability);
+ mvprintw(LINES - 4, 58, "(reliability: %s)", reliability);
+ }
+ mvprintw(LINES - 3, 0, nymserv ? "Nym server: %s" : "Chain: %s",
+ newchain);
+ refresh();
+ c = getch();
+ if (c == '\n' || c == '\r') {
+ /* beep and sleep in case the user made a mistake */
+ if (middlemanlast) {
+ beep();
+ sleep(2);
+ }
+ if (ok || middlemanlast)
+ break;
+ else
+ beep();
+ } else if (c == '*') {
+ if (chainlen > 19 || (nymserv && chainlen > 0))
+ beep();
+ else
+ chain[chainlen++] = 0;
+ } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ if (c >= 'a')
+ c -= 'a';
+ else
+ c = c - 'A' + 26;
+
+ if (chainlen > 19 || (nymserv && chainlen > 0) || c >= num)
+ beep();
+ else
+ chain[chainlen++] = rlist[2 * c];
+ } else if (c == killchar())
+ chainlen = 0;
+ else if ((c == KEY_BACKSPACE || c == KEY_LEFT || c == erasechar())
+ && chainlen > 0)
+ --chainlen;
+ else
+ beep();
+ }
+ if (chainlen)
+ strncpy(chainstr, newchain, CHAINMAX);
+}
+
+#endif /* USE_NCURSES */
diff --git a/Src/menu.h b/Src/menu.h
@@ -0,0 +1,48 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Menu-based user interface
+ $Id: menu.h 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#ifndef _MENU_H
+#define _MENU_H
+#include "mix3.h"
+#ifdef USE_NCURSES
+#ifdef HAVE_NCURSES_H
+#include <ncurses.h>
+#else /* end of HAVE_NCURSES_H */
+#include <curses.h>
+#endif /* else if not HAVE_NCURSES_H */
+#endif /* USE_NCURSES */
+
+#define NONANON "non-anonymous"
+#define ANON "Anonymous"
+
+void send_message(int type, char *nym, BUFFER *txt);
+void read_folder(char command, char *foldername, char *nym);
+void menu_init(void);
+void menu_exit(void);
+
+void menu_spawn_editor(char *path, int lineno);
+
+#ifdef USE_NCURSES
+void read_message(BUFFER *message, char *nym);
+void menu_nym(char *);
+void menu_chain(char *chain, int type, int post);
+void cl(int y, int x);
+void askfilename(char *fn);
+void savemsg(BUFFER *message);
+int menu_replychain(int *d, int *l, char *mdest, char *pdest, char *psub,
+ char *r);
+void update_stats(void);
+
+#endif /* USE_NCURSES */
+
+#define maxnym 30
+
+#endif /* not _MENU_H */
diff --git a/Src/menunym.c b/Src/menunym.c
@@ -0,0 +1,472 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Menu-based user interface - nym management
+ $Id: menunym.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+#ifdef NYMSUPPORT
+
+#include "menu.h"
+#include "mix3.h"
+#include <string.h>
+#include <stdlib.h>
+#ifdef POSIX
+#include <unistd.h>
+#endif /* POSIX */
+
+#ifdef USE_NCURSES
+void menu_nym(char *nnym)
+{
+ char nym[maxnym][LINELEN];
+ char pending[maxnym][LINELEN];
+ int c, i, num = 0, numpending = 0, select = -1;
+ int edit = 0;
+ BUFFER *nymlist;
+ int s;
+ int pass = 0;
+ char reliability[9]; /* When printing information about a chain,
+ this variable stores the reliability. */
+
+ nymlist = buf_new();
+
+ strcpy(nym[0], NONANON);
+ strcatn(nym[0], " (", sizeof(nym[0]));
+ strcatn(nym[0], NAME, sizeof(nym[0]));
+ strcatn(nym[0], ")", sizeof(nym[0]));
+
+ strcpy(nym[1], ANON);
+ num = 2;
+ if (nymlist_read(nymlist) == -1) {
+ user_delpass();
+ mix_status("");
+ } else
+ pass = 1;
+ while (nymlist_get(nymlist, nym[num], NULL, NULL, NULL, NULL, NULL, &s) >= 0) {
+ if (s == NYM_OK) {
+ if (num < maxnym)
+ num++;
+ } else if (s == NYM_WAITING) {
+ if (numpending < maxnym)
+ strncpy(pending[numpending++], nym[num], LINELEN);
+ }
+ }
+ buf_free(nymlist);
+
+nymselect:
+ clear();
+ standout();
+ printw("Select nym:\n\n");
+ standend();
+#ifdef USE_PGP
+ if (pass)
+ printw("c)reate new nym\ne)dit nym\nd)elete nym\n\n");
+ else
+ printw("[nym passphrase is invalid]\n\n");
+#endif /* USE_PGP */
+ for (i = 0; i < num; i++)
+ printw("%d) %s\n", i, nym[i]);
+ if (numpending > 0) {
+ printw("\n\nWaiting for confirmation: ");
+ for (i = 0; i < numpending; i++)
+ printw("%s ", pending[i]);
+ printw("\n");
+ }
+select:
+ if (select != -1)
+ printw("\r%d", select);
+ else
+ printw("\r \r");
+ refresh();
+ c = getch();
+ if (c == erasechar())
+ c = KEY_BACKSPACE;
+ if (c >= '0' && c <= '9') {
+ if (select == -1)
+ select = c - '0';
+ else
+ select = 10 * select + c - '0';
+ if (edit ? select == 0 || select >= num + numpending - 1 : select >= num) {
+ beep();
+ select = -1;
+ }
+ refresh();
+ goto select;
+ } else
+ switch (c) {
+ case KEY_BACKSPACE:
+ select /= 10;
+ if (select < 1)
+ select = -1;
+ goto select;
+ case 'q':
+ if (edit) {
+ edit = 0;
+ select = -1;
+ goto nymselect;
+ }
+ break;
+#ifdef USE_PGP
+ case 'e':
+ if (pass) {
+ if (edit || num + numpending < 3) {
+ edit = 0;
+ select = -1;
+ goto nymselect;
+ } else {
+ clear();
+ standout();
+ printw("Edit nym:\n\n");
+ standend();
+ for (i = 2; i < num + numpending; i++)
+ printw("%d) %s\n", i - 1, i < num ? nym[i] : pending[i - num]);
+ printw("\n");
+ select = -1;
+ edit = NYM_MODIFY;
+ goto select;
+ }
+ }
+ break;
+ case 'd':
+ if (pass) {
+ if (edit || num + numpending < 3) {
+ edit = 0;
+ select = -1;
+ goto nymselect;
+ } else {
+ clear();
+ standout();
+ printw("Delete nym:\n\n");
+ standend();
+ for (i = 2; i < num + numpending; i++)
+ printw("%d) %s\n", i - 1, i < num ? nym[i] : pending[i - num]);
+ printw("\n");
+ select = -1;
+ edit = NYM_DELETE;
+ goto select;
+ }
+ }
+ break;
+ case '\r':
+ case '\n':
+ if (select == -1 || (edit && select == 0)) {
+ beep();
+ edit = 0;
+ select = -1;
+ goto nymselect;
+ }
+ if (!edit) {
+ strncpy(nnym, nym[select], LINELEN);
+ return;
+ }
+ /* fallthru */
+ case 'c':
+ if (pass) {
+ char nymserv[LINELEN] = "*";
+ char replyblock[5][CHAINMAX], dest[10][LINELEN];
+ int latent[5], desttype[5];
+ char mdest[LINELEN], pdest[LINELEN] = "alt.anonymous.messages",
+ psub[LINELEN] = "";
+ int deflatent = 0, defdesttype = MSG_MAIL;
+ char alias[LINELEN] = "";
+ BUFFER *name, *opt;
+ char sendchain[CHAINMAX];
+ int sendnumcopies = 1, rnum = 1;
+ int i;
+ char line[LINELEN];
+ int acksend = 0, signsend = 0, fixedsize = 0, disable = 0,
+ fingerkey = 1;
+
+ name = buf_new();
+ opt = buf_new();
+ strncpy(sendchain, CHAIN, CHAINMAX);
+ strncpy(mdest, ADDRESS, LINELEN);
+ if (edit)
+ strncpy(alias, select + 1 < num ? nym[select + 1] :
+ pending[select + 1 - num], LINELEN);
+ if (edit == NYM_MODIFY) {
+ nymlist_getnym(alias, NULL, NULL, opt, name, NULL);
+ acksend = bufifind(opt, "+acksend");
+ signsend = bufifind(opt, "+signsend");
+ fixedsize = bufifind(opt, "+fixedsize");
+ disable = bufifind(opt, "+disable");
+ fingerkey = bufifind(opt, "+fingerkey");
+ rnum = -1;
+ }
+ newnym:
+ if (!edit) {
+ clear();
+ standout();
+ printw("Create a nym:");
+ standend();
+
+ mvprintw(3, 0, "Alias address: ");
+ echo();
+ wgetnstr(stdscr, alias, LINELEN);
+ noecho();
+ if (alias[0] == '\0')
+ goto end;
+ for (i = 0; alias[i] > ' ' && alias[i] != '@'; i++) ;
+ alias[i] = '\0';
+ if (i == 0)
+ goto newnym;
+ mvprintw(4, 0, "Pseudonym: ");
+ echo();
+ wgetnstr(stdscr, line, LINELEN);
+ noecho();
+ buf_sets(name, line);
+ menu_chain(nymserv, 2, 0);
+ }
+ if (edit != NYM_DELETE) {
+ for (i = 0; i < 5; i++) {
+ desttype[i] = defdesttype;
+ latent[i] = deflatent;
+ dest[i][0] = '\0';
+ strcpy(replyblock[i], "*,*,*,*");
+ }
+ if (rnum != -1) {
+ menu_replychain(&defdesttype, &deflatent, mdest, pdest, psub,
+ replyblock[0]);
+ desttype[0] = defdesttype;
+ latent[0] = deflatent;
+ strncpy(dest[0], desttype[0] == MSG_POST ? pdest : mdest,
+ LINELEN);
+ }
+ }
+ redraw:
+ clear();
+ standout();
+ switch (edit) {
+ case NYM_DELETE:
+ printw("Delete nym:");
+ break;
+ case NYM_MODIFY:
+ printw("Edit nym:");
+ break;
+ default:
+ printw("Create a nym:");
+ break;
+ }
+ standend();
+ loop:
+ {
+ if (!edit) {
+ cl(2, 0);
+ printw("Nym: a)lias address: %s", alias);
+ cl(3, 0);
+ printw(" nym s)erver: %s", nymserv);
+ }
+ if (edit != NYM_DELETE) {
+ cl(4, 0);
+ printw(" p)seudonym: %s", name->data);
+ if (edit)
+ mvprintw(6, 0, "Nym modification:");
+ else
+ mvprintw(6, 0, "Nym creation:");
+ }
+ cl(7, 0);
+ chain_reliability(sendchain, 0, reliability); /* chaintype 0=mix */
+ printw(" c)hain to nym server: %-30s (reliability: %s)", sendchain, reliability);
+ cl(8, 0);
+ printw(" n)umber of redundant copies: %d", sendnumcopies);
+ if (edit != NYM_DELETE) {
+ mvprintw(10, 0, "Configuration:\n");
+ printw(" A)cknowledge sending: %s\n", acksend ? "yes" : "no");
+ printw(" S)erver signatures: %s\n", signsend ? "yes" : "no");
+ printw(" F)ixed size replies: %s\n", fixedsize ? "yes" :
+ "no");
+ printw(" D)isable: %s\n", disable ? "yes" : "no");
+ printw(" Finger K)ey: %s\n", fingerkey ? "yes" : "no");
+ mvprintw(17, 0, "Reply chains:");
+ cl(18, 0);
+ if (rnum == -1)
+ printw(" create new r)eply block");
+ else {
+ printw(" number of r)eply chains: %2d reliability", rnum);
+ for (i = 0; i < rnum; i++) {
+ cl(i + 19, 0);
+ chain_reliability(replyblock[i], 1, reliability); /* 1=ek */
+ printw(" %d) %30s %-31s [%s]", i + 1,
+ desttype[i] == MSG_NULL ?
+ "(cover traffic)" : dest[i], replyblock[i],
+ reliability);
+ }
+ }
+ }
+ move(LINES - 1, COLS - 1);
+ refresh();
+ c = getch();
+ if (edit != NYM_DELETE && c >= '1' && c <= '9' && c - '1' < rnum) {
+ menu_replychain(&defdesttype, &deflatent, mdest, pdest, psub,
+ replyblock[c - '1']);
+ desttype[c - '1'] = defdesttype;
+ latent[c - '1'] = deflatent;
+ strncpy(dest[c - '1'],
+ desttype[c - '1'] == MSG_POST ? pdest : mdest, LINELEN);
+ goto redraw;
+ }
+ switch (c) {
+ case 'A':
+ acksend = !acksend;
+ goto redraw;
+ case 'S':
+ signsend = !signsend;
+ goto redraw;
+ case 'F':
+ fixedsize = !fixedsize;
+ goto redraw;
+ case 'D':
+ disable = !disable;
+ goto redraw;
+ case 'K':
+ fingerkey = !fingerkey;
+ goto redraw;
+ case 'q':
+ edit = 0;
+ select = -1;
+ goto nymselect;
+ case '\014':
+ goto redraw;
+ case 'a':
+ cl(2, 0);
+ printw("Nym: a)lias address: ");
+ echo();
+ wgetnstr(stdscr, alias, LINELEN);
+ noecho();
+ for (i = 0; alias[i] > ' ' && alias[i] != '@'; i++) ;
+ alias[i] = '\0';
+ if (i == 0)
+ goto nymselect;
+ goto redraw;
+ case 'p':
+ cl(4, 0);
+ printw(" p)seudonym: ");
+ echo();
+ wgetnstr(stdscr, line, LINELEN);
+ noecho();
+ if (line[0] != '\0')
+ buf_sets(name, line);
+ goto redraw;
+ case 'c':
+ menu_chain(sendchain, 0, 0);
+ goto redraw;
+ case 'n':
+ cl(8, 0);
+ printw(" n)umber of redundant copies: ");
+ echo();
+ wgetnstr(stdscr, line, LINELEN);
+ noecho();
+ sendnumcopies = strtol(line, NULL, 10);
+ if (sendnumcopies < 1 || sendnumcopies > 10)
+ sendnumcopies = 1;
+ goto redraw;
+ case 'r':
+ cl(18, 0);
+ printw(" number of r)eply chains: ");
+ echo();
+ wgetnstr(stdscr, line, LINELEN);
+ noecho();
+ i = rnum;
+ rnum = strtol(line, NULL, 10);
+ if (rnum < 1)
+ rnum = 1;
+ if (rnum > 5)
+ rnum = 5;
+ for (; i < rnum; i++)
+ if (dest[i][0] == '\0') {
+ desttype[i] = defdesttype;
+ latent[i] = deflatent;
+ strncpy(dest[i], defdesttype == MSG_POST ? pdest :
+ mdest, LINELEN);
+ }
+ goto redraw;
+ case 's':
+ menu_chain(nymserv, 2, 0);
+ goto redraw;
+ case '\n':
+ case '\r':
+ {
+ BUFFER *chains;
+ int err;
+
+ if (rnum == -1)
+ chains = NULL;
+ else {
+ chains = buf_new();
+ for (i = 0; i < rnum; i++)
+ if (replyblock[i][0] != '\0') {
+ if (desttype[i] == MSG_POST)
+ buf_appendf(chains, "Subject: %s\n", psub);
+ if (desttype[i] == MSG_MAIL)
+ buf_appends(chains, "To: ");
+ else if (desttype[i] == MSG_POST)
+ buf_appends(chains, "Newsgroups: ");
+ else
+ buf_appends(chains, "Null:");
+ buf_appendf(chains, "%s\n", dest[i]);
+ buf_appendf(chains, "Chain: %s\n", replyblock[i]);
+ buf_appendf(chains, "Latency: %d\n\n", latent[i]);
+ }
+ }
+ create:
+ clear();
+ buf_setf(opt,
+ " %cacksend %csignsend +cryptrecv %cfixedsize %cdisable %cfingerkey",
+ acksend ? '+' : '-',
+ signsend ? '+' : '-',
+ fixedsize ? '+' : '-',
+ disable ? '+' : '-',
+ fingerkey ? '+' : '-');
+ if (edit) {
+ mix_status("Preparing nymserver configuration message...");
+ err = nym_config(edit, alias, NULL,
+ name, sendchain, sendnumcopies,
+ chains, opt);
+ } else {
+ mix_status("Preparing nym creation request...");
+ err = nym_config(edit, alias, nymserv, name,
+ sendchain, sendnumcopies, chains,
+ opt);
+ }
+ if (err == -3) {
+ beep();
+ mix_status("Bad passphrase!");
+ getch();
+ goto create;
+ }
+ if (err != 0) {
+ mix_genericerror();
+ beep();
+ refresh();
+ } else {
+ if (edit)
+ mix_status("Nymserver configuration message completed.");
+ else
+ mix_status("Nym creation request completed.");
+ }
+ if (chains)
+ buf_free(chains);
+ goto end;
+ }
+ default:
+ beep();
+ goto loop;
+ }
+ }
+ end:
+ buf_free(name);
+ buf_free(opt);
+ return;
+ }
+#endif /* USE_PGP */
+ default:
+ beep();
+ goto select;
+ }
+}
+
+#endif /* USE_NCURSES */
+#endif /* NYMSUPPORT */
diff --git a/Src/menusend.c b/Src/menusend.c
@@ -0,0 +1,556 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Menu-based user interface -- send message
+ $Id: menusend.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "menu.h"
+#include "mix3.h"
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifdef POSIX
+#include <unistd.h>
+#else /* end of POSIX */
+#include <io.h>
+#endif /* else if not POSIX */
+
+void send_message(int type, char *nym, BUFFER *in)
+{
+ char dest[LINELEN] = "", subject[LINELEN] = "";
+ char chain[CHAINMAX], thisnym[LINELEN], path[PATHMAX];
+ BUFFER *chainlist, *msg, *txt, *tmp, *field, *content, *cc, *cite;
+ int numcopies;
+ int hdr = 0; /* txt buffer contains header lines */
+ FILE *f;
+ int n, err;
+
+#ifdef USE_PGP
+ int sign = 0, encrypt = 0, key = 0;
+
+#endif /* USE_PGP */
+#ifdef USE_NCURSES
+ char reliability[9];
+ int c;
+ char line[LINELEN];
+
+#endif /* USE_NCURSES */
+ msg = buf_new();
+ tmp = buf_new();
+ txt = buf_new();
+ field = buf_new();
+ content = buf_new();
+ chainlist = buf_new();
+ cc = buf_new();
+ cite = buf_new();
+ strncpy(chain, CHAIN, CHAINMAX);
+ numcopies = NUMCOPIES;
+
+ mix_status("");
+ strncpy(thisnym, nym, sizeof(thisnym));
+
+ if (in != NULL)
+ buf_set(txt, in);
+
+ if (bufileft(txt, "From "))
+ buf_getline(txt, field); /* ignore envelope From */
+
+ if (type == 'p' || type == 'm') {
+#ifndef USE_NCURSES
+ mix_status("Invalid option to -f");
+ mix_exit();
+ exit(1);
+#else /* end of not USE_NCURSES */
+ clear();
+ echo();
+ if (in != NULL)
+ mvprintw(1, 0, "%s forwarding message...", thisnym);
+ if (type == 'p')
+ mvprintw(3, 0, "Newsgroups: ");
+ else
+ mvprintw(3, 0, "Send message to: ");
+ refresh();
+ wgetnstr(stdscr, dest, LINELEN);
+ if (dest[0] == '\0') {
+ noecho();
+ cl(3, 0);
+ goto quit;
+ }
+ if (txt->length == 0) {
+ mvprintw(4, 0, "Subject: ");
+ refresh();
+ wgetnstr(stdscr, subject, LINELEN);
+ } else {
+ strcpy(subject, "Forwarded message");
+ while (buf_getheader(txt, field, content) == 0) {
+ if (bufieq(field, "subject")) {
+ strncpy(subject, content->data, sizeof(subject));
+ strcatn(subject, " (fwd)", sizeof(subject));
+ }
+ if (bufieq(field, "from") || bufieq(field, "subject") ||
+ bufieq(field, "date"))
+ buf_appendheader(tmp, field, content);
+ }
+ buf_nl(tmp);
+ buf_rest(tmp, txt);
+ buf_move(txt, tmp);
+ }
+ noecho();
+#endif /* else if USE_NCURSES */
+ } else {
+ strcpy(subject, "Re: your mail");
+ while (buf_getheader(txt, field, content) == 0) {
+ if (bufieq(field, "subject")) {
+ if (bufileft(content, "Re:"))
+ subject[0] = '\0';
+ else
+ strcpy(subject, "Re: ");
+ strcatn(subject, content->data, sizeof(subject));
+ }
+ if (bufieq(field, "from"))
+ buf_set(cite, content);
+ if (type == 'p' || type == 'f') {
+ if (dest[0] == '\0' && bufieq(field, "newsgroups"))
+ strncpy(dest, content->data, sizeof(dest));
+ if (bufieq(field, "followup-to") && !bufieq(content, "poster"))
+ strncpy(dest, content->data, sizeof(dest));
+ if (bufieq(field, "message-id"))
+ buf_appendf(tmp, "References: %b\n", content);
+ } else {
+ if (dest[0] == '\0' && bufieq(field, "from"))
+ strncpy(dest, content->data, sizeof(dest));
+ if (bufieq(field, "reply-to"))
+ strncpy(dest, content->data, sizeof(dest));
+ if (type == 'g' && (bufieq(field, "to") || bufieq(field, "cc"))) {
+ if (cc->length)
+ buf_appends(cc, ", ");
+ buf_cat(cc, content);
+ }
+ if (bufieq(field, "message-id"))
+ buf_appendf(tmp, "In-Reply-To: %b\n", content);
+ }
+ }
+ if (cc->length)
+ buf_appendf(tmp, "Cc: %b\n", cc);
+ if (tmp->length > 0)
+ hdr = 1;
+ if (hdr)
+ buf_nl(tmp);
+
+ if ((type == 'f' || type == 'g') && cite->length) {
+ buf_appendf(tmp, "%b wrote:\n\n", cite);
+ }
+ if (type == 'r')
+ buf_appends(tmp, "You wrote:\n\n");
+
+ while (buf_getline(txt, content) != -1)
+ buf_appendf(tmp, "> %b\n", content);
+ buf_set(txt, tmp);
+ if (dest[0] == '\0') {
+#ifdef USE_NCURSES
+ beep();
+ mix_status("No recipient address found.");
+#endif /* USE_NCURSES */
+ goto quit;
+ }
+ goto edit;
+ }
+
+#ifdef USE_NCURSES
+redraw:
+ clear();
+
+ for (;;) {
+ standout();
+ mvprintw(0, 0, "Mixmaster %s - ", VERSION);
+ printw(type == 'p' || type == 'f' ? "posting to Usenet" : "sending mail");
+ standend();
+ mix_status(NULL);
+ cl(2, 0);
+#ifdef NYMSUPPORT
+ printw("n)ym: %s", thisnym);
+#endif /* NYMSUPPORT */
+ if (!strleft(thisnym, NONANON)) {
+ chain_reliability(chain, 0, reliability); /* chaintype 0=mix */
+ cl(4, 0);
+ printw("c)hain: %-35s (reliability: %s)", chain, reliability);
+ cl(5, 0);
+ printw("r)edundancy: %3d copies ", numcopies);
+ }
+ cl(7, 0);
+ printw("d)estination: %s", dest);
+ cl(8, 0);
+ printw("s)ubject: %s", subject);
+#ifdef USE_PGP
+ if (type != 'p' && type != 'f') {
+ cl(10, 0);
+ printw("pgp encry)ption: ");
+ if (encrypt)
+ printw("yes");
+ else
+ printw("no");
+ }
+ if (!streq(thisnym, ANON)) {
+ cl(11, 0);
+ printw("p)gp signature: ");
+ if (sign)
+ printw("yes");
+ else
+ printw("no");
+ cl(12, 0);
+ if (key == 0)
+ printw("attach pgp k)ey: no");
+ }
+#endif /* USE_PGP */
+
+ if (txt->length == 0)
+ mvprintw(LINES - 3, 18,
+ "e)dit message f)ile q)uit w/o sending");
+ else
+ mvprintw(LINES - 3, 0,
+ "m)ail message e)dit message f)ile q)uit w/o sending");
+ move(LINES - 1, COLS - 1);
+ refresh();
+ c = getch();
+ if (c != ERR) {
+ mix_status("");
+ if (c == '\r' || c == '\n') { /* default action is edit or mail */
+ if (txt->length == 0)
+ c = 'e';
+ else
+ c = 'm';
+ }
+ switch (c) {
+#ifdef NYMSUPPORT
+ case 'n':
+ menu_nym(thisnym);
+ goto redraw;
+#endif /* NYMSUPPORT */
+ case '\014':
+ goto redraw;
+ case 'd':
+ echo();
+ cl(LINES - 3, 20);
+ cl(7, 14);
+ wgetnstr(stdscr, dest, LINELEN);
+ noecho();
+ break;
+ case 's':
+ echo();
+ cl(LINES - 3, 20);
+ cl(8, 10);
+ wgetnstr(stdscr, subject, LINELEN);
+ noecho();
+ break;
+ case 'c':
+ menu_chain(chain, 0, (type == 'p' || type == 'f')
+ && streq(thisnym, ANON));
+ goto redraw;
+ case 'r':
+ echo();
+ cl(LINES - 5, 20);
+ cl(5, 13);
+ wgetnstr(stdscr, line, LINELEN);
+ numcopies = strtol(line, NULL, 10);
+ if (numcopies < 1 || numcopies > 10)
+ numcopies = 1;
+ noecho();
+ break;
+ case 'f':
+ cl(LINES - 3, 0);
+ askfilename(path);
+ cl(LINES - 3, 0);
+ if (txt->length) {
+ buf_sets(tmp, path);
+ buf_clear(msg);
+ if (!hdr)
+ buf_nl(msg);
+ buf_cat(msg, txt);
+ if (attachfile(msg, tmp) == -1)
+ beep();
+ else {
+ buf_move(txt, msg);
+ hdr = 1;
+ }
+ } else {
+ if ((f = fopen(path, "r")) != NULL) {
+ buf_clear(txt);
+ buf_read(txt, f);
+ fclose(f);
+ } else
+ beep();
+ }
+ break;
+ case 'e':
+#endif /* USE_NCURSES */
+ {
+ int linecount;
+
+ edit:
+ linecount = 1;
+ sprintf(path, "%s%cx%02x%02x%02x%02x.txt", POOLDIR, DIRSEP,
+ rnd_byte(), rnd_byte(), rnd_byte(), rnd_byte());
+ f = fopen(path, "w");
+ if (f == NULL) {
+#ifdef USE_NCURSES
+ beep();
+#endif /* USE_NCURSES */
+ } else {
+ if (type == 'f' || type == 'p')
+ fprintf(f, "Newsgroups: %s\n", dest);
+ if (type == 'r' || type == 'g' || type == 'm')
+ fprintf(f, "To: %s\n", dest);
+ fprintf(f, "Subject: %s\n", subject);
+ linecount += 2;
+ if (hdr)
+ while (buf_getline(txt, NULL) == 0) linecount++;
+ else
+ fprintf(f, "\n");
+ linecount++;
+ if (txt->length == 0)
+ fprintf(f, "\n");
+
+ buf_write(txt, f);
+ fclose(f);
+ }
+
+ menu_spawn_editor(path, linecount);
+
+ f = fopen(path, "r");
+ if (f == NULL) {
+#ifdef USE_NCURSES
+ clear();
+ beep();
+ continue;
+#else /* end of USE_NCURSES */
+ goto quit;
+#endif /* else if not USE_NCURSES */
+ }
+ buf_reset(txt);
+ hdr = 0;
+
+ buf_reset(tmp);
+ buf_read(tmp, f);
+ while (buf_getheader(tmp, field, content) == 0) {
+ if (bufieq(field, "subject"))
+ strncpy(subject, content->data,
+ sizeof(subject));
+ else if ((type == 'p' || type == 'f') &&
+ bufieq(field, "newsgroups"))
+ strncpy(dest, content->data, sizeof(dest));
+ else if (bufieq(field, "to"))
+ strncpy(dest, content->data, sizeof(dest));
+ else {
+ buf_appendheader(txt, field, content);
+ hdr = 1;
+ }
+ }
+ if (hdr)
+ buf_nl(txt);
+ buf_rest(txt, tmp);
+
+ fclose(f);
+ unlink(path);
+ strcatn(path, "~", PATHMAX);
+ unlink(path);
+#ifndef USE_NCURSES
+ {
+ char line[4];
+
+ fprintf(stderr, "Send message [y/n]? ");
+ scanf("%3s", line);
+ if (!strleft(line, "y"))
+ goto quit;
+ }
+#else /* end of not USE_NCURSES */
+ goto redraw;
+ }
+ break;
+ case 'm':
+ if (txt->length == 0)
+ beep();
+ else if (dest[0] == '\0') {
+ mix_status("No destination given.");
+ goto redraw;
+ } else {
+ mix_status("Creating message...");
+#endif /* else if USE_NCURSES */
+ buf_reset(msg);
+
+ if (type == 'p' || type == 'f')
+ buf_appends(msg, "Newsgroups: ");
+ else
+ buf_appends(msg, "To: ");
+ buf_appends(msg, dest);
+ buf_nl(msg);
+ buf_appends(msg, "Subject: ");
+ if (subject[0] == '\0')
+ buf_appends(msg, "(no subject)");
+ else
+ buf_appends(msg, subject);
+ buf_nl(msg);
+ if (!hdr)
+ buf_nl(msg);
+ buf_cat(msg, txt);
+#ifdef USE_PGP
+ {
+ BUFFER *p;
+
+ p = buf_new();
+ if (streq(thisnym, ANON))
+ sign = 0;
+ if (sign || (key && !strileft(thisnym, NONANON)))
+ user_pass(p);
+
+ if (encrypt || sign) {
+ if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0)
+ | (sign ? PGP_SIGN : 0) | PGP_TEXT
+ | (strleft(thisnym, NONANON) ? 0 : PGP_REMAIL),
+ msg, strleft(thisnym, NONANON) ?
+ ADDRESS : thisnym, p, PGPPUBRING,
+ strleft(thisnym, NONANON) ?
+ PGPSECRING : NYMSECRING) == -1) {
+ mix_genericerror();
+#ifdef USE_NCURSES
+ beep();
+ goto redraw;
+#endif /* USE_NCURSES */
+ }
+ }
+ buf_free(p);
+ }
+#endif /* USE_PGP */
+
+ if (strleft(thisnym, NONANON)) {
+ FILE *f = NULL;
+
+ if (type == 'p' || type == 'f') {
+ if (strchr(NEWS, '@')) {
+ /* NOT_IMPLEMENTED; */
+ } else
+ f = openpipe(NEWS);
+ } else {
+ if (NAME[0]) {
+ buf_sets(tmp, NAME);
+ buf_appends(tmp, " <");
+ buf_appends(tmp, ADDRESS);
+ buf_appends(tmp, ">");
+ } else
+ buf_sets(tmp, ADDRESS);
+ mail_encode(msg, 0);
+ if (sendmail(msg, tmp->data, NULL) != 0) {
+#ifdef USE_NCURSES
+ clear();
+#endif /* USE_NCURSES */
+ mix_status("Error sending message.");
+#ifdef USE_NCURSES
+ goto redraw;
+#else /* end of USE_NCURSES */
+ goto quit;
+#endif /* else if not USE_NCURSES */
+ }
+ }
+#ifdef USE_NCURSES
+ clear();
+#endif /* USE_NCURSES */
+ mix_status("Message sent non-anonymously.");
+ goto quit;
+ } else {
+#ifdef USE_PGP
+#ifdef NYMSUPPORT
+ if (!streq(thisnym, ANON)) {
+ if (nym_encrypt(msg, thisnym, (type == 'p' || type == 'f') ?
+ MSG_POST : MSG_MAIL) == 0)
+ type = 'm';
+ }
+#endif /* NYMSUPPORT */
+#endif /* USE_PGP */
+ err = mix_encrypt((type == 'p' || type == 'f') ?
+ MSG_POST : MSG_MAIL,
+ msg, chain, numcopies, chainlist);
+ if (err == 0) {
+#ifdef USE_NCURSES
+ clear();
+#endif /* USE_NCURSES */
+ for (n = 0; buf_getline(chainlist, tmp) == 0; n++) ;
+ if (n > 1)
+ mix_status("Done. (%d packets)", n);
+ else
+ mix_status("Chain: %s", chainlist->data);
+ goto quit;
+ } else {
+#ifdef USE_NCURSES
+ beep();
+#endif /* USE_NCURSES */
+ if (chainlist->length)
+ mix_status("%s", chainlist->data);
+ else
+ mix_genericerror();
+ }
+ }
+ }
+#ifdef USE_NCURSES
+ break;
+ case 'q':
+ case 'Q':
+ clear();
+ goto quit;
+#ifdef USE_PGP
+ case 'p':
+ if (!streq(thisnym, ANON))
+ sign = !sign;
+ break;
+ case 'y':
+ encrypt = !encrypt;
+ break;
+ case 'k':
+ if (!streq(thisnym, ANON)) {
+ BUFFER *p, *keytxt, *uid;
+
+ key = 1;
+ p = buf_new();
+ keytxt = buf_new();
+ uid = buf_new();
+
+ buf_appendf(uid, "<%s>", strleft(thisnym, NONANON) ? ADDRESS :
+ thisnym);
+ user_pass(p);
+ pgp_pubkeycert(uid, strleft(thisnym, NONANON) ?
+ PGPSECRING : NYMSECRING, p, keytxt, PGP_ARMOR_NYMKEY);
+
+ buf_clear(msg);
+ if (!hdr)
+ buf_nl(msg);
+ buf_cat(msg, txt);
+ buf_sets(p, "application/pgp-keys");
+ mime_attach(msg, keytxt, p);
+ hdr = 1;
+ buf_move(txt, msg);
+
+ buf_free(p);
+ buf_free(keytxt);
+ buf_free(uid);
+ }
+ break;
+#endif /* USE_PGP */
+ default:
+ beep();
+ }
+ }
+ }
+#endif /* USE_NCURSES */
+quit:
+ buf_free(cc);
+ buf_free(cite);
+ buf_free(msg);
+ buf_free(txt);
+ buf_free(field);
+ buf_free(content);
+ buf_free(chainlist);
+ buf_free(tmp);
+}
diff --git a/Src/menustats.c b/Src/menustats.c
@@ -0,0 +1,445 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Menu-based user interface
+ $Id: menustats.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#if 0
+void errlog(int type, char *format, ...) { };
+char MIXDIR[512];
+#include "util.c"
+#include "buffers.c"
+int menu_getuserpass(BUFFER *p, int mode) { return 0; };
+#endif
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "menu.h"
+#ifdef WIN32
+#include <urlmon.h>
+#pragma comment(lib,"urlmon.lib")
+#else
+#include <sys/wait.h>
+#endif /* WIN32 */
+
+
+int url_download(char *url, char *dest) {
+ int err;
+#ifdef WIN32
+ err = URLDownloadToFile(NULL, url, dest, BINDF_GETNEWESTVERSION, NULL);
+
+ if (err != S_OK)
+ return -1;
+ else
+ return 0;
+#else
+ char s[PATHMAX];
+ snprintf(s, PATHMAX, "%s -q %s -O %s", WGET, url, dest);
+ err = system(s);
+
+ if (err != -1) {
+ if (WIFEXITED(err) == 0)
+ return -1; /* abnormal child exit */
+ else
+ return 0;
+ }
+ else
+ return -1;
+#endif /* WIN32 */
+}
+
+/** read the allpingers file into the buffer */
+void read_allpingers(BUFFER *allpingers) {
+ FILE *f;
+
+ f = mix_openfile(ALLPINGERSFILE, "r");
+ if (f != NULL) {
+ buf_clear(allpingers);
+ buf_read(allpingers, f);
+ fclose(f);
+ }
+}
+
+/* Get all sections from inifile.
+ *
+ * They are put into the sections buffer, separated by newlines
+ */
+void get_sections(BUFFER *inifile, BUFFER *sections) {
+ BUFFER *line;
+ int err;
+
+ line = buf_new();
+
+ buf_rewind(inifile);
+ buf_reset(sections);
+
+ while ((err = buf_getline(inifile, line)) != -1) {
+ if (bufileft (line, "[") &&
+ bufiright(line, "]")) {
+ line->data[line->length-1] = '\0';
+ buf_appends(sections, line->data+1);
+ buf_nl(sections);
+ };
+ }
+ buf_free (line);
+}
+
+/* Get value of an attribute
+ *
+ * returns -1 if it isn't found.
+ */
+int get_attribute(BUFFER *inifile, char *section, char *attribute, BUFFER *value) {
+ BUFFER *line;
+ int err = -1;
+ int insection = 0;
+
+ line = buf_new();
+
+ buf_rewind(inifile);
+ buf_reset(value);
+
+ while (buf_getline(inifile, line) != -1) {
+ if (bufileft (line, "[") &&
+ bufiright(line, "]")) {
+ if (insection)
+ break;
+
+ line->data[line->length-1] = '\0';
+ if (strcasecmp(section, line->data+1) == 0) {
+ insection = 1;
+ }
+ } else if (insection && bufileft(line, attribute)) {
+ /* we are in the right section and this attribute name
+ * at least starts with what we want */
+ char *ptr = line->data + strlen(attribute);
+ /* eat up whitespace */
+ while ((*ptr == ' ') || (*ptr == '\t'))
+ ptr++;
+ if (*ptr != '=')
+ continue;
+ ptr++;
+ while ((*ptr == ' ') || (*ptr == '\t'))
+ ptr++;
+ buf_appends(value, ptr);
+ err = 0;
+ break;
+ }
+ }
+ buf_free (line);
+ return (err);
+}
+
+
+
+
+
+static char *files[] = { "mlist", "rlist", "mixring", "pgpring"};
+#define NUMFILES sizeof(files)/sizeof(*files)
+
+/* Download all the needed files from the specified source */
+/* returns -1 on error */
+int stats_download(BUFFER *allpingers, char *sourcename, int curses) {
+ char *localfiles[] = { TYPE2REL, TYPE1LIST, PUBRING, PGPREMPUBASC };
+ char path[PATHMAX];
+ char path_t[PATHMAX];
+ BUFFER *value;
+ int ret = 0;
+ int err;
+ int i;
+
+ value = buf_new();
+
+ if (curses) {
+ clear();
+ }
+
+ err = get_attribute(allpingers, sourcename, "base", value);
+ if (err == 0) {
+ if (curses) {
+ standout();
+ printw("%s", value->data);
+ standend();
+ }
+ else
+ printf("%s\n\r", value->data);
+ }
+
+/* Loop to get each file in turn to a temp file */
+
+ for (i=0; i<NUMFILES; i++) {
+ err = get_attribute(allpingers, sourcename, files[i], value);
+ if (err < 0) {
+ /* the attribute vanished under us */
+ ret = -1;
+ break;
+ }
+ mixfile(path, localfiles[i]);
+ if (curses) {
+ mvprintw(i+3, 0, "downloading %s from %s...", localfiles[i], value->data);
+ refresh();
+ }
+ else
+ printf("downloading %s from %s...", localfiles[i], value->data);
+ err = url_download(value->data, strcat(path, ".t"));
+ if (err < 0) {
+ if (curses)
+ printw("failed to download.\n\rTry using another stats source.");
+ else
+ printf("failed to download.\n\rTry using another stats source.\n\r");
+ ret = -1;
+ break;
+ }
+ if (curses)
+ printw("done");
+ else
+ printf("done\n\r");
+ }
+
+/* We got them all ok - so rename them to their correct names */
+
+ for (i=0; i<NUMFILES; i++) {
+ mixfile(path, localfiles[i]);
+ mixfile(path_t, localfiles[i]);
+ strcat(path_t, ".t");
+ rename(path_t, path);
+ }
+
+ if (curses) {
+ printw("\n\n\n\n\rPress any key to continue");
+ getch();
+ clear();
+ }
+ buf_free(value);
+ return ret;
+}
+/* Checks whether the stats source has all the required files.
+ *
+ * 1 if it has,
+ * 0 otherwise
+ */
+int good_stats_source (BUFFER *allpingers, char *sourcename) {
+ BUFFER *value;
+ int i;
+ int res = 1;
+ int err;
+
+ value = buf_new();
+
+ for (i = 0; i < NUMFILES; i++) {
+ err = get_attribute(allpingers, sourcename, files[i], value);
+ if (err < 0) {
+ res = 0;
+ break;
+ }
+ }
+
+ buf_free (value);
+ return (res);
+}
+
+/* Do a stats download update and report status */
+/* 0 on success */
+/* -1 File download failed */
+/* -2 Error writing file */
+/* -3 Stats source incomplete */
+
+int download_stats(char *sourcename) {
+ BUFFER *inifile;
+ FILE *f;
+ int ret;
+ inifile = buf_new();
+ read_allpingers(inifile);
+ if (good_stats_source(inifile, sourcename) == 1) {
+ if (stats_download(inifile, sourcename, 0) == 0) {
+ f = mix_openfile(STATSSRC, "w+");
+ if (f != NULL) {
+ fprintf(f, "%s", sourcename);
+ fclose(f);
+ ret = 0;
+ } else {
+ ret = -2;
+ errlog(ERRORMSG, "Could not open stats source file for writing.\n");
+ }
+ } else {
+ ret = -1;
+ errlog(ERRORMSG, "Stats source download failed.\n");
+ }
+ } else {
+ ret = -3;
+ errlog(ERRORMSG, "Stats source does not include all required files.\n");
+ }
+
+ buf_free(inifile);
+ return (ret);
+}
+
+
+/* Download allpingers.txt */
+/* -1 on error */
+static int download_list() {
+ char path[PATHMAX];
+
+ mixfile(path, ALLPINGERSFILE);
+
+ clear();
+ standout();
+ printw(ALLPINGERSURL);
+ standend();
+
+ mvprintw(3,0,"downloading %s...", ALLPINGERSURL);
+ refresh();
+ if (url_download(ALLPINGERSURL, path) < 0) {
+ printw("failed to download.\n\rTry again later.");
+ printw("\n\n\rPress any key to continue");
+ getch();
+ return -1;
+ }
+ return 0;
+}
+
+/* Displays the choice of stats sources */
+#define MAXPING (26 * 2)
+void update_stats() {
+ char c;
+ BUFFER *inifile;
+ BUFFER *pingernames;
+ BUFFER *goodpingers;
+ BUFFER *line;
+ BUFFER *statssrc;
+ FILE *f;
+ int num;
+ int err;
+ int x, y;
+ int i;
+
+ inifile = buf_new();
+ pingernames = buf_new();
+ goodpingers = buf_new();
+ line = buf_new();
+ statssrc = buf_new();
+
+ while (1) {
+ clear();
+ standout();
+ buf_clear(statssrc);
+ f = mix_openfile(STATSSRC, "r");
+ if (f != NULL) {
+ buf_read(statssrc, f);
+ fclose(f);
+ }
+ printw("Select stats source:");
+ standend();
+ if (statssrc->length > 0)
+ printw(" Current: %s (Enter to download)", statssrc->data);
+ printw("\n\n");
+
+ read_allpingers(inifile);
+ get_sections (inifile, pingernames);
+
+ num = 0;
+ buf_reset(goodpingers);
+ buf_rewind(pingernames);
+ while ((buf_getline(pingernames, line) != -1) && num < MAXPING) {
+ if (good_stats_source (inifile, line->data)) {
+ buf_cat(goodpingers, line);
+ buf_nl(goodpingers);
+ num++;
+ }
+ }
+
+ x = 0;
+ buf_rewind(goodpingers);
+ for (i=0; i<num; i++) {
+ err = buf_getline(goodpingers, line);
+ assert (err != -1);
+ y = i;
+ if (y >= LINES - 6)
+ y -= LINES - 6, x = 40;
+ mvprintw(y + 2, x, "%c", i < 26 ? i + 'a' : i - 26 + 'A');
+ mvprintw(y + 2, x + 2, "%s", line->data);
+ }
+ y = i + 3;
+ if (y > LINES - 4)
+ y = LINES - 4;
+ mvprintw(y, 0, "* update list of pingers from web = edit list <space> to exit");
+ c = getch();
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ if (c >= 'a')
+ c -= 'a';
+ else
+ c = c - 'A' + 26;
+ if (c < num) {
+ buf_rewind(goodpingers);
+ while (c >= 0) {
+ err = buf_getline(goodpingers, line);
+ assert (err != -1);
+ c--;
+ }
+ if (stats_download(inifile, line->data, 1) == 0) {
+ f = mix_openfile(STATSSRC, "w+");
+ if (f != NULL) {
+ fprintf(f, "%s", line->data);
+ fclose(f);
+ } else
+ fprintf(stderr, "Could not open stats source file for writing\n");
+ break;
+ }
+ }
+ }
+ else if (c == '*') {
+ download_list();
+ }
+ else if (c == '=') {
+ char path[PATHMAX];
+ mixfile(path, ALLPINGERSFILE);
+ menu_spawn_editor(path, 0);
+ }
+ else if ((c == '\r') && statssrc->length) {
+ stats_download(inifile, statssrc->data, 1);
+ break;
+ }
+ else if (c == ' ') {
+ break;
+ }
+ }
+ clear();
+
+ buf_free(statssrc);
+ buf_free(inifile);
+ buf_free(line);
+ buf_free(pingernames);
+ buf_free(goodpingers);
+}
+
+#if 0
+int main() {
+ strcpy(MIXDIR,"./");
+
+ BUFFER *allpingers;
+ BUFFER *pingernames;
+ BUFFER *value;
+
+ allpingers = buf_new();
+ pingernames = buf_new();
+ value = buf_new();
+
+ read_allpingers (allpingers);
+ get_sections (allpingers, pingernames);
+
+ printf("%s", pingernames->data);
+
+ get_attribute (allpingers, "noreply", "rlist", value);
+ printf("%s\n", value->data);
+
+
+ exit(0);
+}
+
+#endif
diff --git a/Src/menuutil.c b/Src/menuutil.c
@@ -0,0 +1,154 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Menu-based user interface - utility functions
+ $Id: menuutil.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "menu.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+int menu_initialized = 0;
+
+#ifdef USE_NCURSES
+void cl(int y, int x)
+{
+ move(y, x);
+ hline(' ', COLS - x);
+}
+#endif /* USE_NCURSES */
+
+void menu_init(void)
+{
+#ifdef USE_NCURSES
+ initscr();
+ cbreak();
+ noecho();
+ nonl();
+ intrflush(stdscr, FALSE);
+ keypad(stdscr, TRUE);
+ menu_initialized = 1;
+#endif /* USE_NCURSES */
+}
+
+void menu_exit(void)
+{
+ user_delpass();
+#ifdef USE_NCURSES
+ endwin();
+#endif /* USE_NCURSES */
+}
+
+#ifdef USE_NCURSES
+void askfilename(char *path)
+{
+ char line[PATHMAX];
+
+ printw("\rFile name: ");
+ echo();
+ wgetnstr(stdscr, path, PATHMAX);
+ noecho();
+ printw("\r");
+ if (path[0] == '~') {
+ char *h;
+
+ if ((h = getenv("HOME")) != NULL) {
+ strncpy(line, h, PATHMAX);
+ strcatn(line, "/", PATHMAX);
+ strcatn(line, path + 1, PATHMAX);
+ strncpy(path, line, PATHMAX);
+ }
+ }
+}
+
+void savemsg(BUFFER *message)
+{
+ char savename[PATHMAX];
+ FILE *f;
+
+ askfilename(savename);
+ f = fopen(savename, "a");
+ if (f != NULL) {
+ buf_write(message, f);
+ fclose(f);
+ }
+}
+
+#endif /* USE_NCURSES */
+
+void menu_spawn_editor(char *path, int lineno) {
+#ifdef WIN32
+ SHELLEXECUTEINFO sei;
+ ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
+ sei.cbSize = sizeof(SHELLEXECUTEINFO);
+ sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
+ sei.hwnd = NULL;
+ sei.lpVerb = "open";
+ sei.lpFile = path;
+ sei.lpParameters = NULL;
+ sei.nShow = SW_SHOWNORMAL;
+
+ if (ShellExecuteEx(&sei) == TRUE) {
+ WaitForSingleObject(sei.hProcess, INFINITE);
+ CloseHandle(sei.hProcess);
+ }
+#else /* WIN32 */
+ char *editor;
+ char s[PATHMAX];
+
+/* Command line option +nn to position the cursor? */
+#define cursorpos (strfind(editor, "emacs") || streq(editor, "vi") || \
+ streq(editor, "joe"))
+
+ editor = getenv("EDITOR");
+ if (editor == NULL)
+ editor = "vi";
+
+ if (lineno > 1 && cursorpos)
+ snprintf(s, PATHMAX, "%s +%d %s", editor, lineno, path);
+ else
+ snprintf(s, PATHMAX, "%s %s", editor, path);
+
+#ifdef USE_NCURSES
+ clear();
+ refresh();
+ endwin();
+#endif /* USE_NCURSES */
+ system(s);
+#ifdef USE_NCURSES
+ refresh();
+#endif /* USE_NCURSES */
+
+#endif /* WIN32 */
+}
+
+int menu_getuserpass(BUFFER *b, int mode)
+{
+#ifdef USE_NCURSES
+ char p[LINELEN];
+
+ if (menu_initialized) {
+ cl(LINES - 1, 10);
+ if (mode == 0)
+ printw("enter passphrase: ");
+ else
+ printw("re-enter passphrase: ");
+ wgetnstr(stdscr, p, LINELEN);
+ cl(LINES - 1, 10);
+ refresh();
+ if (mode == 0)
+ buf_appends(b, p);
+ else
+ return (bufeq(b, p));
+ return (0);
+ }
+#endif /* USE_NCURSES */
+ return (-1);
+}
diff --git a/Src/mime.c b/Src/mime.c
@@ -0,0 +1,814 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ MIME functions
+ $Id: mime.c 934 2006-06-24 13:40:39Z rabbi $ */
+
+
+#include "mix3.h"
+#include <ctype.h>
+#include <string.h>
+
+#define hex(i) (isdigit(i) ? (i) - '0' : tolower(i) - 'a' + 10)
+
+#define hexdigit(i) ((byte)(i < 10 ? i + '0' : i - 10 + 'A'))
+
+static void encode_word(BUFFER *in)
+{
+ BUFFER *out;
+ int i;
+
+ out = buf_new();
+ for (i = 0; i < in->length; i++)
+ if (in->data[i] < 32 || in->data[i] >= 127 || in->data[i] == '='
+ || in->data[i] == '?' || in->data[i] == '_') {
+ buf_appendc(out, '=');
+ buf_appendc(out, hexdigit(in->data[i] / 16));
+ buf_appendc(out, hexdigit(in->data[i] % 16));
+ } else if (in->data[i] == ' ')
+ buf_appendc(out, '_');
+ else
+ buf_appendc(out, in->data[i]);
+ buf_move(in, out);
+ buf_free(out);
+}
+
+void body_encode(BUFFER *in, int transport, BUFFER *hdr)
+{
+ BUFFER *out;
+ int c, l=0, encoding = 0;
+ out = buf_new();
+
+ buf_clear(hdr);
+
+ l = in->ptr;
+ while ((c = buf_getc(in)) != -1 && encoding != 2) {
+ if (c >= 160)
+ encoding = 1;
+ else if (c == ' ') {
+ if (buf_getc(in) == '\n')
+ encoding = 1;
+ buf_ungetc(in);
+ } else if ((c < 32 && c != ' ' && c != '\n' && c != '\t') ||
+ (c >= 127 && c < 160)) {
+ encoding = 2;
+ }
+ }
+ in->ptr = l;
+
+ if (encoding == 2) {
+ buf_sets(hdr, "Content-Transfer-Encoding: base64\n");
+ encode(in, 76);
+ } else {
+
+#if 0
+ if (encoding == 0)
+ buf_sets(hdr, "Content-Transfer-Encoding: 7bit\n");
+#endif
+ if (encoding != 0 && transport == MIME_8BIT)
+ buf_sets(hdr, "Content-Transfer-Encoding: 8bit\n");
+ if (encoding == 0 || transport == MIME_8BIT) {
+ buf_rest(out, in); /* transparent */
+ buf_move(in, out);
+ } else {
+ buf_sets(hdr, "Content-Transfer-Encoding: quoted-printable\n");
+ l = 0;
+ while ((c = buf_getc(in)) != -1) {
+ if (c == '\n') {
+ buf_nl(out);
+ l = 0;
+ }
+ else if (c < 32 || c >= 127 || c == '=') {
+ if (l > 73) {
+ buf_appends(out, "=\n");
+ l = 0;
+ }
+ buf_appendc(out, '=');
+ buf_appendc(out, hexdigit(c / 16));
+ buf_appendc(out, hexdigit(c % 16));
+ l += 3;
+ } else if (c == ' ') {
+ if (buf_getc(in) == '\n') {
+ buf_appendc(out, '=');
+ buf_appendc(out, hexdigit(c / 16));
+ buf_appendc(out, hexdigit(c % 16));
+ buf_nl(out);
+ l = 0;
+ } else {
+ buf_appendc(out, c);
+ buf_ungetc(in);
+ l++;
+ }
+ } else {
+ buf_appendc(out, c);
+ l++;
+ }
+ }
+ buf_move(in, out);
+ }
+ }
+ buf_free(out);
+}
+
+int mail_encode(BUFFER *in, int encoding)
+{
+ BUFFER *out, *line, *tmp;
+
+ out = buf_new();
+ line = buf_new();
+ tmp = buf_new();
+
+ while (buf_getline(in, line) == 0) {
+ hdr_encode(line, 255);
+ buf_cat(out, line);
+ buf_nl(out);
+ }
+ if (in->ptr < in->length) {
+ /* no newline if only encoding header lines */
+ if (encoding == 0) {
+ buf_nl(out);
+ buf_rest(out, in);
+ }
+ else {
+ body_encode(in, encoding, line);
+ buf_cat(out, line);
+ buf_nl(out);
+ buf_cat(out, in);
+ }
+ }
+ buf_move(in, out);
+ buf_free(line);
+ buf_free(tmp);
+ buf_free(out);
+ return (0);
+}
+
+int hdr_encode(BUFFER *in, int n)
+{
+ int i;
+ int encodeword = 0, encode = 0;
+ BUFFER *out, *word, *space;
+
+ out = buf_new();
+ word = buf_new();
+ space = buf_new();
+ for (i = 0; i <= in->length; i++) {
+ if (isspace(in->data[i]) || in->data[i] == '\0') {
+ if (word->length) {
+ if (encodeword) {
+ if (encode == 0) {
+ buf_cat(out, space);
+ buf_clear(space);
+ buf_appends(out, "=?");
+ buf_appends(out, MIMECHARSET);
+ buf_appends(out, "?Q?");
+ encode = 1;
+ } else {
+ buf_cat(space, word);
+ buf_move(word, space);
+ }
+ encode_word(word);
+ }
+ if (encode && !encodeword) {
+ encode = 0;
+ buf_appends(out, "?=");
+ }
+ buf_cat(out, space);
+ buf_cat(out, word);
+ encodeword = 0;
+ buf_clear(space);
+ buf_clear(word);
+ }
+ buf_appendc(space, in->data[i]);
+ } else {
+ if (in->data[i] < 32 || in->data[i] >= 127)
+ encodeword = 1;
+ buf_appendc(word, in->data[i]);
+ }
+ }
+ if (encode)
+ buf_appends(out, "?=");
+
+ buf_move(in, out);
+ while (n > 0 && in->length - in->ptr > n) {
+ for (i = 1; i < in->length - in->ptr; i++)
+ if (isspace(in->data[in->length - i]))
+ break;
+ buf_get(in, out, in->length - i);
+ buf_appends(out, "\n\t");
+ }
+ buf_rest(out, in);
+ buf_move(in, out);
+ buf_free(out);
+ buf_free(space);
+ buf_free(word);
+ return (0);
+}
+
+void addprintable(BUFFER *out, int c)
+{
+ if (c == '\n')
+ buf_appendc(out, (char) c);
+ else if (c == '\t')
+ buf_appends(out, " ");
+ else if (c == '\014')
+ buf_appends(out, "^L");
+ else if (c == '\r') ;
+ else if (c <= 31 || (c >= 128 && c <= 128 + 31))
+ buf_appendc(out, '?');
+ else
+ buf_appendc(out, (char) c);
+}
+
+void addprintablebuf(BUFFER *out, BUFFER *in)
+{
+ int c;
+
+ while ((c = buf_getc(in)) != -1)
+ addprintable(out, c);
+}
+
+int decode_line(BUFFER *line)
+{
+ BUFFER *out;
+ unsigned int i;
+ int c, softbreak = 0;
+
+ out = buf_new();
+ for (i = 0; line->data[i] != '\0'; i++) {
+ if (line->data[i] == '=') {
+ if (isxdigit(line->data[i + 1]) && isxdigit(line->data[i + 2])) {
+ c = hex(line->data[i + 1]) * 16 + hex(line->data[i + 2]);
+ i += 2;
+ addprintable(out, c);
+ } else if (line->data[i + 1] == '\0') {
+ softbreak = 1;
+ break;
+ }
+ } else
+ addprintable(out, line->data[i]);
+ }
+
+ buf_move(line, out);
+ buf_free(out);
+ return (softbreak);
+}
+
+int decode_header(BUFFER *in)
+{
+ int encoded = 0;
+ int c;
+ int err = 0;
+ int last = 0;
+ BUFFER *out;
+
+ out = buf_new();
+ for (in->ptr = 0; in->data[in->ptr] != '\0'; in->ptr++) {
+ if (encoded == 'q' && in->data[in->ptr] == '=' &&
+ isxdigit(in->data[in->ptr + 1])
+ && isxdigit(in->data[in->ptr + 2])) {
+ c = hex(in->data[in->ptr + 1]) * 16 + hex(in->data[in->ptr + 2]);
+ in->ptr += 2;
+ addprintable(out, c);
+ } else if (encoded == 'q' && in->data[in->ptr] == '_')
+ buf_appendc(out, ' ');
+ else if (in->data[in->ptr] == '=' && in->data[in->ptr + 1] == '?' &&
+ in->data[in->ptr + 2] != '\0') {
+ if (last > 0 && out->length > last) {
+ out->data[last] = '\0';
+ out->length = last;
+ }
+ in->ptr++;
+ while (in->data[++in->ptr] != '?')
+ if (in->data[in->ptr] == 0) {
+ err = -1;
+ goto end;
+ }
+ if (in->data[in->ptr + 1] != '\0' && in->data[in->ptr + 2] == '?') {
+ encoded = tolower(in->data[in->ptr + 1]);
+ in->ptr += 2;
+ if (encoded == 'b') {
+ BUFFER *tmp;
+
+ tmp = buf_new();
+ decode(in, tmp);
+ addprintablebuf(out, tmp);
+ last = out->length;
+ buf_free(tmp);
+ } else if (encoded != 'q')
+ err = 1;
+ } else {
+ err = -1;
+ goto end;
+ }
+ } else if (encoded && in->data[in->ptr] == '?' &&
+ in->data[in->ptr + 1] == '=') {
+ in->ptr++;
+ last = out->length;
+ encoded = 0;
+ } else {
+ addprintable(out, in->data[in->ptr]);
+ if (!encoded || !isspace(in->data[in->ptr]))
+ last = out->length;
+ }
+ }
+end:
+ if (err == -1)
+ buf_set(out, in);
+
+ buf_move(in, out);
+ buf_free(out);
+ return (err);
+}
+
+#define delimclose 2
+
+int boundary(BUFFER *line, BUFFER *boundary)
+{
+ int c;
+
+ if (boundary->length == 0 || !bufleft(line, "--") ||
+ !strleft(line->data + 2, boundary->data))
+ return (0);
+ line->ptr = boundary->length + 2;
+ for (;;) {
+ c = buf_getc(line);
+ if (c == -1)
+ return (1);
+ if (c == '-' && buf_getc(line) == '-')
+ return (delimclose);
+ if (!isspace(c))
+ return (0);
+ }
+}
+
+#define pgpenc 1
+#define pgpsig 2
+
+/*
+ * decodes non-multipart quoted printable message
+ */
+int qp_decode_message(BUFFER *msg)
+{
+ BUFFER *out, *line, *field, *content;
+ out = buf_new();
+ line = buf_new();
+ field = buf_new();
+ content = buf_new();
+
+ buf_rewind(msg);
+
+ /* copy over headers without decoding */
+ while (buf_getheader(msg, field, content) == 0) {
+ if (bufieq(field, "content-transfer-encoding")
+ && bufieq(content, "quoted-printable")) {
+ continue; /* no longer quoted-printable */
+ } else {
+ buf_appendheader(out, field, content);
+ }
+ }
+
+ buf_nl(out);
+
+ /* copy over body, quoted-printable decoding as we go */
+ while (buf_getline(msg, line) != -1) {
+ int softbreak;
+ softbreak = decode_line(line);
+ buf_cat(out, line);
+ if (!softbreak)
+ buf_nl(out);
+ }
+ buf_move(msg, out);
+ buf_free(out);
+ buf_free(line);
+ buf_free(field);
+ buf_free(content);
+ return 0;
+}
+
+
+int entity_decode(BUFFER *msg, int message, int mptype, BUFFER *data)
+{
+ BUFFER *out, *line, *field, *content, *type, *subtype, *disposition,
+ *mboundary, *part, *sigdata;
+ int ret = 0, ptype = 0, partno = 0;
+ int p, encoded = 0;
+
+ out = buf_new();
+ line = buf_new();
+ field = buf_new();
+ content = buf_new();
+ type = buf_new();
+ subtype = buf_new();
+ disposition = buf_new();
+ mboundary = buf_new();
+ part = buf_new();
+ sigdata = buf_new();
+
+ if (message && bufileft(msg, "From ")) {
+ buf_getline(msg, out); /* envelope from */
+ buf_nl(out);
+ }
+
+ while (buf_getheader(msg, field, content) == 0) {
+ if (bufieq(field, "content-transfer-encoding") &&
+ bufieq(content, "quoted-printable"))
+ encoded = 'q';
+ if (bufieq(field, "content-type")) {
+ get_type(content, type, subtype);
+ if (bufieq(type, "multipart"))
+ get_parameter(content, "boundary", mboundary);
+ if (bufieq(type, "multipart") && bufieq(subtype, "encrypted")) {
+ get_parameter(content, "protocol", line);
+ if (bufieq(line, "application/pgp-encrypted"))
+ ptype = pgpenc;
+ }
+ if (bufieq(type, "multipart") && bufieq(subtype, "signed")) {
+ get_parameter(content, "protocol", line);
+ if (bufieq(line, "application/pgp-signature"))
+ ptype = pgpsig;
+ }
+ }
+ if (bufieq(field, "content-disposition"))
+ buf_set(disposition, content);
+ if (message) {
+ decode_header(content);
+ buf_appendheader(out, field, content);
+ }
+ }
+
+ if (message)
+ buf_nl(out);
+
+ if (bufifind(disposition, "attachment")) {
+ buf_appendf(out, "[-- %b attachment", type);
+ get_parameter(disposition, "filename", line);
+ if (line->length)
+ buf_appendf(out, " (%b)", line);
+ buf_appends(out, " --]\n");
+ }
+
+ if (mboundary->length) {
+ /* multipart */
+ while (buf_getline(msg, line) > -1 && !boundary(line, mboundary))
+ ; /* ignore preamble */
+ while (buf_getline(msg, line) != -1) {
+ p = boundary(line, mboundary);
+ if (p) {
+ if (part->data[part->length - 1] == '\n')
+ part->data[--(part->length)] = '\0';
+ partno++;
+ if (ptype == pgpsig && partno == 1)
+ buf_set(sigdata, part);
+ ret += entity_decode(part, 0, ptype, sigdata);
+ buf_cat(out, part);
+ buf_clear(part);
+ if (p == delimclose)
+ break;
+ if (bufieq(subtype, "alternative") && ret > 0)
+ break;
+ if (bufieq(subtype, "mixed"))
+ buf_appends(out,
+ "[-------------------------------------------------------------------------]\n");
+ } else {
+ buf_cat(part, line);
+ buf_nl(part);
+ }
+ }
+ } else if (mptype == pgpenc && bufieq(type, "application") &&
+ bufieq(subtype, "pgp-encrypted")) {
+ /* application/pgp-encrypted part of multipart/encrypted */
+ ; /* skip */
+ } else if (mptype == pgpenc && bufieq(type, "application") &&
+ bufieq(subtype, "octet-stream")) {
+ /* application/octet-stream part of multipart/encrypted */
+ int ok = 0;
+ buf_getline(msg, line);
+ if (bufleft(line, info_beginpgp)) {
+ if (buffind(line, "(SIGNED)")) {
+ buf_getline(msg, line);
+ buf_appends(out, "[-- OpenPGP message with signature --]\n");
+ if (bufleft(line, info_pgpsig))
+ buf_appendf(out, "[%s]\n",
+ line->data + sizeof(info_pgpsig) - 1);
+ else
+ buf_appends(out, "[Signature invalid]\n");
+ } else
+ buf_appends(out, "[-- OpenPGP message --]\n");
+ while (buf_getline(msg, line) != -1) {
+ if (bufleft(line, info_endpgp)) {
+ ret += entity_decode(part, 0, 0, NULL);
+ buf_cat(out, part);
+ buf_appends(out, "[-- End OpenPGP message --]\n");
+ ok = 1, ret++;
+ break;
+ }
+ buf_cat(part, line);
+ buf_nl(part);
+ }
+ }
+ if (!ok) {
+ buf_appends(out, "[-- Bad OpenPGP message --]\n");
+ buf_cat(out, msg);
+ }
+ } else if (mptype == pgpsig && bufeq(type, "application") &&
+ bufieq(subtype, "pgp-signature")) {
+ buf_rest(part, msg);
+#ifdef USE_PGP
+ if (pgp_decrypt(part, NULL, data, PGPPUBRING, NULL) == PGP_SIGOK)
+ buf_appendf(out, "[-- OpenPGP signature from:\n %b --]\n", data);
+ else
+ buf_appends(out, "[-- Invalid OpenPGP signature --]\n");
+#else /* USE_PGP */
+ buf_appends(out, "[-- No OpenPGP support --]\n");
+#endif /* !USE_PGP */
+ } else if (type->length == 0 || bufieq(type, "text")) {
+ while (buf_getline(msg, line) != -1) {
+ int softbreak;
+ softbreak = encoded ? decode_line(line) : 0;
+ buf_cat(out, line);
+ if (!softbreak)
+ buf_nl(out);
+ }
+ ret++;
+ } else {
+ buf_appendf(out, "[-- %b/%b message part --]\n", type, subtype);
+ buf_cat(out, msg);
+ }
+
+ buf_move(msg, out);
+ buf_free(line);
+ buf_free(out);
+ buf_free(field);
+ buf_free(content);
+ buf_free(type);
+ buf_free(subtype);
+ buf_free(disposition);
+ buf_free(mboundary);
+ buf_free(part);
+ buf_free(sigdata);
+ return (0);
+}
+
+void mimedecode(BUFFER *msg)
+{
+ entity_decode(msg, 1, 0, NULL);
+}
+
+int attachfile(BUFFER *message, BUFFER *filename)
+{
+ BUFFER *type, *attachment;
+ FILE *f;
+ int ret = -1;
+
+ type = buf_new();
+ attachment = buf_new();
+
+ if ((bufiright(filename, ".txt") || !bufifind(filename, ".")) &&(strlen(DEFLTENTITY) != 0))
+ buf_sets(type, DEFLTENTITY);
+ else if (bufiright(filename, ".htm") || bufiright(filename, ".html"))
+ buf_sets(type, "text/html");
+ else if (bufiright(filename, ".jpeg"))
+ buf_sets(type, "image/jpeg");
+ else if (bufiright(filename, ".gif"))
+ buf_sets(type, "image/gif");
+ else if (bufiright(filename, ".pcm"))
+ buf_sets(type, "audio/basic");
+ else if (bufiright(filename, ".mpg") || bufiright(filename, ".mpeg"))
+ buf_sets(type, "video/mpeg");
+ else if (bufiright(filename, ".ps"))
+ buf_sets(type, "application/postscript");
+ else
+ buf_sets(type, "application/octet-stream");
+
+ f = fopen(filename->data, "r");
+ if (f) {
+ buf_read(attachment, f);
+ fclose(f);
+ ret = mime_attach(message, attachment, type);
+ }
+
+ buf_free(attachment);
+ buf_free(type);
+ return(ret);
+}
+
+int mime_attach(BUFFER *message, BUFFER *attachment, BUFFER *attachtype)
+{
+ BUFFER *out, *part, *line, *type, *subtype, *mboundary, *field, *content;
+ int mimeheader = 0, multipart = 0, versionheader = 0;
+
+ out = buf_new();
+ line = buf_new();
+ part = buf_new();
+ type = buf_new();
+ subtype = buf_new();
+ mboundary = buf_new();
+ field = buf_new();
+ content = buf_new();
+
+ buf_rewind(message);
+ while (buf_getheader(message, field, content) == 0) {
+ if (bufieq(field, "mime-version"))
+ versionheader = 1;
+ if (bufieq(field, "content-type")) {
+ get_type(content, type, subtype);
+ if (bufieq(type, "multipart") && bufieq(subtype, "mixed")) {
+ multipart = 1;
+ get_parameter(content, "boundary", mboundary);
+ }
+ }
+ if (bufileft(field, "content-"))
+ mimeheader = 1;
+ }
+
+ if (mimeheader && !multipart) {
+ buf_rewind(message);
+ while (buf_getheader(message, field, content) == 0) {
+ if (bufileft(field, "content-"))
+ buf_appendheader(part, field, content);
+ else
+ buf_appendheader(out, field, content);
+ }
+ } else {
+ buf_ungetc(message);
+ buf_append(out, message->data, message->ptr);
+ buf_getc(message);
+ }
+
+ if (!versionheader)
+ buf_appends(out, "MIME-Version: 1.0\n");
+
+ if (!multipart) {
+ buf_setrnd(mboundary, 18);
+ encode(mboundary, 0);
+ buf_appendf(out, "Content-Type: multipart/mixed; boundary=\"%b\"\n",
+ mboundary);
+ }
+ buf_nl(out);
+
+ if (multipart) {
+ while (buf_getline(message, line) != -1) {
+ if (boundary(line, mboundary) == delimclose)
+ break;
+ buf_cat(out, line);
+ buf_nl(out);
+ }
+ } else {
+ buf_appendf(out, "--%b\n", mboundary);
+ if (part->length) {
+ buf_cat(out, part); /* body part header */
+ }
+ else {
+ if (strlen(DEFLTENTITY))
+ buf_appendf(out, "Content-Type: %s\n", DEFLTENTITY);
+ }
+
+ buf_nl(out);
+ buf_cat(out, message);
+ buf_nl(out);
+ }
+
+ buf_appendf(out, "--%b\n", mboundary);
+ buf_appendf(out, "Content-Type: %b\n", attachtype);
+
+ body_encode(attachment, MIME_8BIT, line);
+ buf_cat(out, line);
+ buf_nl(out);
+ buf_cat(out, attachment);
+ buf_appendf(out, "\n--%b--\n", mboundary);
+
+ buf_move(message, out);
+
+ buf_free(out);
+ buf_free(line);
+ buf_free(part);
+ buf_free(type);
+ buf_free(subtype);
+ buf_free(mboundary);
+ buf_free(field);
+ buf_free(content);
+ return (1);
+}
+
+static int entity_encode(BUFFER *message, BUFFER *out, BUFFER *messagehdr,
+ int encoding)
+{
+ BUFFER *field, *content, *mboundary, *part, *line, *line2, *tmp;
+
+ field = buf_new();
+ content = buf_new();
+ mboundary = buf_new();
+ part = buf_new();
+ line = buf_new();
+ line2 = buf_new();
+ tmp = buf_new();
+
+ buf_rewind(message);
+ buf_clear(out);
+ buf_clear(messagehdr);
+
+ while (buf_getheader(message, field, content) == 0) {
+ if (bufileft(field, "content-"))
+ buf_appendheader(out, field, content);
+ else if (messagehdr)
+ buf_appendheader(messagehdr, field, content);
+
+ if (bufieq(field, "content-type")) {
+ get_type(content, line, tmp);
+ if (bufieq(line, "multipart"))
+ get_parameter(content, "boundary", mboundary);
+ }
+ }
+
+ buf_nl(out);
+ if (mboundary->length) {
+ while (buf_getline(message, line) != -1) {
+ buf_cat(out, line);
+ buf_nl(out);
+ if (boundary(line, mboundary))
+ break;
+ }
+ while (buf_getline(message, line) != -1) {
+ if (boundary(line, mboundary)) {
+ entity_encode(part, tmp, line2, encoding);
+ buf_cat(out, line2);
+ buf_cat(out, tmp);
+ buf_cat(out, line);
+ buf_nl(out);
+ buf_clear(part);
+ if (boundary(line, mboundary) == delimclose)
+ break;
+ } else {
+ buf_cat(part, line);
+ buf_nl(part);
+ }
+ }
+ } else
+ buf_rest(out, message);
+ buf_rewind(out);
+ mail_encode(out, encoding);
+
+ buf_free(field);
+ buf_free(content);
+ buf_free(mboundary);
+ buf_free(part);
+ buf_free(line);
+ buf_free(line2);
+ buf_free(tmp);
+ return (1);
+}
+
+int pgpmime_sign(BUFFER *message, BUFFER *uid, BUFFER *pass, char *secring)
+{
+#ifndef USE_PGP
+ return (-1)
+#else /* end of not USE_PGP */
+ BUFFER *out, *body, *mboundary, *algo;
+ int err;
+
+ out = buf_new();
+ body = buf_new();
+ mboundary = buf_new();
+ algo = buf_new();
+
+ pgp_signhashalgo(algo, uid, secring, pass);
+
+ entity_encode(message, body, out, MIME_7BIT);
+
+ buf_setrnd(mboundary, 18);
+ encode(mboundary, 0);
+ buf_appendf(out, "Content-Type: multipart/signed; boundary=\"%b\";\n",
+ mboundary);
+ buf_appendf(out,
+ "\tmicalg=pgp-%b; protocol=\"application/pgp-signature\"\n",
+ algo);
+ buf_nl(out);
+
+ buf_appendf(out, "--%b\n", mboundary);
+ buf_cat(out, body);
+ buf_nl(out);
+ buf_appendf(out, "--%b\n", mboundary);
+
+ err = pgp_encrypt(PGP_SIGN | PGP_TEXT | PGP_DETACHEDSIG, body, NULL,
+ uid, pass, NULL, secring);
+
+ buf_appends(out, "Content-Type: application/pgp-signature\n");
+ buf_nl(out);
+ buf_cat(out, body);
+ buf_nl(out);
+ buf_appendf(out, "--%b--\n", mboundary);
+ if (err == 0)
+ buf_move(message, out);
+
+ buf_free(out);
+ buf_free(body);
+ buf_free(mboundary);
+ buf_free(algo);
+ return (err);
+#endif /* else if USE_PGP */
+}
diff --git a/Src/mix.c b/Src/mix.c
@@ -0,0 +1,1262 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+ ANY KIND, either express or implied. See the file COPYRIGHT for
+ details.
+
+ Mixmaster initialization, configuration
+ $Id: mix.c 962 2007-11-19 13:42:41Z zax $ */
+
+
+#include "mix3.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef POSIX
+#include <signal.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/utsname.h>
+#else /* end of POSIX */
+#include <io.h>
+#include <direct.h>
+#endif /* else if not POSIX */
+#ifdef WIN32
+#include <windows.h>
+#include <shlobj.h>
+#include <shlobj.h>
+#endif /* WIN32 */
+#include <assert.h>
+#include "menu.h"
+
+int buf_vappendf(BUFFER *b, char *fmt, va_list args);
+
+/** filenames ************************************************************/
+char MIXCONF[PATHMAX] = DEFAULT_MIXCONF;
+char DISCLAIMFILE[PATHMAX];
+char FROMDSCLFILE[PATHMAX];
+char MSGFOOTERFILE[PATHMAX];
+char POP3CONF[PATHMAX];
+char HELPFILE[PATHMAX];
+char REQUESTDIR[PATHMAX];
+char ABUSEFILE[PATHMAX];
+char REPLYFILE[PATHMAX];
+char USAGEFILE[PATHMAX];
+char USAGELOG[PATHMAX];
+char BLOCKFILE[PATHMAX];
+char ADMKEYFILE[PATHMAX];
+char KEYFILE[PATHMAX];
+char PGPKEY[PATHMAX];
+char DSAPARAMS[PATHMAX];
+char DHPARAMS[PATHMAX];
+char MIXRAND[PATHMAX];
+char SECRING[PATHMAX];
+char PUBRING[PATHMAX];
+char IDLOG[PATHMAX];
+char STATS[PATHMAX];
+char PGPMAXCOUNT[PATHMAX];
+char DESTBLOCK[PATHMAX];
+char DESTALLOW[PATHMAX];
+char DESTALLOW2[PATHMAX];
+char SOURCEBLOCK[PATHMAX];
+char HDRFILTER[PATHMAX];
+char REGULAR[PATHMAX];
+char POOL[PATHMAX];
+char TYPE1LIST[PATHMAX];
+char TYPE2REL[PATHMAX];
+char PIDFILE[PATHMAX];
+
+char PGPREMPUBRING[PATHMAX];
+char PGPREMPUBASC[PATHMAX];
+char PGPREMSECRING[PATHMAX];
+char NYMSECRING[PATHMAX];
+char NYMDB[PATHMAX];
+char STAREX[PATHMAX];
+
+/** config ***************************************************************/
+
+char MIXDIR[PATHMAX];
+char POOLDIR[PATHMAX];
+
+/* programs */
+char SENDMAIL[LINELEN];
+char SENDANONMAIL[LINELEN];
+char NEWS[LINELEN];
+char TYPE1[LINELEN];
+
+/* addresses */
+char MAILtoNEWS[LINELEN];
+char REMAILERNAME[LINELEN];
+char ANONNAME[LINELEN];
+char REMAILERADDR[LINELEN];
+char ANONADDR[LINELEN];
+char COMPLAINTS[LINELEN];
+int AUTOREPLY;
+char SMTPRELAY[LINELEN];
+char SMTPUSERNAME[LINELEN];
+char SMTPPASSWORD[LINELEN];
+
+#ifdef USE_SOCK
+char HELONAME[LINELEN];
+char ENVFROM[LINELEN];
+int POP3DEL;
+int POP3SIZELIMIT;
+long POP3TIME;
+
+#endif /* USE_SOCK */
+
+char SHORTNAME[LINELEN];
+char ALLPINGERSURL[BUFSIZE];
+char ALLPINGERSFILE[PATHMAX];
+char WGET[PATHMAX];
+char STATSSRC[PATHMAX];
+int STATSAUTOUPDATE;
+long STATSINTERVAL;
+
+
+/* remailer configuration */
+int REMAIL;
+int MIX;
+int PGP;
+int UNENCRYPTED;
+int REMIX;
+int REPGP;
+char EXTFLAGS[LINELEN]; /* user-defined capstring flags */
+
+char PRECEDENCE[LINELEN]; /* default Precedence: header for outgoing mail */
+int POOLSIZE;
+int RATE;
+int INDUMMYP;
+int OUTDUMMYP;
+int INDUMMYMAXP;
+int OUTDUMMYMAXP;
+int MIDDLEMAN;
+int AUTOBLOCK;
+int STATSDETAILS;
+char FORWARDTO[LINELEN];
+int SIZELIMIT; /* maximal size of remailed messages */
+int INFLATEMAX; /* maximal size of Inflate: padding */
+int MAXRANDHOPS;
+int BINFILTER; /* filter binary attachments? */
+int LISTSUPPORTED; /* list supported remailers in remailer-conf reply? */
+long PACKETEXP; /* Expiration time for old packets */
+long IDEXP; /* 0 = no ID log !! */
+long SENDPOOLTIME; /* frequency for sending pool messages */
+long MAILINTIME; /* frequency for processing MAILIN mail */
+
+long KEYLIFETIME;
+long KEYOVERLAPPERIOD;
+long KEYGRACEPERIOD;
+
+char ERRLOG[LINELEN];
+char ADDRESS[LINELEN];
+char NAME[LINELEN];
+
+char ORGANIZATION[LINELEN];
+char MID[LINELEN];
+
+/* client config */
+int NUMCOPIES;
+char CHAIN[LINELEN];
+int VERBOSE;
+int DISTANCE;
+int MINREL;
+int RELFINAL;
+long MAXLAT;
+long MINLAT;
+char PGPPUBRING[PATHMAX];
+char PGPSECRING[PATHMAX];
+char PASSPHRASE[LINELEN];
+char MAILIN[PATHMAX];
+char MAILBOX[PATHMAX];
+char MAILABUSE[PATHMAX];
+char MAILBLOCK[PATHMAX];
+char MAILUSAGE[PATHMAX];
+char MAILANON[PATHMAX];
+char MAILERROR[PATHMAX];
+char MAILBOUNCE[PATHMAX];
+
+int CLIENTAUTOFLUSH;
+int MAXRECIPIENTS;
+
+long TIMESKEW_FORWARD;
+long TIMESKEW_BACK;
+int TEMP_FAIL;
+
+char ENTEREDPASSPHRASE[LINELEN] = "";
+
+static int rereadconfig = 0;
+static int terminatedaemon = 0;
+
+#if defined(S_IFDIR) && !defined(S_ISDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif /* defined(S_IFDIR) && !defined(S_ISDIR) */
+
+static int mixdir(char *d, int create)
+{
+ int err;
+ struct stat buf;
+
+ if (d != MIXDIR)
+ strncpy(MIXDIR, d, PATHMAX);
+ if (MIXDIR[strlen(MIXDIR) - 1] == DIRSEP)
+ MIXDIR[strlen(MIXDIR) - 1] = '\0';
+ err = stat(MIXDIR, &buf);
+ if (err == -1) {
+ if (create) {
+#ifndef POSIX
+ err = mkdir(MIXDIR);
+#else /* end of not POSIX */
+ err = mkdir(MIXDIR, S_IRWXU);
+#endif /* else if POSIX */
+ if (err == 0)
+ errlog(NOTICE, "Creating directory %s.\n", MIXDIR);
+ } else
+ err = 1;
+ } else if (!S_ISDIR(buf.st_mode))
+ err = -1;
+ if (err == 0)
+ strcatn(MIXDIR, DIRSEPSTR, PATHMAX);
+ return (err);
+}
+
+void whoami(char *addr, char *defaultname)
+{
+ char *p = NULL;
+
+#if defined(HAVE_GETDOMAINNAME) || (defined(HAVE_GETHOSTNAME) && ! defined(HAVE_UNAME))
+ char line[LINELEN];
+
+#endif /* defined(HAVE_GETDOMAINNAME) || [...] */
+#ifdef HAVE_UNAME
+ struct utsname uts;
+
+#endif /* HAVE_UNAME */
+#ifdef POSIX
+ p = getlogin();
+#endif /* POSIX */
+ if (p == NULL)
+ strcpy(addr, defaultname);
+ else
+ strncpy(addr, p, LINELEN);
+
+ strcatn(addr, "@", LINELEN);
+#ifdef HAVE_UNAME
+ if (uname(&uts) != -1)
+ strcatn(addr, uts.nodename, LINELEN);
+#elif defined(HAVE_GETHOSTNAME) /* end of HAVE_UNAME */
+ if (gethostname(line, LINELEN) == 0)
+ strcatn(addr, line, LINELEN);
+#endif /* defined(HAVE_GETHOSTNAME) */
+ if (addr[strlen(addr) - 1] == '@')
+ strcatn(addr, SHORTNAME, LINELEN);
+
+ if (strchr(strchr(addr, '@'), '.') == NULL) {
+#ifdef HAVE_GETDOMAINNAME
+ if (getdomainname(line, LINELEN) == 0 && !streq(line, "(none)")) {
+ strcatn(addr, ".", LINELEN);
+ strcatn(addr, line, LINELEN);
+ }
+#endif /* HAVE_GETDOMAINNAME */
+ }
+}
+
+#define read_conf(t) readconfline(line, #t, sizeof(#t)-1, t)
+
+static int readconfline(char *line, char *name, int namelen, char *var)
+{
+ if (strncmp(line, name, namelen) == 0 &&
+ (isspace(line[namelen]) || line[namelen] == '=')) {
+ line += namelen;
+ if (*line == '=')
+ line++;
+ while (isspace(*line))
+ line++;
+ if (line[0] == '\n' || line[0] == '\0') /* leave default */
+ return (1);
+ strncpy(var, line, LINELEN);
+ if (var[strlen(var) - 1] == '\n')
+ var[strlen(var) - 1] = '\0';
+ return (1);
+ } else
+ return (0);
+}
+
+#define read_conf_i(t) readiconfline(line, #t, sizeof(#t)-1, &t)
+
+static int readiconfline(char *line, char *name, int namelen, int *var)
+{
+ if (strncmp(line, name, namelen) == 0 &&
+ (isspace(line[namelen]) || line[namelen] == '=')) {
+ line += namelen;
+ if (*line == '=')
+ line++;
+ while (isspace(*line))
+ line++;
+ if (line[0] == '\n' || line[0] == '\0') /* leave default */
+ return (1);
+ switch (tolower(line[0])) {
+ case 'n':
+ *var = 0;
+ break;
+ case 'y':
+ *var = 1;
+ break;
+ case 'x':
+ *var = 2;
+ break;
+ default:
+ sscanf(line, "%d", var);
+ }
+ return (1);
+ } else
+ return (0);
+}
+
+#define read_conf_t(t) readtconfline(line, #t, sizeof(#t)-1, &t)
+
+static int readtconfline(char *line, char *name, int namelen, long *var)
+{
+ char *linenext;
+ int mod = 0;
+ long l = 0;
+ long n;
+
+ if (strncmp(line, name, namelen) == 0 &&
+ (isspace(line[namelen]) || line[namelen] == '=')) {
+ line += namelen;
+ if (*line == '=')
+ line++;
+ for (;; line++) {
+ n = strtol(line, &linenext, 10);
+ if (linenext == line)
+ break;
+ line = linenext;
+ mod = 1;
+ assert(line != NULL);
+ while (isspace(*line))
+ line++;
+ switch (tolower(*line)) {
+ case 'y': /* years */
+ l += 365 * 24 * 60 * 60 * n;
+ break;
+ case 'b': /* months */
+ l += 30 * 24 * 60 * 60 * n;
+ break;
+ case 'w': /* weeks */
+ l += 7 * 24 * 60 * 60 * n;
+ break;
+ case 'd': /* days */
+ l += 24 * 60 * 60 * n;
+ break;
+ case 's': /* seconds */
+ l += n;
+ break;
+ case 'm': /* minutes */
+ l += 60 * n;
+ break;
+ case 'h': /* hours - default */
+ default:
+ l += 60 * 60 * n;
+ break;
+ }
+ }
+ if (mod)
+ *var = l;
+ return (1);
+ } else
+ return (0);
+}
+
+static void mix_setdefaults()
+{
+#define strnncpy(a,b) strncpy(a, b, sizeof(a)); a[sizeof(a)-1] = '\0'
+
+ strnncpy(DISCLAIMFILE , DEFAULT_DISCLAIMFILE);
+ strnncpy(FROMDSCLFILE , DEFAULT_FROMDSCLFILE);
+ strnncpy(MSGFOOTERFILE, DEFAULT_MSGFOOTERFILE);
+ strnncpy(POP3CONF , DEFAULT_POP3CONF);
+ strnncpy(HELPFILE , DEFAULT_HELPFILE);
+ strnncpy(REQUESTDIR , DEFAULT_REQUESTDIR);
+ strnncpy(ABUSEFILE , DEFAULT_ABUSEFILE);
+ strnncpy(REPLYFILE , DEFAULT_REPLYFILE);
+ strnncpy(USAGEFILE , DEFAULT_USAGEFILE);
+ strnncpy(USAGELOG , DEFAULT_USAGELOG);
+ strnncpy(BLOCKFILE , DEFAULT_BLOCKFILE);
+ strnncpy(ADMKEYFILE , DEFAULT_ADMKEYFILE);
+ strnncpy(KEYFILE , DEFAULT_KEYFILE);
+ strnncpy(PGPKEY , DEFAULT_PGPKEY);
+ strnncpy(DSAPARAMS , DEFAULT_DSAPARAMS);
+ strnncpy(DHPARAMS , DEFAULT_DHPARAMS);
+ strnncpy(MIXRAND , DEFAULT_MIXRAND);
+ strnncpy(SECRING , DEFAULT_SECRING);
+ strnncpy(PUBRING , DEFAULT_PUBRING);
+ strnncpy(IDLOG , DEFAULT_IDLOG);
+ strnncpy(STATS , DEFAULT_STATS);
+ strnncpy(PGPMAXCOUNT , DEFAULT_PGPMAXCOUNT);
+ strnncpy(DESTBLOCK , DEFAULT_DESTBLOCK);
+ strnncpy(DESTALLOW , DEFAULT_DESTALLOW);
+ strnncpy(DESTALLOW2 , DEFAULT_DESTALLOW2);
+ strnncpy(SOURCEBLOCK , DEFAULT_SOURCEBLOCK);
+ strnncpy(HDRFILTER , DEFAULT_HDRFILTER);
+ strnncpy(REGULAR , DEFAULT_REGULAR);
+ strnncpy(POOL , DEFAULT_POOL);
+ strnncpy(TYPE1LIST , DEFAULT_TYPE1LIST);
+ strnncpy(TYPE2REL , DEFAULT_TYPE2REL);
+ strnncpy(PIDFILE , DEFAULT_PIDFILE);
+
+ strnncpy(PGPREMPUBRING, DEFAULT_PGPREMPUBRING);
+ strnncpy(PGPREMPUBASC , DEFAULT_PGPREMPUBASC);
+ strnncpy(PGPREMSECRING, DEFAULT_PGPREMSECRING);
+ strnncpy(NYMSECRING , DEFAULT_NYMSECRING);
+ strnncpy(NYMDB , DEFAULT_NYMDB);
+ strnncpy(STAREX , DEFAULT_STAREX);
+ strnncpy(ALLPINGERSURL, DEFAULT_ALLPINGERSURL);
+ strnncpy(ALLPINGERSFILE, DEFAULT_ALLPINGERSFILE);
+ strnncpy(WGET , DEFAULT_WGET);
+ strnncpy(STATSSRC , DEFAULT_STATSSRC);
+
+ strnncpy(MIXDIR , "");
+ strnncpy(POOLDIR , "");
+
+/* programs */
+#ifdef WIN32
+ strnncpy(SENDMAIL , "outfile");
+#else /* end of WIN32 */
+ strnncpy(SENDMAIL , "/usr/lib/sendmail -t");
+#endif /* else if not WIN32 */
+ strnncpy(SENDANONMAIL , "");
+ strnncpy(NEWS , "");
+ strnncpy(TYPE1 , "");
+
+/* addresses */
+ strnncpy(MAILtoNEWS , "mail2news@dizum.com,mail2news@m2n.mixmin.net");
+ strnncpy(REMAILERNAME , "Anonymous Remailer");
+ strnncpy(ANONNAME , "Anonymous");
+ strnncpy(REMAILERADDR , "");
+ strnncpy(ANONADDR , "");
+ strnncpy(COMPLAINTS , "");
+ strnncpy(SMTPRELAY , "");
+ AUTOREPLY = 0;
+
+#ifdef USE_SOCK
+ strnncpy(HELONAME , "");
+ strnncpy(ENVFROM , "");
+ POP3DEL = 0;
+ POP3SIZELIMIT = 0;
+ POP3TIME = 60 * 60;
+
+#endif /* USE_SOCK */
+
+ strnncpy(SHORTNAME , "");
+
+/* configuration */
+ REMAIL = 0;
+ MIX = 1;
+ PGP = 1;
+ UNENCRYPTED = 0;
+ REMIX = 1;
+ REPGP = 1;
+ STATSAUTOUPDATE = 0;
+ STATSINTERVAL = 8 * 60 * 60;
+ strnncpy(EXTFLAGS, "");
+
+ strnncpy(PRECEDENCE, "");
+ POOLSIZE = 0;
+ RATE = 100;
+ INDUMMYP = 3; /* add dummy messages with probability p for each message added to the pool */
+ OUTDUMMYP = 10; /* add dummy messages with probability p each time we send from the pool */
+ INDUMMYMAXP = 84; /* for both of the above: while (rnd < p) { senddummy(); } */
+ OUTDUMMYMAXP = 96; /* set max INDUMMYP and OUTDUMMYP such that 24 and 5.25 dummy messages will */
+ MIDDLEMAN = 0; /* be generated on average. More than this is insane. */
+ AUTOBLOCK = 1;
+ STATSDETAILS = 1;
+ strnncpy(FORWARDTO, "*");
+ SIZELIMIT = 0; /* maximal size of remailed messages */
+ INFLATEMAX = 50; /* maximal size of Inflate: padding */
+ MAXRANDHOPS = 5;
+ BINFILTER = 0; /* filter binary attachments? */
+ LISTSUPPORTED = 1; /* list supported remailers in remailer-conf reply? */
+ PACKETEXP = 7 * SECONDSPERDAY; /* Expiration time for old packets */
+ IDEXP = 7 * SECONDSPERDAY; /* 0 = no ID log !! */
+ SENDPOOLTIME = 0; /* frequency for sending pool messages */
+ MAILINTIME = 5 * 60; /* frequency for processing MAILIN mail */
+
+ KEYLIFETIME = 13 * 30 * 24 * 60 * 60; /* validity period for keys. */
+ KEYOVERLAPPERIOD = 1 * 30 * 24 * 60 * 60; /* when keys have this amount of time */
+ /* left before expiration, create */
+ /* new ones when ./mix -K is run.*/
+ KEYGRACEPERIOD = 7 * 24 * 60 * 60; /* accept mail to the old key for this */
+ /* amount of time after it has expired. */
+
+
+ strnncpy(ERRLOG , "");
+ strnncpy(ADDRESS , "");
+ strnncpy(NAME , "");
+
+ strnncpy(ORGANIZATION, "Anonymous Posting Service");
+ strnncpy(MID , "y");
+
+/* client config */
+ NUMCOPIES = 1;
+ strnncpy(CHAIN, "*,*,*,*");
+ VERBOSE = 2;
+ DISTANCE = 2;
+ MINREL = 98;
+ RELFINAL = 99;
+ MAXLAT = 36 * 60 * 60;
+ MINLAT = 5 * 60;
+ strnncpy(PGPPUBRING, "");
+ strnncpy(PGPSECRING, "");
+#ifdef COMPILEDPASS
+ strnncpy(PASSPHRASE, COMPILEDPASS);
+#else /* end of COMPILEDPASS */
+ strnncpy(PASSPHRASE, "");
+#endif /* else if not COMPILEDPASS */
+ strnncpy(MAILIN , "");
+ strnncpy(MAILBOX , "mbox");
+ strnncpy(MAILABUSE , "");
+ strnncpy(MAILBLOCK , "");
+#ifdef WIN32
+ strnncpy(MAILUSAGE , "nul:");
+ strnncpy(MAILANON , "nul:");
+ strnncpy(MAILERROR , "nul:");
+#else /* end of WIN32 */
+ strnncpy(MAILUSAGE , "/dev/null");
+ strnncpy(MAILANON , "/dev/null");
+ strnncpy(MAILERROR , "/dev/null");
+#endif /* else if not WIN32 */
+ strnncpy(MAILBOUNCE, "");
+
+ CLIENTAUTOFLUSH = 1;
+ MAXRECIPIENTS = 5;
+
+ TIMESKEW_FORWARD = 2*7*24*60*60;
+ TIMESKEW_BACK = 12*60*60;
+ TEMP_FAIL = 75;
+}
+
+int mix_configline(char *line)
+{
+ return (read_conf(ADDRESS) || read_conf(NAME) ||
+ read_conf(SHORTNAME) || read_conf(REMAILERADDR) ||
+ read_conf(ANONADDR) || read_conf(REMAILERNAME) ||
+ read_conf(ANONNAME) || read_conf(COMPLAINTS) ||
+ read_conf_i(AUTOREPLY) || read_conf(SMTPRELAY) ||
+ read_conf(SMTPUSERNAME) || read_conf(SMTPPASSWORD) ||
+#ifdef USE_SOCK
+ read_conf(HELONAME) || read_conf(ENVFROM) ||
+#endif /* USE_SOCK */
+ read_conf(SENDMAIL) || read_conf(SENDANONMAIL) ||
+ read_conf(PRECEDENCE) ||
+ read_conf_i(REMAIL) || read_conf_i(MIX) ||
+ read_conf_i(PGP) || read_conf_i(UNENCRYPTED) ||
+ read_conf_i(REMIX) || read_conf(NEWS) ||
+ read_conf_i(REPGP) || read_conf(EXTFLAGS) ||
+ read_conf(MAILtoNEWS) || read_conf(ERRLOG) ||
+ read_conf(ORGANIZATION) || read_conf(MID) ||
+ read_conf(TYPE1) || read_conf_i(POOLSIZE) ||
+ read_conf_i(RATE) || read_conf_i(MIDDLEMAN) ||
+ read_conf_i(INDUMMYP) ||
+ read_conf_i(OUTDUMMYP) ||
+ read_conf_i(AUTOBLOCK) || read_conf(FORWARDTO) ||
+ read_conf_i(STATSDETAILS) ||
+ read_conf_i(SIZELIMIT) || read_conf_i(INFLATEMAX) ||
+ read_conf_i(MAXRANDHOPS) || read_conf_i(BINFILTER) ||
+ read_conf_i(LISTSUPPORTED) ||
+ read_conf_t(PACKETEXP) || read_conf_t(IDEXP) ||
+ read_conf_t(SENDPOOLTIME) || read_conf_i(NUMCOPIES) ||
+ read_conf_t(MAILINTIME) ||
+ read_conf(CHAIN) || read_conf_i(VERBOSE) ||
+ read_conf_i(DISTANCE) || read_conf_i(MINREL) ||
+ read_conf_i(RELFINAL) || read_conf_t(MAXLAT) ||
+ read_conf_t(MINLAT) ||
+ read_conf(PGPPUBRING) || read_conf(PGPSECRING) ||
+ read_conf(PASSPHRASE) || read_conf_t(KEYLIFETIME) ||
+ read_conf_t(KEYGRACEPERIOD) || read_conf_t(KEYOVERLAPPERIOD) ||
+#ifdef USE_SOCK
+ read_conf_i(POP3DEL) || read_conf_i(POP3SIZELIMIT) ||
+ read_conf_t(POP3TIME) ||
+#endif /* USE_SOCK */
+ read_conf(MAILBOX) || read_conf(MAILABUSE) ||
+ read_conf(MAILBLOCK) || read_conf(MAILUSAGE) ||
+ read_conf(MAILANON) || read_conf(MAILERROR) ||
+ read_conf(MAILBOUNCE) || read_conf(MAILIN) ||
+
+ read_conf(DISCLAIMFILE) || read_conf(FROMDSCLFILE) ||
+ read_conf(MSGFOOTERFILE) ||
+ read_conf(POP3CONF) || read_conf(HELPFILE) ||
+ read_conf(REQUESTDIR) ||
+ read_conf(ABUSEFILE) || read_conf(REPLYFILE) ||
+ read_conf(USAGEFILE) || read_conf(USAGELOG) ||
+ read_conf(BLOCKFILE) || read_conf(ADMKEYFILE) ||
+ read_conf(KEYFILE) || read_conf(PGPKEY) ||
+ read_conf(DSAPARAMS) || read_conf(DHPARAMS) ||
+ read_conf(MIXRAND) || read_conf(SECRING) ||
+ read_conf(PUBRING) || read_conf(IDLOG) ||
+ read_conf(STATS) || read_conf(DESTBLOCK) ||
+ read_conf(PGPMAXCOUNT) ||
+ read_conf(DESTALLOW) || read_conf(DESTALLOW2) ||
+ read_conf(SOURCEBLOCK) ||
+ read_conf(STAREX) || read_conf(ALLPINGERSURL) ||
+ read_conf(ALLPINGERSFILE) ||
+ read_conf(HDRFILTER) || read_conf(REGULAR) ||
+ read_conf(POOL) || read_conf(TYPE1LIST) ||
+ read_conf(TYPE2REL) ||
+ read_conf(PGPREMPUBRING) || read_conf(PGPREMPUBASC) ||
+ read_conf(PGPREMSECRING) || read_conf(NYMSECRING) ||
+ read_conf(NYMDB) || read_conf(PIDFILE) ||
+ read_conf(WGET) || read_conf(STATSSRC) ||
+ read_conf_i(STATSAUTOUPDATE) || read_conf_t(STATSINTERVAL) ||
+
+ read_conf_i(CLIENTAUTOFLUSH) ||
+ read_conf_i(MAXRECIPIENTS) ||
+
+ read_conf_t(TIMESKEW_FORWARD) ||
+ read_conf_t(TIMESKEW_BACK) ||
+ read_conf_i(TEMP_FAIL) );
+}
+
+int mix_config(void)
+{
+ char *d;
+ FILE *f;
+ char line[PATHMAX];
+ int err = -1;
+#ifdef POSIX
+ struct passwd *pw;
+#endif /* POSIX */
+ struct stat buf;
+#ifdef HAVE_UNAME
+ struct utsname uts;
+#endif /* HAVE_UNAME */
+#ifdef WIN32
+ HKEY regsw, reg, regpgp;
+ DWORD type, len;
+ int rkey = 0;
+#endif /* WIN32 */
+
+ mix_setdefaults();
+
+#ifdef POSIX
+ pw = getpwuid(getuid());
+#endif /* POSIX */
+
+ /* find our base directory
+ *
+ * first match wins.
+ *
+ * - what the MIXPATH environment variable points to, if it is set.
+ * - On WIN32, HKEY_CURRENT_USER\Software\Mixmaster\MixDir, if it exists
+ * - whatever is compiled in with -DSPOOL
+ * - On Win32 %APPDATA%\Mixmaster
+ * - on POSIX, ~/Mix (or ~/<HOMEMIXDIR>)
+ * - the current working directory
+ */
+
+ if (err == -1 && (d = getenv("MIXPATH")) != NULL)
+ err = mixdir(d, 1);
+
+#ifdef WIN32
+ RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, ®sw);
+ len=sizeof(line);
+ if (err == -1 &&
+ RegOpenKeyEx(regsw, "Mixmaster", 0, KEY_QUERY_VALUE, ®) == 0) {
+ if (RegQueryValueEx(reg, "MixDir", 0, &type, line, &len) == 0)
+ err = mixdir(line, 1);
+ RegCloseKey(reg);
+ }
+#endif /* WIN32 */
+
+#ifdef SPOOL
+ if (err == -1 && strlen(SPOOL) > 0)
+ err = mixdir(SPOOL, 0);
+#endif /* SPOOL */
+
+#ifdef WIN32
+ if (err == -1) {
+ LPMALLOC lpmalloc;
+ ITEMIDLIST *itemidlist;
+ if (SUCCEEDED(SHGetMalloc(&lpmalloc)))
+ {
+ SHGetSpecialFolderLocation(0,CSIDL_APPDATA,&itemidlist);
+ SHGetPathFromIDList(itemidlist,line);
+ lpmalloc->lpVtbl->Free(lpmalloc,&itemidlist);
+ lpmalloc->lpVtbl->Release(lpmalloc);
+
+ strcatn(line, "\\Mixmaster", PATHMAX);
+ err = mixdir(line, 1);
+
+ }
+ }
+#endif /* WIN32 */
+
+#ifdef POSIX
+ if (err == -1 && pw != NULL) {
+ strncpy(line, pw->pw_dir, PATHMAX);
+ line[PATHMAX-1] = '\0';
+ if (line[strlen(line) - 1] != DIRSEP)
+ strcatn(line, DIRSEPSTR, PATHMAX);
+ strcatn(line, HOMEMIXDIR, PATHMAX);
+ err = mixdir(line, 1);
+ }
+#endif /* POSIX */
+
+ if (err == -1) {
+ getcwd(MIXDIR, PATHMAX);
+ mixdir(MIXDIR, 0);
+ }
+
+#ifdef GLOBALMIXCONF
+ f = mix_openfile(GLOBALMIXCONF, "r");
+ if (f != NULL) {
+ while (fgets(line, LINELEN, f) != NULL)
+ if (line[0] > ' ' && line[0] != '#')
+ mix_configline(line);
+ fclose(f);
+ }
+#endif /* GLOBALMIXCONF */
+ f = mix_openfile(MIXCONF, "r");
+ if (f != NULL) {
+ while (fgets(line, LINELEN, f) != NULL)
+ if (line[0] > ' ' && line[0] != '#')
+ mix_configline(line);
+ fclose(f);
+ }
+
+ mixfile(POOLDIR, POOL); /* set POOLDIR after reading POOL from cfg file */
+ if (POOLDIR[strlen(POOLDIR) - 1] == DIRSEP)
+ POOLDIR[strlen(POOLDIR) - 1] = '\0';
+ if (stat(POOLDIR, &buf) != 0)
+ if
+#ifndef POSIX
+ (mkdir(POOLDIR) != 0)
+#else /* end of not POSIX */
+ (mkdir(POOLDIR, S_IRWXU) == -1)
+#endif /* else if POSIX */
+ strncpy(POOLDIR, MIXDIR, PATHMAX);
+
+ if (IDEXP > 0 && IDEXP < 5 * SECONDSPERDAY)
+ IDEXP = 5 * SECONDSPERDAY;
+ if (MAXRANDHOPS > 20)
+ MAXRANDHOPS = 20;
+ if (INDUMMYP > INDUMMYMAXP)
+ INDUMMYP = INDUMMYMAXP;
+ if (OUTDUMMYP > OUTDUMMYMAXP)
+ OUTDUMMYP = OUTDUMMYMAXP;
+
+ if (strchr(SHORTNAME, '.'))
+ *strchr(SHORTNAME, '.') = '\0';
+ if (strchr(SHORTNAME, ' '))
+ *strchr(SHORTNAME, ' ') = '\0';
+#ifdef HAVE_UNAME
+ if (SHORTNAME[0] == '\0' && uname(&uts) != -1)
+ strncpy(SHORTNAME, uts.nodename, LINELEN);
+#elif defined(HAVE_GETHOSTNAME) /* end of HAVE_UNAME */
+ if (SHORTNAME[0] == '\0')
+ gethostname(SHORTNAME, LINELEN);
+#endif /* defined(HAVE_GETHOSTNAME) */
+ if (SHORTNAME[0] == '\0')
+ strcpy(SHORTNAME, "unknown");
+
+ if (ADDRESS[0] == '\0')
+ whoami(ADDRESS, "user");
+
+#ifdef HAVE_GECOS
+ if (NAME[0] == '\0' && pw != NULL)
+ strcatn(NAME, pw->pw_gecos, sizeof(NAME));
+#endif /* HAVE_GECOS */
+
+ if (REMAILERADDR[0] == '\0')
+ strncpy(REMAILERADDR, ADDRESS, LINELEN);
+
+ if (COMPLAINTS[0] == '\0')
+ strncpy(COMPLAINTS, REMAILERADDR, LINELEN);
+
+ if (strchr(REMAILERNAME, '@') == NULL) {
+ strcatn(REMAILERNAME, " <", LINELEN);
+ strcatn(REMAILERNAME, REMAILERADDR, LINELEN);
+ strcatn(REMAILERNAME, ">", LINELEN);
+ }
+ if (strchr(ANONNAME, '@') == NULL && ANONADDR[0] != '\0') {
+ strcatn(ANONNAME, " <", LINELEN);
+ strcatn(ANONNAME, ANONADDR, LINELEN);
+ strcatn(ANONNAME, ">", LINELEN);
+ }
+ if (strchr(ANONNAME, '@') == NULL) {
+ strcatn(ANONNAME, " <", LINELEN);
+ strcatn(ANONNAME, REMAILERADDR, LINELEN);
+ strcatn(ANONNAME, ">", LINELEN);
+ }
+#ifndef USE_PGP
+ if (TYPE1[0] == '\0')
+ PGP = 0;
+#endif /* not USE_PGP */
+
+#ifdef WIN32
+ if (RegOpenKeyEx(regsw, "PGP", 0, KEY_ALL_ACCESS, ®pgp) == 0)
+ rkey++;
+ if (rkey && RegOpenKeyEx(regpgp, "PGPlib", 0, KEY_QUERY_VALUE, ®) == 0)
+ rkey++;
+ if (PGPPUBRING[0] == '\0' && rkey == 2) {
+ len = PATHMAX;
+ RegQueryValueEx(reg, "PubRing", 0, &type, PGPPUBRING, &len);
+ }
+ if (PGPSECRING[0] == '\0' && rkey == 2) {
+ len = PATHMAX;
+ RegQueryValueEx(reg, "SecRing", 0, &type, PGPSECRING, &len);
+ }
+ if (rkey == 2)
+ RegCloseKey(reg);
+ if (rkey)
+ RegCloseKey(regpgp);
+ RegCloseKey(regsw);
+#endif /* WIN32 */
+
+ if (PGPPUBRING[0] == '\0') {
+ char *d;
+
+ if ((d = getenv("HOME")) != NULL) {
+ strcpy(PGPPUBRING, d);
+ strcatn(PGPPUBRING, "/.pgp/", PATHMAX);
+ }
+ strcatn(PGPPUBRING, "pubring.pkr", PATHMAX);
+ if (stat(PGPPUBRING, &buf) == -1)
+ strcpy(strrchr(PGPPUBRING, '.'), ".pgp");
+ }
+ if (PGPSECRING[0] == '\0') {
+ char *d;
+
+ if ((d = getenv("HOME")) != NULL) {
+ strcpy(PGPSECRING, d);
+ strcatn(PGPSECRING, "/.pgp/", PATHMAX);
+ }
+ strcatn(PGPSECRING, "secring.skr", PATHMAX);
+ if (stat(PGPSECRING, &buf) == -1)
+ strcpy(strrchr(PGPSECRING, '.'), ".pgp");
+ }
+ if (streq(NEWS, "mail-to-news"))
+ strncpy(NEWS, MAILtoNEWS, sizeof(NEWS));
+
+ if (f == NULL) {
+#ifndef GLOBALMIXCONF
+ /* Only write the config file in non systemwide installation */
+ f = mix_openfile(MIXCONF, "w");
+ if (f == NULL)
+ errlog(WARNING, "Can't open %s%s!\n", MIXDIR, MIXCONF);
+ else {
+ fprintf(f, "# mix.cfg - mixmaster configuration file\n");
+ fprintf(f, "NAME %s\n", NAME);
+ fprintf(f, "ADDRESS %s\n", ADDRESS);
+ fprintf(f, "\n# edit to set up a remailer:\n");
+ fprintf(f, "REMAIL n\n");
+ fprintf(f, "SHORTNAME %s\n", SHORTNAME);
+ fprintf(f, "REMAILERADDR %s\n", REMAILERADDR);
+ fprintf(f, "COMPLAINTS %s\n", COMPLAINTS);
+ fclose(f);
+ }
+#endif /* not GLOBALMIXCONF */
+ REMAIL = 0;
+ }
+
+ if (ENTEREDPASSPHRASE[0] != '\0') {
+ strncpy(PASSPHRASE, ENTEREDPASSPHRASE, LINELEN);
+ PASSPHRASE[LINELEN-1] = 0;
+ };
+
+ return (0);
+}
+
+/** Library initialization: ******************************************/
+
+static int initialized = 0;
+
+void mix_check_timeskew() {
+ FILE *f;
+ long now, tpool = 0, tpop3 = 0, tdaily = 0, tmailin = 0, latest = 0;
+
+ f = mix_openfile(REGULAR, "r+");
+ if (f != NULL) {
+ lock(f);
+ fscanf(f, "%ld %ld %ld %ld", &tpool, &tpop3, &tdaily, &tmailin);
+ latest = tpool;
+ latest = latest > tpop3 ? latest : tpop3;
+ latest = latest > tdaily ? latest : tdaily;
+ latest = latest > tmailin ? latest : tmailin;
+ now = time(NULL);
+
+
+ if (( (TIMESKEW_BACK != 0) && (now < latest - TIMESKEW_BACK )) ||
+ ( (TIMESKEW_FORWARD != 0) && (now > latest + TIMESKEW_FORWARD)) ) {
+ /* Possible timeskew */
+ errlog(ERRORMSG, "Possible timeskew detected. Check clock and rm %s\n", REGULAR);
+ exit(TEMP_FAIL);
+ }
+ fclose(f);
+ } else {
+ /* shrug */
+ }
+}
+
+int mix_init(char *mixdir)
+{
+ if (!initialized) {
+ if (mixdir)
+ strncpy(MIXDIR, mixdir, LINELEN);
+ mix_config();
+#if defined(USE_SOCK) && defined(WIN32)
+ sock_init();
+#endif /* defined(USE_SOCK) && defined(WIN32) */
+ /* atexit (mix_exit); */
+ initialized = 1;
+ }
+
+ if (rnd_init() == -1)
+ rnd_seed();
+ return(0);
+}
+
+void mix_exit(void)
+{
+ if (!initialized)
+ return;
+ rnd_final();
+#if defined(USE_SOCK) && defined(WIN32)
+ sock_exit();
+#endif /* defined(USE_SOCK) && defined(WIN32) */
+ initialized=0;
+}
+
+void mix_upd_stats(void)
+{
+ FILE *f;
+ BUFFER *statssrc;
+ statssrc = buf_new();
+ buf_clear(statssrc);
+ f = mix_openfile(STATSSRC, "r");
+ if (f != NULL) {
+ buf_read(statssrc, f);
+ fclose(f);
+ }
+ if (statssrc->length > 0)
+ download_stats(statssrc->data);
+ buf_free(statssrc);
+}
+
+int mix_regular(int force)
+{
+ FILE *f;
+ long now, tpool = 0, tpop3 = 0, tdaily = 0, tmailin = 0, tstats = 0;
+ int ret = 0;
+
+ mix_init(NULL);
+ now = time(NULL);
+
+ f = mix_openfile(REGULAR, "r+");
+ if (f != NULL) {
+ lock(f);
+ fscanf(f, "%ld %ld %ld %ld %ld", &tpool, &tpop3, &tdaily, &tmailin, &tstats);
+ if (now - tpool >= SENDPOOLTIME)
+ force |= FORCE_POOL | FORCE_MAILIN;
+#ifdef USE_SOCK
+ if (now - tpop3 >= POP3TIME)
+ force |= FORCE_POP3 | FORCE_MAILIN;
+#endif /* USE_SOCK */
+ if (now - tdaily >= SECONDSPERDAY)
+ force |= FORCE_DAILY;
+ if (now - tmailin >= MAILINTIME)
+ force |= FORCE_MAILIN;
+ if (now - tstats >= STATSINTERVAL)
+ force |= FORCE_STATS;
+ if (force & FORCE_POOL)
+ tpool = now;
+ if (force & FORCE_POP3)
+ tpop3 = now;
+ if (force & FORCE_DAILY)
+ tdaily = now;
+ if (force & FORCE_MAILIN)
+ tmailin = now;
+ if (force & FORCE_STATS)
+ tstats = now;
+ rewind(f);
+ fprintf(f, "%ld %ld %ld %ld %ld\n", tpool, tpop3, tdaily, tmailin, tstats);
+ unlock(f);
+ fclose(f);
+ } else {
+ force = FORCE_POOL | FORCE_POP3 | FORCE_DAILY | FORCE_MAILIN | FORCE_STATS;
+ f = mix_openfile(REGULAR, "w+");
+ if (f != NULL) {
+ lock(f);
+ fprintf(f, "%ld %ld %ld %ld %ld\n", now, now, now, now, now);
+ unlock(f);
+ fclose(f);
+ } else
+ errlog(ERRORMSG, "Can't create %s!\n", REGULAR);
+ }
+
+ if (force & FORCE_DAILY)
+ mix_daily(), ret = 1;
+#ifdef USE_SOCK
+ if (force & FORCE_POP3)
+ pop3get();
+#endif /* USE_SOCK */
+ if (force & FORCE_MAILIN)
+ ret = process_mailin();
+ if (force & FORCE_POOL)
+ ret = pool_send();
+ if ((force & FORCE_STATS) && (STATSAUTOUPDATE != 0))
+ mix_upd_stats();
+
+ return (ret);
+}
+
+int mix_daily(void)
+{
+ idexp();
+ pgpmaxexp();
+ pool_packetexp();
+ stats(NULL);
+ keymgt(0);
+ return (0);
+}
+
+/** Handle signals SIGHUP, SIGINT, and SIGTERM
+ This signal handler gets called if the daemon
+ process receives one of SIGHUP, SIGINT, or SIGTERM.
+ It then sets either rereadconfig of terminatedaemon
+ to true depending on the signal received.
+
+ @author PP
+ @return nothing
+ */
+#ifdef POSIX
+void sighandler(int signal) {
+ if (signal == SIGHUP)
+ rereadconfig = 1;
+ else if (signal == SIGINT || signal == SIGTERM)
+ terminatedaemon = 1;
+};
+#endif /* POSIX */
+
+/** Set the signal handler for SIGHUP, SIGINT and SIGTERM
+ This function registers signal handlers so that
+ we can react on signals send by the user in daemon
+ mode. SIGHUP will instruct mixmaster to reload its
+ configuration while SIGINT and SIGTERM will instruct
+ it to shut down. Mixmaster will finish the current
+ pool run before it terminates.
+
+ @param restart Whether or not system calls should be
+ restarted. Usually we want this, the
+ only excetion is the sleep() in the
+ daemon mail loop.
+ @author PP
+ @return -1 if calling sigaction failed, 0 on
+ no error
+ */
+int setsignalhandler(int restart)
+{
+#ifdef POSIX
+ struct sigaction hdl;
+ int err = 0;
+
+ memset(&hdl, 0, sizeof(hdl));
+ hdl.sa_handler = sighandler;
+ hdl.sa_flags = restart ? SA_RESTART : 0;
+
+ if (sigaction(SIGHUP, &hdl, NULL))
+ err = -1;
+ if (sigaction(SIGINT, &hdl, NULL))
+ err = -1;
+ if (sigaction(SIGTERM, &hdl, NULL))
+ err = -1;
+ return (err);
+#else /* POSIX */
+ return(0);
+#endif /* POSIX */
+}
+
+#ifdef WIN32
+/* Try to detect if we are the service or not...
+ seems there is no easy reliable way */
+int is_nt_service(void)
+{
+ static int issvc = -1;
+#ifdef WIN32SERVICE
+ STARTUPINFO StartupInfo;
+ OSVERSIONINFO VersionInfo;
+ DWORD dwsize;
+
+ if (issvc != -1) /* do it only once */
+ return issvc;
+
+ VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
+ if (GetVersionEx(&VersionInfo))
+ if (VersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ return issvc = 0; /* not NT - not the service */
+
+ GetStartupInfo(&StartupInfo);
+ if (StartupInfo.lpDesktop[0] == 0)
+ return issvc = 1; /* have no desktop - we are the service probably */
+#endif /* WIN32SERVICE */
+
+ return issvc = 0; /* assume not the service */
+} /* is_nt_service */
+
+HANDLE hMustTerminate = NULL;
+void set_nt_exit_event(HANDLE h_svc_exit_event)
+{
+ hMustTerminate = h_svc_exit_event;
+} /* set_nt_exit_event */
+
+#endif /* WIN32 */
+
+int mix_daemon(void)
+{
+ long t, slept;
+ t = SENDPOOLTIME;
+ if (MAILINTIME < t && (MAILIN != NULL && MAILIN[0] != '\0'))
+ t = MAILINTIME;
+#ifdef USE_SOCK
+ if (POP3TIME < t)
+ t = POP3TIME;
+#endif /* USE_SOCK */
+ if (t < 5)
+ t = 5; /* Some kind of safety for broken systems */
+ slept = t;
+
+ setsignalhandler(1); /* set signal handlers and restart any interrupted system calls */
+ for(;;) {
+ if (terminatedaemon)
+ break;
+ if (rereadconfig) {
+ rereadconfig = 0;
+ mix_config();
+ t = SENDPOOLTIME;
+ if (MAILINTIME < t && (MAILIN != NULL && MAILIN[0] != '\0'))
+ t = MAILINTIME;
+#ifdef USE_SOCK
+ if (POP3TIME < t)
+ t = POP3TIME;
+ if (t < 5)
+ t = 5; /* Some kind of safety for broken systems */
+#endif /* USE_SOCK */
+ }
+ if (slept >= t) {
+ mix_regular(0);
+ slept = 0;
+ }
+
+#ifdef WIN32SERVICE
+ if (hMustTerminate) {
+ if (WaitForSingleObject(hMustTerminate, t * 1000) == WAIT_OBJECT_0) {
+ CloseHandle(hMustTerminate);
+ terminatedaemon = 1;
+ }
+ }
+#endif /* WIN32SERVICE */
+
+ if (!terminatedaemon && !rereadconfig) {
+ setsignalhandler(0); /* set signal handlers; don't restart system calls */
+#ifdef WIN32
+ sleep(t); /* how to get the real number of seconds slept? */
+ slept = t;
+#else /* end of WIN32 */
+ slept += (t - slept) - sleep(t - slept);
+#endif /* else if not WIN32 */
+ setsignalhandler(1); /* set signal handlers and restart any interrupted system calls */
+ }
+ }
+ return (0);
+}
+
+/** error ***************************************************************/
+
+void errlog(int type, char *fmt,...)
+{
+ va_list args;
+ BUFFER *msg;
+ FILE *e = NULL;
+ time_t t;
+ struct tm *tc;
+ char line[LINELEN];
+ int p;
+ char err[6][8] =
+ {"", "Error", "Warning", "Notice", "Info", "Info"};
+
+ if ((VERBOSE == 0 && type != ERRORMSG) || (type == LOG && VERBOSE < 2)
+ || (type == DEBUGINFO && VERBOSE < 3))
+ return;
+
+ t = time(NULL);
+ tc = localtime(&t);
+ strftime(line, LINELEN, "[%Y-%m-%d %H:%M:%S] ", tc);
+
+ msg = buf_new();
+ buf_appends(msg, line);
+ p = msg->length;
+ buf_appendf(msg, "%s: ", err[type]);
+ va_start(args, fmt);
+ buf_vappendf(msg, fmt, args);
+ va_end(args);
+
+ if (streq(ERRLOG, "stdout"))
+ e = stdout;
+ else if (streq(ERRLOG, "stderr"))
+ e = stderr;
+
+ if (e == NULL && (ERRLOG[0] == '\0' ||
+ (e = mix_openfile(ERRLOG, "a")) == NULL))
+ mix_status("%s", msg->data + p);
+ else {
+ buf_write(msg, e);
+ if (e != stderr && e != stdout) {
+ fclose(e);
+ /* duplicate the error message on screen */
+ mix_status("%s", msg->data + p);
+ }
+ }
+ buf_free(msg);
+}
+
+static char statusline[BUFSIZE] = "";
+
+void mix_status(char *fmt,...)
+{
+ va_list args;
+
+ if (fmt != NULL) {
+ va_start(args, fmt);
+#ifdef _MSC
+ _vsnprintf(statusline, sizeof(statusline) - 1, fmt, args);
+#else /* end of _MSC */
+ vsnprintf(statusline, sizeof(statusline) - 1, fmt, args);
+#endif /* else if not _MSC */
+ va_end(args);
+ }
+#ifdef USE_NCURSES
+ if (menu_initialized) {
+ cl(LINES - 2, 10);
+ printw("%s", statusline);
+ refresh();
+ } else
+#endif /* USE_NCURSES */
+ {
+ fprintf(stderr, "%s", statusline);
+ }
+}
+
+void mix_genericerror(void)
+{
+ if (streq(statusline, "") || strfind(statusline, "...") ||
+ strifind(statusline, "generating"))
+ mix_status("Failed!");
+ else
+ mix_status(NULL);
+}
diff --git a/Src/mix.h b/Src/mix.h
@@ -0,0 +1,917 @@
+/* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
+
+ Mixmaster may be redistributed and modified under certain conditions.
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF