Initial revision
authorPekka Riikonen <priikone@silcnet.org>
Tue, 27 Jun 2000 11:36:50 +0000 (11:36 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 27 Jun 2000 11:36:50 +0000 (11:36 +0000)
324 files changed:
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
apps/silc/Makefile.am [new file with mode: 0644]
apps/silc/client.c [new file with mode: 0644]
apps/silc/client.h [new file with mode: 0644]
apps/silc/clientconfig.c [new file with mode: 0644]
apps/silc/clientconfig.h [new file with mode: 0644]
apps/silc/clientutil.c [new file with mode: 0644]
apps/silc/clientutil.h [new file with mode: 0644]
apps/silc/command.c [new file with mode: 0644]
apps/silc/command.h [new file with mode: 0644]
apps/silc/command_reply.c [new file with mode: 0644]
apps/silc/command_reply.h [new file with mode: 0644]
apps/silc/idlist.h [new file with mode: 0644]
apps/silc/protocol.c [new file with mode: 0644]
apps/silc/protocol.h [new file with mode: 0644]
apps/silc/pubkey.pub [new file with mode: 0644]
apps/silc/screen.c [new file with mode: 0644]
apps/silc/screen.h [new file with mode: 0644]
apps/silc/silc.c [new file with mode: 0644]
apps/silc/silc.h [new file with mode: 0644]
apps/silc/testi.conf [new file with mode: 0644]
apps/silc/testi2.conf [new file with mode: 0644]
apps/silcd/Makefile.am [new file with mode: 0644]
apps/silcd/command.c [new file with mode: 0644]
apps/silcd/command.h [new file with mode: 0644]
apps/silcd/command_reply.c [new file with mode: 0644]
apps/silcd/command_reply.h [new file with mode: 0644]
apps/silcd/idlist.c [new file with mode: 0644]
apps/silcd/idlist.h [new file with mode: 0644]
apps/silcd/leevi.conf [new file with mode: 0644]
apps/silcd/leevi2.conf [new file with mode: 0644]
apps/silcd/protocol.c [new file with mode: 0644]
apps/silcd/protocol.h [new file with mode: 0644]
apps/silcd/pubkey.pub [new file with mode: 0644]
apps/silcd/route.c [new file with mode: 0644]
apps/silcd/route.h [new file with mode: 0644]
apps/silcd/server.c [new file with mode: 0644]
apps/silcd/server.h [new file with mode: 0644]
apps/silcd/server_internal.h [new file with mode: 0644]
apps/silcd/server_version.c [new file with mode: 0644]
apps/silcd/serverconfig.c [new file with mode: 0644]
apps/silcd/serverconfig.h [new file with mode: 0644]
apps/silcd/serverid.c [new file with mode: 0644]
apps/silcd/serverid.h [new file with mode: 0644]
apps/silcd/silc.conf [new file with mode: 0644]
apps/silcd/silcd.c [new file with mode: 0644]
apps/silcd/silcd.h [new file with mode: 0644]
apps/silcd/testi.conf [new file with mode: 0644]
apps/silcd/testi2.conf [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.sub [new file with mode: 0755]
configure.in [new file with mode: 0644]
doc/CodingStyle [new file with mode: 0644]
doc/FAQ [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/Makefile.in [new file with mode: 0644]
doc/draft-riikonen-silc-ke-auth-00.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-pp-00.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-spec-00.nroff [new file with mode: 0644]
doc/example_silc.conf [new file with mode: 0644]
doc/example_silcd.conf [new file with mode: 0644]
doc/fix.pl [new file with mode: 0755]
doc/makerfc [new file with mode: 0755]
includes/Makefile.am [new file with mode: 0644]
includes/Makefile.in [new file with mode: 0644]
includes/bitmove.h [new file with mode: 0644]
includes/clientincludes.h [new file with mode: 0644]
includes/serverincludes.h [new file with mode: 0644]
includes/silcdefs.h.in [new file with mode: 0644]
includes/silcincludes.h [new file with mode: 0644]
includes/version.h [new file with mode: 0644]
install-sh [new file with mode: 0755]
lib/Makefile.am [new file with mode: 0644]
lib/silccore/Makefile.am [new file with mode: 0644]
lib/silccore/id.c [new file with mode: 0644]
lib/silccore/id.h [new file with mode: 0644]
lib/silccore/idcache.c [new file with mode: 0644]
lib/silccore/idcache.h [new file with mode: 0644]
lib/silccore/silcbuffer.c [new file with mode: 0644]
lib/silccore/silcbuffer.h [new file with mode: 0644]
lib/silccore/silcbuffmt.c [new file with mode: 0644]
lib/silccore/silcbuffmt.h [new file with mode: 0644]
lib/silccore/silcbufutil.c [new file with mode: 0644]
lib/silccore/silcbufutil.h [new file with mode: 0644]
lib/silccore/silcchannel.c [new file with mode: 0644]
lib/silccore/silcchannel.h [new file with mode: 0644]
lib/silccore/silccommand.c [new file with mode: 0644]
lib/silccore/silccommand.h [new file with mode: 0644]
lib/silccore/silcconfig.c [new file with mode: 0644]
lib/silccore/silcconfig.h [new file with mode: 0644]
lib/silccore/silclog.c [new file with mode: 0644]
lib/silccore/silclog.h [new file with mode: 0644]
lib/silccore/silcmemory.c [new file with mode: 0644]
lib/silccore/silcmemory.h [new file with mode: 0644]
lib/silccore/silcnet.c [new file with mode: 0644]
lib/silccore/silcnet.h [new file with mode: 0644]
lib/silccore/silcpacket.c [new file with mode: 0644]
lib/silccore/silcpacket.h [new file with mode: 0644]
lib/silccore/silcprotocol.c [new file with mode: 0644]
lib/silccore/silcprotocol.h [new file with mode: 0644]
lib/silccore/silcschedule.c [new file with mode: 0644]
lib/silccore/silcschedule.h [new file with mode: 0644]
lib/silccore/silcsockconn.c [new file with mode: 0644]
lib/silccore/silcsockconn.h [new file with mode: 0644]
lib/silccore/silctask.c [new file with mode: 0644]
lib/silccore/silctask.h [new file with mode: 0644]
lib/silccore/silcutil.c [new file with mode: 0644]
lib/silccore/silcutil.h [new file with mode: 0644]
lib/silccrypt/Makefile.am [new file with mode: 0644]
lib/silccrypt/blowfish.c [new file with mode: 0644]
lib/silccrypt/blowfish.h [new file with mode: 0644]
lib/silccrypt/blowfish_internal.h [new file with mode: 0644]
lib/silccrypt/cast.c [new file with mode: 0644]
lib/silccrypt/cast.h [new file with mode: 0644]
lib/silccrypt/cast_internal.h [new file with mode: 0644]
lib/silccrypt/ciphers.h [new file with mode: 0644]
lib/silccrypt/ciphers_def.h [new file with mode: 0644]
lib/silccrypt/crypton.c [new file with mode: 0644]
lib/silccrypt/crypton.h [new file with mode: 0644]
lib/silccrypt/crypton_internal.h [new file with mode: 0644]
lib/silccrypt/dfc.c [new file with mode: 0644]
lib/silccrypt/dfc.h [new file with mode: 0644]
lib/silccrypt/dfc_internal.h [new file with mode: 0644]
lib/silccrypt/e2.c [new file with mode: 0644]
lib/silccrypt/e2.h [new file with mode: 0644]
lib/silccrypt/e2_internal.h [new file with mode: 0644]
lib/silccrypt/loki.c [new file with mode: 0644]
lib/silccrypt/loki.h [new file with mode: 0644]
lib/silccrypt/loki_internal.h [new file with mode: 0644]
lib/silccrypt/mars.c [new file with mode: 0644]
lib/silccrypt/mars.h [new file with mode: 0644]
lib/silccrypt/mars_internal.h [new file with mode: 0644]
lib/silccrypt/md5.c [new file with mode: 0644]
lib/silccrypt/md5.h [new file with mode: 0644]
lib/silccrypt/md5_internal.h [new file with mode: 0644]
lib/silccrypt/none.c [new file with mode: 0644]
lib/silccrypt/none.h [new file with mode: 0644]
lib/silccrypt/rc5.c [new file with mode: 0644]
lib/silccrypt/rc5.h [new file with mode: 0644]
lib/silccrypt/rc5_internal.h [new file with mode: 0644]
lib/silccrypt/rc6.c [new file with mode: 0644]
lib/silccrypt/rc6.h [new file with mode: 0644]
lib/silccrypt/rc6_internal.h [new file with mode: 0644]
lib/silccrypt/rijndael.c [new file with mode: 0644]
lib/silccrypt/rijndael.h [new file with mode: 0644]
lib/silccrypt/rijndael_internal.h [new file with mode: 0644]
lib/silccrypt/rsa.c [new file with mode: 0644]
lib/silccrypt/rsa.h [new file with mode: 0644]
lib/silccrypt/rsa_internal.h [new file with mode: 0644]
lib/silccrypt/safer.c [new file with mode: 0644]
lib/silccrypt/safer.h [new file with mode: 0644]
lib/silccrypt/safer_internal.h [new file with mode: 0644]
lib/silccrypt/serpent.c [new file with mode: 0644]
lib/silccrypt/serpent.h [new file with mode: 0644]
lib/silccrypt/serpent_internal.h [new file with mode: 0644]
lib/silccrypt/sha1.c [new file with mode: 0644]
lib/silccrypt/sha1.h [new file with mode: 0644]
lib/silccrypt/sha1_internal.h [new file with mode: 0644]
lib/silccrypt/silccipher.c [new file with mode: 0644]
lib/silccrypt/silccipher.h [new file with mode: 0644]
lib/silccrypt/silchash.c [new file with mode: 0644]
lib/silccrypt/silchash.h [new file with mode: 0644]
lib/silccrypt/silchmac.c [new file with mode: 0644]
lib/silccrypt/silchmac.h [new file with mode: 0644]
lib/silccrypt/silcpkcs.c [new file with mode: 0644]
lib/silccrypt/silcpkcs.h [new file with mode: 0644]
lib/silccrypt/silcrng.c [new file with mode: 0644]
lib/silccrypt/silcrng.h [new file with mode: 0644]
lib/silccrypt/tests/inst [new file with mode: 0644]
lib/silccrypt/tests/inst_rsa [new file with mode: 0644]
lib/silccrypt/tests/inst_twofish [new file with mode: 0644]
lib/silccrypt/tests/insth [new file with mode: 0644]
lib/silccrypt/tests/test_mars.c [new file with mode: 0644]
lib/silccrypt/tests/test_rijndael.c [new file with mode: 0644]
lib/silccrypt/tests/test_rsa.c [new file with mode: 0644]
lib/silccrypt/tests/test_speed.c [new file with mode: 0644]
lib/silccrypt/tests/test_twofish.c [new file with mode: 0644]
lib/silccrypt/twofish.c [new file with mode: 0644]
lib/silccrypt/twofish.h [new file with mode: 0644]
lib/silccrypt/twofish_internal.h [new file with mode: 0644]
lib/silcmath/Makefile.am [new file with mode: 0644]
lib/silcmath/modinv.c [new file with mode: 0644]
lib/silcmath/modinv.h [new file with mode: 0644]
lib/silcmath/silcmp.h [new file with mode: 0644]
lib/silcmath/silcprimegen.c [new file with mode: 0644]
lib/silcmath/silcprimegen.h [new file with mode: 0644]
lib/silcsim/Makefile.am [new file with mode: 0644]
lib/silcsim/modules/Makefile.am [new file with mode: 0644]
lib/silcsim/modules/Makefile.in [new file with mode: 0644]
lib/silcsim/silcsim.c [new file with mode: 0644]
lib/silcsim/silcsim.h [new file with mode: 0644]
lib/silcsim/silcsimutil.c [new file with mode: 0644]
lib/silcsim/silcsimutil.h [new file with mode: 0644]
lib/silcske/Makefile.am [new file with mode: 0644]
lib/silcske/groups.c [new file with mode: 0644]
lib/silcske/groups.h [new file with mode: 0644]
lib/silcske/groups_internal.h [new file with mode: 0644]
lib/silcske/payload.c [new file with mode: 0644]
lib/silcske/payload.h [new file with mode: 0644]
lib/silcske/payload_internal.h [new file with mode: 0644]
lib/silcske/silcske.c [new file with mode: 0644]
lib/silcske/silcske.h [new file with mode: 0644]
lib/silcske/silcske_status.h [new file with mode: 0644]
lib/zlib/ChangeLog [new file with mode: 0644]
lib/zlib/FAQ [new file with mode: 0644]
lib/zlib/INDEX [new file with mode: 0644]
lib/zlib/Make_vms.com [new file with mode: 0644]
lib/zlib/Makefile [new file with mode: 0644]
lib/zlib/Makefile.in [new file with mode: 0644]
lib/zlib/Makefile.riscos [new file with mode: 0644]
lib/zlib/README [new file with mode: 0644]
lib/zlib/adler32.c [new file with mode: 0644]
lib/zlib/algorithm.txt [new file with mode: 0644]
lib/zlib/amiga/Makefile.pup [new file with mode: 0644]
lib/zlib/amiga/Makefile.sas [new file with mode: 0644]
lib/zlib/compress.c [new file with mode: 0644]
lib/zlib/configure [new file with mode: 0755]
lib/zlib/contrib/README.contrib [new file with mode: 0644]
lib/zlib/contrib/asm386/gvmat32.asm [new file with mode: 0644]
lib/zlib/contrib/asm386/gvmat32c.c [new file with mode: 0644]
lib/zlib/contrib/asm386/mkgvmt32.bat [new file with mode: 0644]
lib/zlib/contrib/asm386/zlibvc.def [new file with mode: 0644]
lib/zlib/contrib/asm386/zlibvc.dsp [new file with mode: 0644]
lib/zlib/contrib/asm386/zlibvc.dsw [new file with mode: 0644]
lib/zlib/contrib/asm586/README.586 [new file with mode: 0644]
lib/zlib/contrib/asm586/match.S [new file with mode: 0644]
lib/zlib/contrib/asm686/README.686 [new file with mode: 0644]
lib/zlib/contrib/asm686/match.S [new file with mode: 0644]
lib/zlib/contrib/delphi/zlib.mak [new file with mode: 0644]
lib/zlib/contrib/delphi/zlibdef.pas [new file with mode: 0644]
lib/zlib/contrib/delphi2/d_zlib.bpr [new file with mode: 0644]
lib/zlib/contrib/delphi2/d_zlib.cpp [new file with mode: 0644]
lib/zlib/contrib/delphi2/readme.txt [new file with mode: 0644]
lib/zlib/contrib/delphi2/zlib.bpg [new file with mode: 0644]
lib/zlib/contrib/delphi2/zlib.bpr [new file with mode: 0644]
lib/zlib/contrib/delphi2/zlib.cpp [new file with mode: 0644]
lib/zlib/contrib/delphi2/zlib.pas [new file with mode: 0644]
lib/zlib/contrib/delphi2/zlib32.bpr [new file with mode: 0644]
lib/zlib/contrib/delphi2/zlib32.cpp [new file with mode: 0644]
lib/zlib/contrib/iostream/test.cpp [new file with mode: 0644]
lib/zlib/contrib/iostream/zfstream.cpp [new file with mode: 0644]
lib/zlib/contrib/iostream/zfstream.h [new file with mode: 0644]
lib/zlib/contrib/iostream2/zstream.h [new file with mode: 0644]
lib/zlib/contrib/iostream2/zstream_test.cpp [new file with mode: 0644]
lib/zlib/contrib/minizip/ChangeLogUnzip [new file with mode: 0644]
lib/zlib/contrib/minizip/Makefile [new file with mode: 0644]
lib/zlib/contrib/minizip/miniunz.c [new file with mode: 0644]
lib/zlib/contrib/minizip/minizip.c [new file with mode: 0644]
lib/zlib/contrib/minizip/readme.txt [new file with mode: 0644]
lib/zlib/contrib/minizip/unzip.c [new file with mode: 0644]
lib/zlib/contrib/minizip/unzip.def [new file with mode: 0644]
lib/zlib/contrib/minizip/unzip.h [new file with mode: 0644]
lib/zlib/contrib/minizip/zip.c [new file with mode: 0644]
lib/zlib/contrib/minizip/zip.def [new file with mode: 0644]
lib/zlib/contrib/minizip/zip.h [new file with mode: 0644]
lib/zlib/contrib/minizip/zlibvc.def [new file with mode: 0644]
lib/zlib/contrib/minizip/zlibvc.dsp [new file with mode: 0644]
lib/zlib/contrib/minizip/zlibvc.dsw [new file with mode: 0644]
lib/zlib/contrib/untgz/Makefile [new file with mode: 0644]
lib/zlib/contrib/untgz/makefile.w32 [new file with mode: 0644]
lib/zlib/contrib/untgz/untgz.c [new file with mode: 0644]
lib/zlib/contrib/visual-basic.txt [new file with mode: 0644]
lib/zlib/crc32.c [new file with mode: 0644]
lib/zlib/deflate.c [new file with mode: 0644]
lib/zlib/deflate.h [new file with mode: 0644]
lib/zlib/descrip.mms [new file with mode: 0644]
lib/zlib/example.c [new file with mode: 0644]
lib/zlib/gzio.c [new file with mode: 0644]
lib/zlib/infblock.c [new file with mode: 0644]
lib/zlib/infblock.h [new file with mode: 0644]
lib/zlib/infcodes.c [new file with mode: 0644]
lib/zlib/infcodes.h [new file with mode: 0644]
lib/zlib/inffast.c [new file with mode: 0644]
lib/zlib/inffast.h [new file with mode: 0644]
lib/zlib/inffixed.h [new file with mode: 0644]
lib/zlib/inflate.c [new file with mode: 0644]
lib/zlib/inftrees.c [new file with mode: 0644]
lib/zlib/inftrees.h [new file with mode: 0644]
lib/zlib/infutil.c [new file with mode: 0644]
lib/zlib/infutil.h [new file with mode: 0644]
lib/zlib/maketree.c [new file with mode: 0644]
lib/zlib/minigzip.c [new file with mode: 0644]
lib/zlib/msdos/Makefile.b32 [new file with mode: 0644]
lib/zlib/msdos/Makefile.bor [new file with mode: 0644]
lib/zlib/msdos/Makefile.dj2 [new file with mode: 0644]
lib/zlib/msdos/Makefile.emx [new file with mode: 0644]
lib/zlib/msdos/Makefile.msc [new file with mode: 0644]
lib/zlib/msdos/Makefile.tc [new file with mode: 0644]
lib/zlib/msdos/Makefile.w32 [new file with mode: 0644]
lib/zlib/msdos/Makefile.wat [new file with mode: 0644]
lib/zlib/msdos/zlib.def [new file with mode: 0644]
lib/zlib/msdos/zlib.rc [new file with mode: 0644]
lib/zlib/nt/Makefile.emx [new file with mode: 0644]
lib/zlib/nt/Makefile.gcc [new file with mode: 0644]
lib/zlib/nt/Makefile.nt [new file with mode: 0644]
lib/zlib/nt/zlib.dnt [new file with mode: 0644]
lib/zlib/os2/Makefile.os2 [new file with mode: 0644]
lib/zlib/os2/zlib.def [new file with mode: 0644]
lib/zlib/trees.c [new file with mode: 0644]
lib/zlib/trees.h [new file with mode: 0644]
lib/zlib/uncompr.c [new file with mode: 0644]
lib/zlib/zconf.h [new file with mode: 0644]
lib/zlib/zlib.3 [new file with mode: 0644]
lib/zlib/zlib.h [new file with mode: 0644]
lib/zlib/ztest2188.c [new file with mode: 0644]
lib/zlib/ztest30104.c [new file with mode: 0644]
lib/zlib/zutil.c [new file with mode: 0644]
lib/zlib/zutil.h [new file with mode: 0644]
missing [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
prepare [new file with mode: 0755]
prepare-clean [new file with mode: 0755]
public_html/about.html [new file with mode: 0644]
public_html/copying.html [new file with mode: 0644]
public_html/features.html [new file with mode: 0644]
public_html/history.html [new file with mode: 0644]
public_html/index.html [new file with mode: 0644]
public_html/silc.jpg [new file with mode: 0644]
public_html/silc2.jpg [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..c2d5f4b
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,23 @@
+Installing SILC Developer's Version
+===================================
+
+./configure
+./make
+
+You should not install the SILC into your system, instead, you should
+run it from the current directory.
+
+To see different compilation options, give,
+
+./configure --help
+
+
+Generally, developers wants to compile with debugging, in this case,
+give,
+
+./configure --enable-debug
+
+WARNING: The debugging is very very heavy and you currently cannot turn
+it off if you have compiled it with this option.  However, if you're
+going to develop or debug SILC you whould compile with this option.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..f0436ab
--- /dev/null
@@ -0,0 +1,21 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+SUBDIRS = lib silcd silc doc includes
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1953d94
--- /dev/null
+++ b/README
@@ -0,0 +1,131 @@
+SILC - Secure Internet Live Conferencing
+========================================
+
+[NOTE: SILC is still in middle of development and this package is known
+as Developer's Version which means that the package is in no means stable
+or ready to be in production use.  This package is for those who wants
+to test SILC, find bugs and maybe contribute some time and code for the
+SILC project.  There is no guarantees that this package even compiles and
+even if it compiles there is no guarantees that it would work, and even
+if it works there is no guarantees that it would work correctly, and even
+if it seems to work correctly it may be just plain luck.]
+
+
+Description
+===========
+
+SILC (Secure Internet Live Conferencing) is a protocol which provides
+secure conferencing services in the Internet over insecure channel.
+SILC is IRC like softwarre although internally they are very different.
+Biggest similiarity between SILC and IRC is that they both provide
+conferencing services and that SILC has almost same commands as IRC.  Other
+than that they are nothing alike.  Biggest differences are that SILC is 
+secure what IRC is not in any way.  The network model is also entirely
+different compared to IRC.
+
+
+Features
+========
+
+Features to be included into the final release of SILC.  [Note that the
+current Developer's Version does not include all of these features, read
+TODO file for more information.]
+
+ o Normal conferencing services such as private messages, channels,
+   channel messages, etc.  All traffic is secured and authenticated.
+
+ o No unique nicknames.  There can same nicknames in SILC without
+   collisions.  SILC has unique Client ID's, Server ID's and Channel ID's
+   to assure that there are no collisions.
+
+ o Secure key exchange and authentication protocol.  SILC Key Exchange
+   protocol provides key material used in the SILC sessions in secure
+   manner.  The protocol is immune for example to man-in-the-middle 
+   attacks.  The SILC Authentication protocol provides strong 
+   authentication.  Authentication may be based on passphrase or public
+   key (RSA) authentication.  For clients there is an option not to
+   use authentication when connecting to servers.
+
+ o All traffic is encrypted and authenticated using the best cryptographic
+   algorithms out there.  Command messages, private messages and channel
+   messages are all protected by encryption.  User can set private keys
+   for both private message and for channels so that even SILC servers do
+   not know the keys.  Cipher keys are, by default, 128 bits in length and
+   public keys, by default, 1024 bits in length.
+
+ o Supports data compression with GZIP to improve performance.
+
+ o SIM (SILC Module) support.  Support for loading of shared objects at 
+   run-time that provides new and extended features to both SILC client
+   and server.  These can provide extra ciphers and extra features to
+   the software.
+
+ o SILC client can be installed and used without root privileges.
+
+ o SILC client can be configured by system wide configuration files but
+   with user specific configuration files as well.
+
+
+History
+=======
+
+Even though SILC were just released to the public the idea and the protocol
+itself is quite old.  I got the idea about SILC in its current form in
+the year 1996 and first lines of codes were written in early 1997.  This
+release is now third rewrite of the SILC.  The very first version were
+written in 1997 and it included SILC client and very very preliminary
+SILC server.  The server actually weren't usable but the client looked
+pretty much the same as it does now.  At that time the SILC also included
+RSA implementation and 3DES implementation.  The random number generator
+that exists in this current release is actually based on the RNG written
+in 1997.  The RNG written in 1997, on the other hand, were based on
+the SSH's random number generator.  The RNG has been rewritten twice
+since the first version.
+
+I stopped writing the SILC later in 1997 when I got busy at school and
+in work.  The pause lasted several months.  The development resumed in
+1998 when my friend (Juha Räsänen) and I implemented ElGamal algorithm.
+I rewrote some other parts as well.  However, for the same reasons as
+previously the development stopped again.  I resumed the development
+later in 1998 by doing rewrite of the SILC in C++.  This was obviously 
+a mistake but at that time it seemed like a good idea.  Again, in the 
+winter 1999 I got very busy writing my thesis and was forced to stop the 
+development again.  I also, started a new job in the spring.
+
+Later, in 1999, I decided that this time I'm going to make it the right
+way.  C++ was obviously a bad choice so I decided to fall back to plain
+C language.  I also decided to do complete rewrite and started doing
+more thorough planning of what the SILC actually should include.  I also
+decided that this time it is going to kill me before I stop the 
+development.  I started writing SILC in the weekends and actually 
+everytime I had some spare time.  I also started a new job but I didn't
+let that get to my way.  The result of this development effort is the
+release now in public.
+
+I've learned a lot by doing the SILC.  I guess, when I started it I wasn't
+that good of a C programmer.  That alone was a reason why SILC hasn't
+seen the day of light before now.  My programming style has also changed 
+dramatically during these years.  Actually, it has changed couple times 
+since this last rewrite as well.  However, the code style of current SILC 
+release is quite consistent (actually the coding style SILC has been 
+written now I've learned in my current job).
+
+There is probably over 85% of new code in this third rewrite.  Rest has 
+just been copied from the old versions and only minor changes has been
+made (like changed function names and overall coding style).  I've 
+preserved the dates of the old files (dating back to 1997) that has 
+existed in some forms in the old versions.  There is a lot of new code but
+already I see a lot that needs rewriting.  The development continues.
+
+
+Contact
+=======
+
+Feedback and comments are welcome.  You can reach me in the following
+Address. 
+
+[Note that generally bug reports should not be sent just yet as the 
+Developer's Version is full of them and the bug hunt has not even started 
+yet.]
+
+                               Pekka Riikonen <priikone@poseidon.pspt.fi>
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..ece615c
--- /dev/null
+++ b/TODO
@@ -0,0 +1,369 @@
+TODO
+====
+
+This is more or less complete list of tasks that has to be done before
+SILC 1.0 could ever be released.  It is clear that the list does not
+include all the bugs that exists.  At the end of list are tasks that 
+needs to be done but are probably post 1.0.
+
+Feel free to contribute if you have the ability and free time - all the
+help is really appreciated - and needed.
+
+                                                       - Pekka
+
+[Latest Note:  The protocol has changed a bit in some parts which 
+causes that the current implementation violates some requirements.
+These are not listed here, currently.]
+
+
+New features TODO
+=================
+
+ o Extended SIM (SILC Module) support.  Currently only SILC Cipher API
+   and SILC Hash API may be used as SIM's.  What I have in mind is to
+   have extended support for SIM's so that basically any SILC API could
+   be used as SIM's.  This would open tremendous possiblities but
+   opens also issues on security that needs to be dealt with.
+
+   Some sort of SIM compilation environment should be defined so that
+   the SIM's could use SILC specific symbols from the modules (which they
+   cannot do currently).  In the future modules could add new features
+   to SILC easily with this support.  I'm more thinking this from client's
+   perspective to add new features to client (such as IRC support as SIM)
+   but server should have the support as well.  Anyhow, this is an 
+   interesting feature...
+
+   This maybe post 1.0 task - dunno.
+
+ o SIM support for other platforms than just for Linux.  Apache has
+   example code (code that we could use directly pretty easily) for
+   other platforms.
+
+ o We should replace all short, int, long, unsigned short, unsigned int,
+   unsigned long with some pre-defined datatypes that really are what
+   we want on all platforms.  int16, uint16, int32, uint32 etc. are
+   what we could use or maybe SilcInt16, SilcUInt16 etc.  Also, boolean
+   datatype should be defined.
+
+ o More platform supports should be added.  The code is pretty much
+   generic but there are some parts that require porting (SIM).  Also, 
+   some support for different platforms is needed into configure.in.
+
+ o SILC requires currently GCC to work because we use GCC specific 
+   compilation options.  Generally any compiler that supports inline
+   functions and can build shared libraries (for SIMs) should work.  
+   These cases should be included into configure.in.
+
+
+TODO In SILC Client
+===================
+
+ o Implement all commands.  A lot of commands are still yet to be
+   implemented.  Most of them are trivial but some will require some
+   planning.  Go see the command.c for unimplemented commands.
+
+ o Non-blocking connection on the background must be stopped if some
+   other connection on same window has established.  Now it is possible
+   that some non-blocking connection timeouts on the background when
+   we already have a working connection to some other place; things
+   goes bad.
+
+ o Finish WHOIS, finish JOIN and other commands that are partly
+   implemented.
+
+ o Input line on UI is buggy.  Cursor movement etc bugs.  Too lazy to
+   fix it.
+
+ o Logic for handling multiple same nicknames for example in private
+   message sending.  I guess the logic is done in server side but is
+   missing from client.
+
+ o Private message key setting is missing and must be implemented.
+   Currently private messages are encrypted with session keys.  This
+   is required by the protocol.
+
+ o Channel private key setting is missing and must be implemented.
+   Currently there cannot be private keys for channels.  Normal channel
+   keys (generated by server) are used.  This is required by the protocol.
+
+ o Public and private key generation is now done everytime the program
+   is run.  Now, this is only for testing period as I've been lazy to
+   do it any better for now.  This must be fixed.
+
+ o I guess, public key authentication (when connecting to a server)
+   is not working currently.  It is just matter of loading the keys
+   from file and using them (see corresponding code in server, it should
+   support public key authentication already).
+
+ o Multiple windows support.  Basic support for multiple windows already
+   exists but a lot is still missing to get it working.  Also, some
+   of the existing stuff probably needs to be tweaked a bit before the
+   multiple windows support could be done.  And of course the actual
+   commands that control the windows needs to be written (/WINDDOW).
+
+ o Implement /KEYMAP (or similiar) command to remap control and function
+   keys.
+
+ o Implement /ALIAS command to make command aliases.
+
+ o Implement /set/if/do/while etc as in IRC2.  Maybe post 1.0 task.
+   Some scripting would be good.
+
+ o Connection Authentication request resolving is missing and must be
+   done.  This is required by the protocol.
+
+ o Key Exchange protocol's responder side is missing from client.  
+   Generally it is possible for the client to be responder so it should
+   be implemented (See corresponding code from server).  Error handling
+   in the KE protocol is also in pretty bad shape in client.
+
+ o Configuration file loading from global and from local dirs.  This
+   is currently missing and I guess the global is only used.  Old SILC
+   version (in 1997) had ~./silc directory that I guess should be done
+   now as well.  The code for handling those exists but not in current
+   source tree.
+
+ o Configuration file format - could be better.
+
+ o Write help files for commands.  Nice format for the help files should
+   be selected.  I'm open for ideas.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+   Also, return values from various allocations and functions needs to
+   checked.
+
+
+TODO In SILC Server
+===================
+
+ o Implement all commands on server side.  A lot of commands are still yet
+   to be implemented.  Most of them are trivial but some will require some
+   planning.  Go see the command.c for unimplemented commands.
+
+ o DNS/IP lookup blocks the server.  This must be fixed.  Check the
+   resolver stuff (resolver(3), resolver(5)).  Either we have to do the
+   own resolver stuff (through scheduler, if possible without writing
+   too much own stuff) or use threads.
+
+ o Lenght of the packet processing timeouts needs to be checked whether
+   they are too short or too long.  I haven't really tested whether they
+   are suitable.  They should be tested on high load which I haven't done
+   at all yet.
+
+ o Public and private key generation is now done everytime the program
+   is run.  Now, this is only for testing period as I've been lazy to
+   do it any better for now.  This must be fixed.
+
+ o Server says that it is able to listen on multiple ports but currently
+   that is bogus.  It can, but internals are for single server.
+
+ o Command lagging must implemented.  Those commands (all currently) that
+   has the LAG flag set they must not be allowed to be executed more than
+   once, say, in 2 seconds.
+
+ o Command flag usage in general is not implemented yet.
+
+ o Client history must be implemented.  Protocol says that server must
+   keep history information about clients for some period of time.
+
+ o Channel flags and user modes on channels are not implemented yet as
+   /MODE command is not implemented yet in client and server.
+
+ o Protocol execution timeouts are hard coded, should be configurable.
+
+ o Channel message sending routines uses a lot of common code.  Should
+   create a common function for those instead of writing the same code
+   again everytime, as done now.
+
+ o serverutil.c I guess should be created for util-like functions that
+   now resides in server.c, which is getting too big.
+
+ o serverconfig.c and the function naming in it is inconsistent.  It is 
+   not silc_config_server* it should be silc_server_config*.  As should
+   all the SilcConfigServer* types be SilcServerConfig*.
+
+ o Implement DENY_CONNECTION section in serverconfig.c and in server.
+
+ o Implement REDIRECT_CLIENT section in serverconfig.c and in server.
+
+ o Configuration file format - could be better.
+
+ o IP address fields in configuration file should accept mask format
+   as well, IP/MASK, and not just plain IP.
+
+ o Connection classes should be actually implemented in serverconfig.c.
+   They can be defined but they are totally ignored currently.
+
+ o Acceptance of incoming connections (client and server connections)
+   should be checked before key exchange protocol.  Currently it is
+   checked at the authentication phase after KE, that is ok, but it should
+   be checked before starting KE, as well.
+
+ o Statistics are totally missing from the server.  It would be nice
+   to gather some statistics.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+   Also, return values from various allocations and functions needs to
+   checked.
+
+
+TODO In SILC Libraries
+======================
+
+ o Public key verification in SKE (SILC Key Exchange) protocol is missing,
+   thus currently we trust on all public keys.  This probably doesn't cause
+   bad problems but the mechanism of verifying it from local database
+   (from files) needs to be done (it can open man-in-the-middle-attacks).
+
+ o Implement PFS (Perfect Forward Secrecy) flag in SKE (and in client and
+   server, actually).  If PFS is set, re-key must cause new key exchange.
+   This is required by the SILC protocol.
+
+ o Re-key in general is actually missing (from everywhere) and must be done.
+
+ o SKE does not send correct status types.  Types are defined but not
+   sent.
+
+ o Connection authentication protocol does not send correct status types.
+   These types are not defined currently at all.
+
+ o PKCS#1 style RSA public key encryption/decryption/sign/verify is 
+   missing, and should be added for interoperability reasons.  The thing 
+   I've done now is bad and should be removed as soon as possible (or 
+   the protocol should then state the method of how they should be done).
+
+ o SILC public key file type is bad.  I'd like to see PEM encoded files.
+   I have public domain code for base64 encoding but it needs to be 
+   rewritten.
+
+ o Slow ciphers should be removed.  I think we don't need more than
+   the AES finalists plus blowfish and RC5.
+
+ o These slow ciphers actually don't work currently as I've tested
+   only the ones that are worth testing.  The CBC mode on these slow
+   ciphers probably don't work.  No need to worry, these ciphers should
+   be removed.
+
+ o Scheduler needs to be analyzed on high load as it might be unfair
+   towards select() because it may run timeout tasks before select() and
+   after select().  If it is found to be unfair the timeout task running
+   before select() should probably be removed.
+
+ o On select() issue; maybe we should use poll() instead if it is
+   available? poll() doesn't have max fd limit...
+
+ o SIM support for SILC PKCS API needs to made so that they could be
+   used as SIM's.  At the same time some work is required on prime
+   generation as the way it is done now sucks.  Read from code for
+   more (silcpkcs.h).
+
+ o Compression routines are missing.  The protocol supports packet
+   compression thus it must be implemented.  SILC Comp API must be
+   defined.  zlib package is already included into the lib dir (in CVS,
+   not in distribution), but it is not used yet, and it requires some
+   tweaking on the Makefiles (we want static lib not shared).
+
+ o Cipher API needs to be made more consistent.  Some parts of the
+   code generated with current Cipher API looks really bad.  Same
+   is with PKCS API, even worse actually.  They need to be made
+   cleaner.  Introducing silc_cipher_encrypt/decrypt/set_key etc.
+   functions (I actually don't understand why have I left these un-done).
+
+ o Scheduler should automatically allocate task queues if NULL pointers 
+   are passed to the silc_schedule_init.  Would make initialization 
+   cleaner.
+
+ o Packet processing routines in client and server are actually pretty
+   much generic and should be moved from the client/server to the library
+   as generic routines (silc_<client/server>_packet_decrypt_rest* etc).
+   This requires heavy changes to the client and server.
+
+ o Random Number Generator needs some tweaking.  Reading /dev/random may
+   block resulting slow initialization of RNG.  Some other things in the
+   RNG may block as well.  Also, I have some pending changes to the RNG 
+   that needs to be commited (from Schneier's Yarrow-160 paper).  They 
+   should make the RNG even better.
+
+ o Logging should be made more generic in a way that application can
+   set to where the logging is destined to.  Now, it is always destined
+   to stdout (or stderr) which is a bad thing for client.  Ie. some
+   sort of logging registration functions or similiar should be done
+   (silclog.[ch] in core).  The actual output of logs should be done
+   by callback function in the application not in lib.
+
+ o I don't like the ID cache system currenly implemented.  Ugly and
+   not so good.  Must be rewritten very soon.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+
+ o There are also checks missing from allocations whether the allocation
+   returns valid memory or NULL.  These are missing in library as well
+   in client and server.  Either all checks has to be added or we will
+   have to make sure that silc_*alloc()s always return valid memory
+   and assert()s if the system's memory allocator (*alloc()) fails.
+
+ o silc_buffer_[un]format() needs to be made more stable as it may
+   crash the SILC if malformed data is sent as argument.  There are a
+   lot of places in client and server where we trust directly data coming
+   from network and try to unformat it.  The unformatting routine needs
+   to be able handle situations where data sent is malformed, by mistake
+   or intentionally.  This is important as it is easy to crash the SILC
+   now by just sending malformed data.  Also, in client and server we
+   must start checking the return value from silc_buffer_[un]format.
+
+
+Other Things TODO
+=================
+
+ o Write manuals for server.
+
+ o Write manuals for client.
+
+ o Write SILC Library Reference manual.  This would include all the SILC
+   API's with simple examples how the functions are to be used.  This is
+   pretty easy to create by taking all the functions plus their comments
+   from source/header files.  However, same sort of reference manual 
+   should be written for client and server as well.
+
+
+TODO After 1.0
+==============
+
+ o Pthreads support.  A lot of problems are solved with server (and with
+   client as well) if we add pthread support.  We can forget things such
+   as non-blocking connecting etc, and we can do things such as DNS/IP
+   lookups async.  The server itself also benefits great deal from 
+   threads, especially from performance point of view.
+
+   But, this is not a small task and almost entire SILC Library has to
+   be made re-entrant.  Own API is probably added for the threads support
+   to make changes in the future as painless as possible.  So the API 
+   would have things like silc_mutex_lock, silc_mutex_unlock and 
+   friends...
+
+ o X.509 certificate support.  SILC protocol supports certificates and
+   it would be great to have support for them.  This is a big task as
+   support has to be made for ASN.1 as well.  I've looked into OpenSSL 
+   package as it has X.509 certificate support (and ASN.1 as well).  
+   The code does not look very good to my eye but it has some potentials.
+   This should be looked at more closely.
+
+   Naturally own SILC Certificate API has to be defined regardles what
+   the actual X.509 library is (OpenSSL X.509 or something else).  Other
+   choice is to write own X.509 library but I'm not going to do it - 
+   I can help to migrate the OpenSSL X.509 into SILC and I can help if 
+   someone would like to write the X.509 library - but I'm not going 
+   to start writing one myself.  Anyhow, the OpenSSL X.509 lib should
+   be checked.
+
+ o SSH2 public keys support.  Maybe - not really needed but could be
+   nice as SSH is widely used all over the place.  SILC Protocol 
+   supports SSH2 public keys.
+
+ o IRC support for SILC client.  This would be nice to have on client
+   as it could be used to connect to SILC and IRC.  People wouldn't
+   have to have two different clients when same would work on both.
+   I'd like to see this done as SIM, after the extended SIM support
+   has been added to SILC.
+
+ o Cipher optimizations (asm, that this) at least for i386 would be nice.
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..65e1903
--- /dev/null
@@ -0,0 +1,16 @@
+/* Name of the package. */
+#undef PACKAGE
+
+/* Version of the package. */
+#undef VERSION
+
+/* Debugging */
+#undef SILC_DEBUG
+
+/* Default configuration file */
+#undef SILC_SERVER_CONFIG_FILE
+
+/* SIM (SILC Module) support */
+#undef SILC_SIM
+#undef HAVE_RTLD_NOW
+#undef HAVE_RTLD_LAZY
diff --git a/apps/silc/Makefile.am b/apps/silc/Makefile.am
new file mode 100644 (file)
index 0000000..1b358e6
--- /dev/null
@@ -0,0 +1,40 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = silc
+
+silc_SOURCES = \
+       silc.c \
+       client.c \
+       command.c \
+       command_reply.c \
+       clientconfig.c \
+       clientutil.c \
+       protocol.c \
+       screen.c
+
+LDADD = -L. -L.. -L../lib -lsilc -lcurses
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
+       -I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
+       -I../includes \
+       -I../lib/silcmath/gmp-3.0.1
diff --git a/apps/silc/client.c b/apps/silc/client.c
new file mode 100644 (file)
index 0000000..80e2784
--- /dev/null
@@ -0,0 +1,2371 @@
+/*
+
+  client.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Static function prototypes */
+static int silc_client_bad_keys(unsigned char key);
+static void silc_client_process_message(SilcClient client);
+static char *silc_client_parse_command(unsigned char *buffer);
+
+/* Static task callback prototypes */
+SILC_TASK_CALLBACK(silc_client_update_clock);
+SILC_TASK_CALLBACK(silc_client_run_commands);
+SILC_TASK_CALLBACK(silc_client_process_key_press);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
+SILC_TASK_CALLBACK(silc_client_packet_process);
+SILC_TASK_CALLBACK(silc_client_packet_parse);
+
+SilcClientWindow silc_client_create_main_window(SilcClient client);
+SilcClientWindow silc_client_add_window(SilcClient client,
+                                       int is_current);
+void silc_client_packet_parse_type(SilcClient client, 
+                                  SilcSocketConnection sock,
+                                  SilcPacketContext *packet);
+void silc_client_private_message_process(SilcClient client,
+                                        SilcSocketConnection sock,
+                                        SilcPacketContext *packet);
+
+/* Definitions from version.h */
+extern char *silc_version;
+extern char *silc_name;
+extern char *silc_fullname;
+
+/* Allocates new client object. This has to be done before client may
+   work. After calling this one must call silc_client_init to initialize
+   the client. */
+
+int silc_client_alloc(SilcClient *new_client)
+{
+
+  *new_client = silc_calloc(1, sizeof(**new_client));
+  if (*new_client == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new client object"));
+    return FALSE;
+  }
+
+  (*new_client)->input_buffer = NULL;
+  (*new_client)->screen = NULL;
+  (*new_client)->windows = NULL;
+  (*new_client)->windows_count = 0;
+  (*new_client)->current_win = NULL;
+
+  return TRUE;
+}
+
+/* Free's client object */
+
+void silc_client_free(SilcClient client)
+{
+  if (client) {
+    silc_free(client);
+  }
+}
+
+/* Initializes the client. This makes all the necessary steps to make
+   the client ready to be run. One must call silc_client_run to run the
+   client. */
+
+int silc_client_init(SilcClient client)
+{
+
+  SILC_LOG_DEBUG(("Initializing client"));
+  assert(client);
+
+  client->username = silc_get_username();
+  client->realname = silc_get_real_name();
+
+  /* Register all configured ciphers, PKCS and hash functions. */
+  client->config->client = (void *)client;
+  silc_client_config_register_ciphers(client->config);
+  silc_client_config_register_pkcs(client->config);
+  silc_client_config_register_hashfuncs(client->config);
+
+  /* Initialize hash functions for client to use */
+  silc_hash_alloc("md5", &client->md5hash);
+  silc_hash_alloc("sha1", &client->sha1hash);
+
+  /* Initialize none cipher */
+  silc_cipher_alloc("none", &client->none_cipher);
+
+  /* Initialize random number generator */
+  client->rng = silc_rng_alloc();
+  silc_rng_init(client->rng);
+  silc_math_primegen_init(); /* XXX */
+
+#if 0
+  {
+    SilcCipher twofish;
+    unsigned char *src, *dst, *dec;
+    SilcBuffer packet;
+    int payload_len;
+
+    payload_len = 4 + strlen("pekka riikonen");
+    packet = silc_buffer_alloc(payload_len);
+    silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+    silc_buffer_format(packet,
+                      SILC_STR_UI_SHORT(payload_len),
+                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+                      SILC_STR_UI_XNSTRING("pekka riikonen", 
+                                           strlen("pekka riikonen")),
+                      SILC_STR_END);
+
+    silc_cipher_alloc("twofish", &twofish);
+    twofish->cipher->set_key(twofish->context, "1234567890123456", 16);
+    twofish->set_iv(twofish, "6543210987654321");
+    SILC_LOG_HEXDUMP(("source: len %d", packet->len), 
+                    packet->data, packet->len );
+    silc_packet_encrypt(twofish, packet, packet->len);
+    SILC_LOG_HEXDUMP(("encrypted"), packet->data, packet->len);
+    silc_packet_decrypt(twofish, packet, packet->len);
+    SILC_LOG_HEXDUMP(("decrypted"), packet->data, packet->len);
+
+  }
+
+  {
+    SilcCipher cipher1, cipher2;
+    unsigned char *src, *dst, *dec;
+    int len = strlen("12345678901234561234567890123456123456789012345612345678901234561234567890123456");
+
+    src = silc_calloc(len + 1, sizeof(unsigned char));
+    dst = silc_calloc(len + 1, sizeof(unsigned char));
+    dec = silc_calloc(len + 1, sizeof(unsigned char));
+
+    memcpy(src, "12345678901234561234567890123456123456789012345612345678901234561234567890123456", len);
+    
+    silc_cipher_alloc("twofish", &cipher1);
+    cipher1->cipher->set_key(cipher1->context, "1234567890123456", 128);
+    cipher1->set_iv(cipher1, "6543210987654321");
+
+    silc_cipher_alloc("twofish", &cipher2);
+    cipher2->cipher->set_key(cipher2->context, "1234567890123456", 128);
+    cipher2->set_iv(cipher2, "6543210987654321");
+
+    SILC_LOG_HEXDUMP(("source: %d", len), src, len);
+    cipher1->cipher->encrypt(cipher1->context, src, src, len, cipher1->iv);
+    SILC_LOG_HEXDUMP(("encrypted"), src, len);
+    cipher2->set_iv(cipher2, "6543210987654321");
+    cipher2->cipher->decrypt(cipher2->context, src, src, len, cipher2->iv);
+    SILC_LOG_HEXDUMP(("decrypted"), src, len);
+
+  }
+#endif
+
+  /* Register the task queues. In SILC we have by default three task queues. 
+     One task queue for non-timeout tasks which perform different kind of 
+     I/O on file descriptors, timeout task queue for timeout tasks, and,
+     generic non-timeout task queue whose tasks apply to all connections. */
+  silc_task_queue_alloc(&client->io_queue, TRUE);
+  if (!client->io_queue) {
+    goto err0;
+  }
+  silc_task_queue_alloc(&client->timeout_queue, TRUE);
+  if (!client->timeout_queue) {
+    goto err1;
+  }
+  silc_task_queue_alloc(&client->generic_queue, TRUE);
+  if (!client->generic_queue) {
+    goto err1;
+  }
+
+  /* Initialize the scheduler */
+  silc_schedule_init(client->io_queue, client->timeout_queue, 
+                    client->generic_queue, 5000);
+
+  /* Register the main task that is used in client. This received
+     the key pressings. */
+  if (silc_task_register(client->io_queue, fileno(stdin), 
+                        silc_client_process_key_press,
+                        (void *)client, 0, 0, 
+                        SILC_TASK_FD,
+                        SILC_TASK_PRI_NORMAL) == NULL) {
+    goto err2;
+  }
+
+  /* Register timeout task that updates clock every minute. */
+  if (silc_task_register(client->timeout_queue, 0,
+                        silc_client_update_clock,
+                        (void *)client, 
+                        silc_client_time_til_next_min(), 0,
+                        SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_LOW) == NULL) {
+    goto err2;
+  }
+
+  if (client->config->commands) {
+    /* Run user configured commands with timeout */
+    if (silc_task_register(client->timeout_queue, 0,
+                          silc_client_run_commands,
+                          (void *)client, 0, 1,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW) == NULL) {
+      goto err2;
+    }
+  }
+
+  /* Allocate the input buffer used to save typed characters */
+  client->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE);
+  silc_buffer_pull_tail(client->input_buffer, 
+                       SILC_BUFFER_END(client->input_buffer));
+
+  /* Initialize the screen */
+  client->screen = silc_screen_init();
+  silc_client_create_main_window(client);
+  client->screen->input_buffer = client->input_buffer->data;
+  silc_screen_print_coordinates(client->screen, 0);
+
+  return TRUE;
+
+ err0:
+  silc_task_queue_free(client->timeout_queue);
+ err1:
+  silc_task_queue_free(client->io_queue);
+ err2:
+  return FALSE;
+}
+
+/* Stops the client. This is called to stop the client and thus to stop
+   the program. */
+
+void silc_client_stop(SilcClient client)
+{
+  SILC_LOG_DEBUG(("Stopping client"));
+
+  /* Stop the scheduler, although it might be already stopped. This
+     doesn't hurt anyone. This removes all the tasks and task queues,
+     as well. */
+  silc_schedule_stop();
+  silc_schedule_uninit();
+
+  SILC_LOG_DEBUG(("Client client"));
+}
+
+/* Runs the client. */
+
+void silc_client_run(SilcClient client)
+{
+  SILC_LOG_DEBUG(("Running client"));
+
+  /* Start the scheduler, the heart of the SILC client. When this returns
+     the program will be terminated. */
+  silc_schedule();
+}
+
+/* Creates the main window used in SILC client. This is called always
+   at the initialization of the client. If user wants to create more
+   than one windows a new windows are always created by calling 
+   silc_client_add_window. */
+
+SilcClientWindow silc_client_create_main_window(SilcClient client)
+{
+  SilcClientWindow win;
+  void *screen;
+
+  SILC_LOG_DEBUG(("Creating main window"));
+
+  assert(client->screen != NULL);
+
+  win = silc_calloc(1, sizeof(*win));
+  if (win == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new window"));
+    return NULL;
+  }
+
+  client->screen->u_stat_line.program_name = silc_name;
+  client->screen->u_stat_line.program_version = silc_version;
+
+  /* Add the pointers */
+  win->nickname = silc_get_username();
+  win->local_id = NULL;
+  win->local_id_data = NULL;
+  win->local_id_data_len = 0;
+  win->remote_host = NULL;
+  win->remote_port = -1;
+  win->sock = NULL;
+
+  /* Create the actual screen */
+  screen = (void *)silc_screen_create_output_window(client->screen);
+  silc_screen_create_input_window(client->screen);
+  silc_screen_init_upper_status_line(client->screen);
+  silc_screen_init_output_status_line(client->screen);
+  win->screen = screen;
+
+  client->screen->bottom_line->nickname = win->nickname;
+  silc_screen_print_bottom_line(client->screen, 0);
+
+  /* Add the window to windows table */
+  client->windows = silc_calloc(1, sizeof(*client->windows));
+  client->windows[client->windows_count] = win;
+  client->windows_count = 1;
+
+  /* Automatically becomes the current active window */
+  client->current_win = win;
+
+  return win;
+}
+
+/* Allocates and adds new window to the client. This allocates new
+   physical window and internal window for connection specific data. 
+   All the connection specific data is always saved into a window
+   since connection is always associated to a active window. */
+
+SilcClientWindow silc_client_add_window(SilcClient client,
+                                       int is_current)
+{
+  SilcClientWindow win;
+
+  assert(client->screen != NULL);
+
+  win = silc_calloc(1, sizeof(*win));
+  if (win == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new window"));
+    return NULL;
+  }
+
+  /* Add the pointers */
+  win->screen = silc_screen_add_output_window(client->screen);
+  win->sock = NULL;
+
+  /* Add the window to windows table */
+  client->windows = silc_realloc(client->windows, sizeof(*client->windows)
+                                * (client->windows_count + 1));
+  client->windows[client->windows_count] = win;
+  client->windows_count++;
+
+  if (is_current == TRUE)
+    client->current_win = win;
+
+  return win;
+}
+
+/* The main task on SILC client. This processes the key pressings user
+   has made. */
+
+SILC_TASK_CALLBACK(silc_client_process_key_press)
+{
+  SilcClient client = (SilcClient)context;
+  int c;
+
+  /* There is data pending in stdin, this gets it directly */
+  c = wgetch(client->screen->input_win);
+  if (silc_client_bad_keys(c))
+    return;
+
+  SILC_LOG_DEBUG(("Pressed key: %d", c));
+
+  switch(c) {
+    /* 
+     * Special character handling
+     */
+  case KEY_UP: 
+  case KEY_DOWN:
+    break;
+  case KEY_RIGHT:
+    /* Right arrow */
+    SILC_LOG_DEBUG(("RIGHT"));
+    silc_screen_input_cursor_right(client->screen);
+    break;
+  case KEY_LEFT:
+    /* Left arrow */
+    SILC_LOG_DEBUG(("LEFT"));
+    silc_screen_input_cursor_left(client->screen);
+    break;
+  case KEY_BACKSPACE:
+  case KEY_DC:
+  case '\177':
+  case '\b':
+    /* Backspace */
+    silc_screen_input_backspace(client->screen);
+    break;
+  case '\011':
+    /* Tabulator */
+    break;
+  case KEY_IC:
+    /* Insert switch. Turns on/off insert on input window */
+    silc_screen_input_insert(client->screen);
+    break;
+  case CTRL('j'):
+  case '\r':
+    /* Enter, Return. User pressed enter we are ready to
+       process the message. */
+    silc_client_process_message(client);
+    silc_screen_input_reset(client->screen);
+    break;
+  case CTRL('l'):
+    /* Refresh screen, Ctrl^l */
+    silc_screen_refresh_all(client->screen);
+    break;
+  case CTRL('a'):
+  case KEY_HOME:
+  case KEY_BEG:
+    /* Beginning, Home */
+    silc_screen_input_cursor_home(client->screen);
+    break;
+  case CTRL('e'):
+  case KEY_END:
+    /* End */
+    silc_screen_input_cursor_end(client->screen);
+    break;
+  case KEY_LL:
+    /* End */
+    break;
+  case CTRL('g'):
+    /* Bell, Ctrl^g */
+    beep();
+    break;
+  case KEY_DL:
+  case CTRL('u'):
+    /* Delete line */
+    break;
+  default:
+    /* 
+     * Other characters 
+     */
+    if (c < 32) {
+      /* Control codes are printed as reversed */
+      c = (c & 127) | 64;
+      wattron(client->screen->input_win, A_REVERSE);
+      silc_screen_input_print(client->screen, c);
+      wattroff(client->screen->input_win, A_REVERSE);
+    } else  {
+      /* Normal character */
+      silc_screen_input_print(client->screen, c);
+    }
+  }
+
+  silc_screen_print_coordinates(client->screen, 0);
+  silc_screen_refresh_win(client->screen->input_win);
+}
+
+static int silc_client_bad_keys(unsigned char key)
+{
+  /* these are explained in curses.h */
+  switch(key) {
+  case KEY_SF:
+  case KEY_SR:
+  case KEY_NPAGE:
+  case KEY_PPAGE:
+  case KEY_PRINT:
+  case KEY_A1:
+  case KEY_A3:
+  case KEY_B2:
+  case KEY_C1:
+  case KEY_C3:
+  case KEY_UNDO:
+  case KEY_EXIT:
+  case '\v':           /* VT */
+  case '\E':           /* we ignore ESC */
+    return TRUE;
+  default: 
+    return FALSE; 
+  }
+}
+
+/* Processes messages user has typed on the screen. This either sends
+   a packet out to network or if command were written executes it. */
+
+static void silc_client_process_message(SilcClient client)
+{
+  unsigned char *data;
+  unsigned int len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  data = client->input_buffer->data;
+  len = strlen(data);
+
+  if (data[0] == '/' && data[1] != ' ') {
+    /* Command */
+    unsigned int argc = 0;
+    unsigned char **argv, *tmpcmd;
+    unsigned int *argv_lens, *argv_types;
+    SilcClientCommand *cmd;
+    SilcClientCommandContext ctx;
+
+    /* Get the command */
+    tmpcmd = silc_client_parse_command(data);
+
+    /* Find command match */
+    for (cmd = silc_command_list; cmd->name; cmd++) {
+      if (!strcmp(cmd->name, tmpcmd))
+       break;
+    }
+
+    if (cmd->name == NULL) {
+      silc_say(client, "Invalid command: %s", tmpcmd);
+      silc_free(tmpcmd);
+      goto out;
+    }
+
+    /* Now parse all arguments */
+    silc_client_parse_command_line(data, &argv, &argv_lens, 
+                                  &argv_types, &argc, cmd->max_args);
+    silc_free(tmpcmd);
+
+    SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
+
+    /* Allocate command context. This and its internals must be free'd 
+       by the command routine receiving it. */
+    ctx = silc_calloc(1, sizeof(*ctx));
+    ctx->client = client;
+    ctx->sock = client->current_win->sock;
+    ctx->argc = argc;
+    ctx->argv = argv;
+    ctx->argv_lens = argv_lens;
+    ctx->argv_types = argv_types;
+
+    /* Execute command */
+    (*cmd->cb)(ctx);
+
+  } else {
+    /* Normal message to a channel */
+    if (len && client->current_win->current_channel &&
+       client->current_win->current_channel->on_channel == TRUE) {
+      silc_print(client, "> %s", data);
+      silc_client_packet_send_to_channel(client, 
+                                        client->current_win->sock,
+                                        client->current_win->current_channel,
+                                        data, strlen(data), TRUE);
+    }
+  }
+
+ out:
+  /* Clear the input buffer */
+  silc_buffer_clear(client->input_buffer);
+  silc_buffer_pull_tail(client->input_buffer, 
+                       SILC_BUFFER_END(client->input_buffer));
+}
+
+/* Returns the command fetched from user typed command line */
+
+static char *silc_client_parse_command(unsigned char *buffer)
+{
+  char *ret;
+  const char *cp = buffer;
+  int len;
+
+  len = strcspn(cp, " ");
+  ret = silc_to_upper((char *)++cp);
+  ret[len - 1] = 0;
+
+  return ret;
+}
+
+/* Parses user typed command line. At most `max_args' is taken. Rest
+   of the line will be allocated as the last argument if there are more
+   than `max_args' arguments in the line. Note that the command name
+   is counted as one argument and is saved. */
+
+void silc_client_parse_command_line(unsigned char *buffer, 
+                                   unsigned char ***parsed,
+                                   unsigned int **parsed_lens,
+                                   unsigned int **parsed_types,
+                                   unsigned int *parsed_num,
+                                   unsigned int max_args)
+{
+  int i, len = 0;
+  int argc = 0;
+  const char *cp = buffer;
+
+  /* Take the '/' away */
+  cp++;
+
+  *parsed = silc_calloc(1, sizeof(**parsed));
+  *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
+
+  /* Get the command first */
+  len = strcspn(cp, " ");
+  (*parsed)[0] = silc_to_upper((char *)cp);
+  (*parsed_lens)[0] = len;
+  cp += len + 1;
+  argc++;
+
+  /* Parse arguments */
+  if (strchr(cp, ' ') || strlen(cp) != 0) {
+    for (i = 1; i < max_args; i++) {
+
+      if (i != max_args - 1)
+       len = strcspn(cp, " ");
+      else
+       len = strlen(cp);
+      
+      *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
+      *parsed_lens = silc_realloc(*parsed_lens, 
+                                 sizeof(**parsed_lens) * (argc + 1));
+      (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
+      memcpy((*parsed)[argc], cp, len);
+      (*parsed_lens)[argc] = len;
+      argc++;
+
+      cp += len;
+      if (strlen(cp) == 0)
+       break;
+      else
+       cp++;
+    }
+  }
+
+  /* Save argument types. Protocol defines all argument types but
+     this implementation makes sure that they are always in correct
+     order hence this simple code. */
+  *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
+  for (i = 0; i < argc; i++)
+    (*parsed_types)[i] = i;
+
+  *parsed_num = argc;
+}
+
+/* Updates clock on the screen every minute. */
+
+SILC_TASK_CALLBACK(silc_client_update_clock)
+{
+  SilcClient client = (SilcClient)context;
+
+  /* Update the clock on the screen */
+  silc_screen_print_clock(client->screen);
+
+  /* Re-register this same task */
+  silc_task_register(qptr, 0, silc_client_update_clock, context, 
+                    silc_client_time_til_next_min(), 0,
+                    SILC_TASK_TIMEOUT,
+                    SILC_TASK_PRI_LOW);
+
+  silc_screen_refresh_win(client->screen->input_win);
+}
+
+/* Runs commands user configured in configuration file. This is
+   called when initializing client. */
+
+SILC_TASK_CALLBACK(silc_client_run_commands)
+{
+  SilcClient client = (SilcClient)context;
+  SilcClientConfigSectionCommand *cs;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  cs = client->config->commands;
+  while(cs) {
+    unsigned int argc = 0;
+    unsigned char **argv, *tmpcmd;
+    unsigned int *argv_lens, *argv_types;
+    SilcClientCommand *cmd;
+    SilcClientCommandContext ctx;
+
+    /* Get the command */
+    tmpcmd = silc_client_parse_command(cs->command);
+
+    for (cmd = silc_command_list; cmd->name; cmd++) {
+      if (!strcmp(cmd->name, tmpcmd))
+       break;
+    }
+    
+    if (cmd->name == NULL) {
+      silc_say(client, "Invalid command: %s", tmpcmd);
+      silc_free(tmpcmd);
+      continue;
+    }
+    
+    /* Now parse all arguments */
+    silc_client_parse_command_line(cs->command, &argv, &argv_lens, 
+                                  &argv_types, &argc, cmd->max_args);
+    silc_free(tmpcmd);
+
+    SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
+
+    /* Allocate command context. This and its internals must be free'd 
+       by the command routine receiving it. */
+    ctx = silc_calloc(1, sizeof(*ctx));
+    ctx->client = client;
+    ctx->sock = client->current_win->sock;
+    ctx->argc = argc;
+    ctx->argv = argv;
+    ctx->argv_lens = argv_lens;
+    ctx->argv_types = argv_types;
+
+    /* Execute command */
+    (*cmd->cb)(ctx);
+
+    cs = cs->next;
+  }
+}
+
+/* Internal context for connection process. This is needed as we
+   doing asynchronous connecting. */
+typedef struct {
+  SilcClient client;
+  SilcTask task;
+  int sock;
+  char *host;
+  int port;
+  int tries;
+} SilcClientInternalConnectContext;
+
+static int 
+silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
+{
+  int sock;
+
+  /* XXX In the future we should give up this non-blocking connect all
+     together and use threads instead. */
+  /* Create connection to server asynchronously */
+  sock = silc_net_create_connection_async(ctx->port, ctx->host);
+  if (sock < 0)
+    return -1;
+
+  /* Register task that will receive the async connect and will
+     read the result. */
+  ctx->task = silc_task_register(ctx->client->io_queue, sock, 
+                                silc_client_connect_to_server_start,
+                                (void *)ctx, 0, 0, 
+                                SILC_TASK_FD,
+                                SILC_TASK_PRI_NORMAL);
+  silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
+  silc_schedule_set_listen_fd(sock, ctx->task->iomask);
+
+  ctx->sock = sock;
+
+  return sock;
+}
+
+/* Connects to remote server */
+
+int silc_client_connect_to_server(SilcClient client, int port,
+                                 char *host)
+{
+  SilcClientInternalConnectContext *ctx;
+
+  SILC_LOG_DEBUG(("Connecting to port %d of server %s",
+                 port, host));
+
+  silc_say(client, "Connecting to port %d of server %s", port, host);
+
+  client->current_win->remote_host = strdup(host);
+  client->current_win->remote_port = port;
+
+  /* Allocate internal context for connection process. This is
+     needed as we are doing async connecting. */
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->client = client;
+  ctx->host = strdup(host);
+  ctx->port = port;
+  ctx->tries = 0;
+
+  /* Do the actual connecting process */
+  return silc_client_connect_to_server_internal(ctx);
+}
+
+/* Start of the connection to the remote server. This is called after
+   succesful TCP/IP connection has been established to the remote host. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
+{
+  SilcClientInternalConnectContext *ctx =
+    (SilcClientInternalConnectContext *)context;
+  SilcClient client = ctx->client;
+  SilcProtocol protocol;
+  SilcClientKEInternalContext *proto_ctx;
+  int opt, opt_len = sizeof(opt);
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Check the socket status as it might be in error */
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
+  if (opt != 0) {
+    if (ctx->tries < 2) {
+      /* Connection failed but lets try again */
+      silc_say(ctx->client, "Could not connect to server %s: %s",
+              ctx->host, strerror(opt));
+      silc_say(client, "Connecting to port %d of server %s resumed", 
+              ctx->port, ctx->host);
+
+      /* Unregister old connection try */
+      silc_schedule_unset_listen_fd(fd);
+      silc_net_close_connection(fd);
+      silc_task_unregister(client->io_queue, ctx->task);
+
+      /* Try again */
+      silc_client_connect_to_server_internal(ctx);
+      ctx->tries++;
+    } else {
+      /* Connection failed and we won't try anymore */
+      silc_say(ctx->client, "Could not connect to server %s: %s",
+              ctx->host, strerror(opt));
+      silc_schedule_unset_listen_fd(fd);
+      silc_net_close_connection(fd);
+      silc_task_unregister(client->io_queue, ctx->task);
+      silc_free(ctx);
+    }
+    return;
+  }
+
+  silc_schedule_unset_listen_fd(fd);
+  silc_task_unregister(client->io_queue, ctx->task);
+  silc_free(ctx);
+
+  /* Allocate new socket connection object */
+  silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, 
+                   (void *)client->current_win, 
+                   &client->current_win->sock);
+  if (client->current_win->sock == NULL) {
+    silc_say(client, "Error: Could not allocate connection socket");
+    silc_net_close_connection(fd);
+    return;
+  }
+  client->current_win->sock->hostname = client->current_win->remote_host;
+  client->current_win->sock->port = client->current_win->remote_port;
+
+  /* Allocate internal Key Exchange context. This is sent to the
+     protocol as context. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->client = (void *)client;
+  proto_ctx->sock = client->current_win->sock;
+  proto_ctx->rng = client->rng;
+  proto_ctx->responder = FALSE;
+
+  /* Perform key exchange protocol. silc_client_connect_to_server_final
+     will be called after the protocol is finished. */
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
+                     &protocol, (void *)proto_ctx,
+                     silc_client_connect_to_server_second);
+  if (!protocol) {
+    silc_say(client, "Error: Could not start authentication protocol");
+    return;
+  }
+  client->current_win->sock->protocol = protocol;
+
+  /* Register the connection for network input and output. This sets
+     that scheduler will listen for incoming packets for this connection 
+     and sets that outgoing packets may be sent to this connection as well.
+     However, this doesn't set the scheduler for outgoing traffic, it will 
+     be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+     later when outgoing data is available. */
+  context = (void *)client;
+  SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
+
+  /* Execute the protocol */
+  protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+}
+
+/* Second part of the connecting to the server. This executed 
+   authentication protocol. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientKEInternalContext *ctx = 
+    (SilcClientKEInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+  SilcSocketConnection sock = NULL;
+  SilcClientConnAuthInternalContext *proto_ctx;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    SILC_LOG_DEBUG(("Error during KE protocol"));
+    silc_protocol_free(protocol);
+    if (ctx->packet)
+      silc_buffer_free(ctx->packet);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    silc_free(ctx);
+    sock->protocol = NULL;
+    return;
+  }
+
+  /* Allocate internal context for the authentication protocol. This
+     is sent as context for the protocol. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->client = (void *)client;
+  proto_ctx->sock = sock = ctx->sock;
+  proto_ctx->ske = ctx->ske;   /* Save SKE object from previous protocol */
+
+  /* Resolve the authentication method to be used in this connection */
+  proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+  if (client->config->conns) {
+    SilcClientConfigSectionConnection *conn = NULL;
+
+    /* Check if we find a match from user configured connections */
+    conn = silc_client_config_find_connection(client->config,
+                                             sock->hostname,
+                                             sock->port);
+    if (conn) {
+      /* Match found. Use the configured authentication method */
+      proto_ctx->auth_meth = conn->auth_meth;
+      if (conn->auth_data) {
+       proto_ctx->auth_data = strdup(conn->auth_data);
+       proto_ctx->auth_data_len = strlen(conn->auth_data);
+      }
+    } else {
+      /* No match found. Resolve by sending AUTH_REQUEST to server */
+      proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+    }
+  } else {
+    /* XXX Resolve by sending AUTH_REQUEST to server */
+    proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+  }
+
+  /* Free old protocol as it is finished now */
+  silc_protocol_free(protocol);
+  if (ctx->packet)
+    silc_buffer_free(ctx->packet);
+  silc_free(ctx);
+  /* silc_free(ctx->keymat....); */
+  sock->protocol = NULL;
+
+  /* Allocate the authentication protocol. This is allocated here
+     but we won't start it yet. We will be receiving party of this
+     protocol thus we will wait that connecting party will make
+     their first move. */
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
+                     &sock->protocol, (void *)proto_ctx, 
+                     silc_client_connect_to_server_final);
+
+  /* Execute the protocol */
+  sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
+}
+
+/* Finalizes the connection to the remote SILC server. This is called
+   after authentication protocol has been completed. This send our
+   user information to the server to receive our client ID from
+   server. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientConnAuthInternalContext *ctx = 
+    (SilcClientConnAuthInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+  SilcClientWindow win = (SilcClientWindow)ctx->sock->user_data;
+  SilcBuffer packet;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    SILC_LOG_DEBUG(("Error during authentication protocol"));
+    silc_protocol_free(protocol);
+    if (ctx->auth_data)
+      silc_free(ctx->auth_data);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    silc_free(ctx);
+    win->sock->protocol = NULL;
+    return;
+  }
+
+  /* Send NEW_CLIENT packet to the server. We will become registered
+     to the SILC network after sending this packet and we will receive
+     client ID from the server. */
+  packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
+                            strlen(client->realname));
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(strlen(client->username)),
+                    SILC_STR_UI_XNSTRING(client->username,
+                                         strlen(client->username)),
+                    SILC_STR_UI_SHORT(strlen(client->realname)),
+                    SILC_STR_UI_XNSTRING(client->realname,
+                                         strlen(client->realname)),
+                    SILC_STR_END);
+
+  /* Send the packet */
+  silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
+                         NULL, 0, NULL, NULL, 
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+
+  silc_say(client, "Connected to port %d of host %s",
+          win->remote_port, win->remote_host);
+
+  client->screen->bottom_line->connection = win->remote_host;
+  silc_screen_print_bottom_line(client->screen, 0);
+
+  silc_protocol_free(protocol);
+  if (ctx->auth_data)
+    silc_free(ctx->auth_data);
+  if (ctx->ske)
+    silc_ske_free(ctx->ske);
+  silc_free(ctx);
+  win->sock->protocol = NULL;
+}
+
+typedef struct {
+  SilcPacketContext *packetdata;
+  SilcSocketConnection sock;
+  SilcClient client;
+} SilcClientInternalPacket;
+
+SILC_TASK_CALLBACK(silc_client_packet_process)
+{
+  SilcClient client = (SilcClient)context;
+  SilcSocketConnection sock = NULL;
+  int ret, packetlen, paddedlen;
+
+  SILC_LOG_DEBUG(("Processing packet"));
+
+  SILC_CLIENT_GET_SOCK(client, fd, sock);
+  if (sock == NULL)
+    return;
+
+  /* Packet sending */
+  if (type == SILC_TASK_WRITE) {
+    SILC_LOG_DEBUG(("Writing data to connection"));
+
+    if (sock->outbuf->data - sock->outbuf->head)
+      silc_buffer_push(sock->outbuf, 
+                      sock->outbuf->data - sock->outbuf->head);
+
+    /* Write the packet out to the connection */
+    ret = silc_packet_write(fd, sock->outbuf);
+
+    /* If returned -2 could not write to connection now, will do
+       it later. */
+    if (ret == -2)
+      return;
+    
+    /* Error */
+    if (ret == -1)
+      SILC_LOG_ERROR(("Packet dropped"));
+
+    /* The packet has been sent and now it is time to set the connection
+       back to only for input. When there is again some outgoing data 
+       available for this connection it will be set for output as well. 
+       This call clears the output setting and sets it only for input. */
+    SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
+    SILC_UNSET_OUTBUF_PENDING(sock);
+
+    return;
+  }
+
+  /* Packet receiving */
+  if (type == SILC_TASK_READ) {
+    SILC_LOG_DEBUG(("Reading data from connection"));
+
+    /* Allocate the incoming data buffer if not done already. */
+    if (!sock->inbuf)
+      sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+
+    /* Read some data from connection */
+    ret = silc_packet_read(fd, sock->inbuf);
+    
+    /* If returned -2 data was not available now, will read it later. */
+    if (ret == -2)
+      return;
+    
+    /* Error */
+    if (ret == -1) {
+      SILC_LOG_ERROR(("Packet dropped"));
+      return;
+    }
+    
+    /* EOF */
+    if (ret == 0) {
+      SILC_LOG_DEBUG(("Read EOF"));
+
+      /* If connection is disconnecting already we will finally
+        close the connection */
+      if (SILC_IS_DISCONNECTING(sock)) {
+       silc_client_close_connection(client, sock);
+       return;
+      }
+      
+      silc_say(client, "Connection closed: premature EOF");
+      SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+
+      silc_client_close_connection(client, sock);
+      return;
+    }
+
+    /* Check whether we received a whole packet. If reading went without
+       errors we either read a whole packet or the read packet is 
+       incorrect and will be dropped. */
+    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+    if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
+      SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+      silc_buffer_clear(sock->inbuf);
+      return;
+    }
+    
+    /* Decrypt a packet coming from server connection */
+    if (sock->type == SILC_SOCKET_TYPE_SERVER ||
+       sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      SilcClientWindow win = (SilcClientWindow)sock->user_data;
+      SilcClientInternalPacket *packet;
+      int mac_len = 0;
+
+      if (win->hmac)
+       mac_len = win->hmac->hash->hash->hash_len;
+
+      if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+       /* Received possibly many packets at once */
+
+       while(sock->inbuf->len > 0) {
+         SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+         if (sock->inbuf->len < paddedlen) {
+           SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+           return;
+         }
+
+         paddedlen += 2;
+         packet = silc_calloc(1, sizeof(*packet));
+         packet->client = client;
+         packet->sock = sock;
+         packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+         packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
+         silc_buffer_pull_tail(packet->packetdata->buffer, 
+                               SILC_BUFFER_END(packet->packetdata->buffer));
+         silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data, 
+                         paddedlen + mac_len);
+
+         SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
+                           packet->packetdata->buffer->len),
+                          packet->packetdata->buffer->data, 
+                          packet->packetdata->buffer->len);
+         SILC_LOG_DEBUG(("Packet from server %s, "
+                         "server type %d, packet length %d", 
+                         win->remote_host, win->remote_type, paddedlen));
+
+         /* If this packet is for the current active connection we will
+            parse the packet right away to get it quickly on the screen.
+            Otherwise, it will be parsed with a timeout as the data is
+            for inactive window (which might not be visible at all). */
+         if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
+           /* Parse it real soon */
+           silc_task_register(client->timeout_queue, fd, 
+                              silc_client_packet_parse,
+                              (void *)packet, 0, 1, 
+                              SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+         } else {
+           /* Parse the packet with timeout */
+           silc_task_register(client->timeout_queue, fd, 
+                              silc_client_packet_parse,
+                              (void *)packet, 0, 200000, 
+                              SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+         }
+
+         /* Pull the packet from inbuf thus we'll get the next one
+            in the inbuf. */
+         silc_buffer_pull(sock->inbuf, paddedlen);
+         if (win->hmac)
+           silc_buffer_pull(sock->inbuf, mac_len);
+       }
+       silc_buffer_clear(sock->inbuf);
+       return;
+      } else {
+       /* Received one packet */
+       
+       SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+                        sock->inbuf->data, sock->inbuf->len);
+       SILC_LOG_DEBUG(("Packet from server %s, "
+                       "server type %d, packet length %d", 
+                       win->remote_host, win->remote_type, paddedlen));
+       
+       packet = silc_calloc(1, sizeof(*packet));
+       packet->client = client;
+       packet->sock = sock;
+       packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+       packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+       silc_buffer_clear(sock->inbuf);
+
+       /* If this packet is for the current active connection we will
+          parse the packet right away to get it quickly on the screen.
+          Otherwise, it will be parsed with a timeout as the data is
+          for inactive window (which might not be visible at all). */
+       if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
+         /* Parse it real soon */
+         silc_task_register(client->timeout_queue, fd, 
+                            silc_client_packet_parse,
+                            (void *)packet, 0, 1, 
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+         return;
+       } else {
+         /* Parse the packet with timeout */
+         silc_task_register(client->timeout_queue, fd, 
+                            silc_client_packet_parse,
+                            (void *)packet, 0, 200000, 
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+         return;
+       }
+      }
+    }
+  }
+  
+  SILC_LOG_ERROR(("Weird, nothing happened - ignoring"));
+}
+
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
+   after packet has been totally decrypted and parsed. */
+
+static int silc_client_packet_check_mac(SilcClient client,
+                                       SilcSocketConnection sock,
+                                       SilcBuffer buffer)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+
+  /* Check MAC */
+  if (win->hmac) {
+    int headlen = buffer->data - buffer->head, mac_len;
+    unsigned char *packet_mac, mac[32];
+    
+    SILC_LOG_DEBUG(("Verifying MAC"));
+
+    mac_len = win->hmac->hash->hash->hash_len;
+
+    silc_buffer_push(buffer, headlen);
+
+    /* Take mac from packet */
+    packet_mac = buffer->tail;
+    
+    /* Make MAC and compare */
+    memset(mac, 0, sizeof(mac));
+    silc_hmac_make_with_key(win->hmac, 
+                           buffer->data, buffer->len,
+                           win->hmac_key, win->hmac_key_len, mac);
+#if 0
+    SILC_LOG_HEXDUMP(("PMAC"), packet_mac, mac_len);
+    SILC_LOG_HEXDUMP(("CMAC"), mac, mac_len);
+#endif
+    if (memcmp(mac, packet_mac, mac_len)) {
+      SILC_LOG_DEBUG(("MAC failed"));
+      return FALSE;
+    }
+    
+    SILC_LOG_DEBUG(("MAC is Ok"));
+    memset(mac, 0, sizeof(mac));
+
+    silc_buffer_pull(buffer, headlen);
+  }
+  
+  return TRUE;
+}
+
+/* Decrypts rest of the packet (after decrypting just the SILC header).
+   After calling this function the packet is ready to be parsed by calling 
+   silc_packet_parse. */
+
+static int silc_client_packet_decrypt_rest(SilcClient client, 
+                                          SilcSocketConnection sock,
+                                          SilcBuffer buffer)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  unsigned int mac_len = 0;
+  
+  /* Decrypt */
+  if (win && win->receive_key) {
+
+    /* Pull MAC from packet before decryption */
+    if (win->hmac) {
+      mac_len = win->hmac->hash->hash->hash_len;
+      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, mac_len);
+      } else {
+       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       return FALSE;
+      }
+    }
+
+    SILC_LOG_DEBUG(("Decrypting rest of the packet"));
+
+    /* Decrypt rest of the packet */
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    silc_packet_decrypt(win->receive_key, buffer, buffer->len);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+
+    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
+                    buffer->data, buffer->len);
+  }
+
+  return TRUE;
+}
+
+/* Decrypts rest of the SILC Packet header that has been decrypted partly
+   already. This decrypts the padding of the packet also.  After calling 
+   this function the packet is ready to be parsed by calling function 
+   silc_packet_parse. This is used in special packet reception. */
+
+static int silc_client_packet_decrypt_rest_special(SilcClient client, 
+                                                 SilcSocketConnection sock,
+                                                 SilcBuffer buffer)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  unsigned int mac_len = 0;
+
+  /* Decrypt rest of the header plus padding */
+  if (win && win->receive_key) {
+    unsigned short truelen, len1, len2, padlen;
+
+    /* Pull MAC from packet before decryption */
+    if (win->hmac) {
+      mac_len = win->hmac->hash->hash->hash_len;
+      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, mac_len);
+      } else {
+       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       return FALSE;
+      }
+    }
+  
+    SILC_LOG_DEBUG(("Decrypting rest of the header"));
+
+    SILC_GET16_MSB(len1, &buffer->data[4]);
+    SILC_GET16_MSB(len2, &buffer->data[6]);
+
+    truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
+    padlen = SILC_PACKET_PADLEN(truelen);
+    len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
+
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    SILC_LOG_HEXDUMP(("XXX"), buffer->data, buffer->len);
+    silc_packet_decrypt(win->receive_key, buffer, len1);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    SILC_LOG_HEXDUMP(("XXX"), buffer->data, buffer->len);
+  }
+
+  return TRUE;
+}
+
+/* Parses whole packet, received earlier. */
+
+SILC_TASK_CALLBACK(silc_client_packet_parse)
+{
+  SilcClientInternalPacket *packet = (SilcClientInternalPacket *)context;
+  SilcBuffer buffer = packet->packetdata->buffer;
+  SilcClient client = packet->client;
+  SilcSocketConnection sock = packet->sock;
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  int ret;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Decrypt start of the packet header */
+  if (win && win->receive_key)
+    silc_packet_decrypt(win->receive_key, buffer, SILC_PACKET_MIN_HEADER_LEN);
+
+  /* If the packet type is not any special type lets decrypt rest
+     of the packet here. */
+  if (buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE &&
+      buffer->data[3] != SILC_PACKET_PRIVATE_MESSAGE) {
+  normal:
+    /* Normal packet, decrypt rest of the packet */
+    if (!silc_client_packet_decrypt_rest(client, sock, buffer))
+      goto out;
+
+    /* Parse the packet. Packet type is returned. */
+    ret = silc_packet_parse(packet->packetdata);
+    if (ret == SILC_PACKET_NONE)
+      goto out;
+
+    /* Check MAC */
+    if (!silc_client_packet_check_mac(client, sock, buffer))
+      goto out;
+  } else {
+    /* If private message key is not set for private message it is
+       handled as normal packet. Go back up. */
+    if (buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+       !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+      goto normal;
+
+    /* Packet requires special handling, decrypt rest of the header.
+       This only decrypts. This does not do any MAC checking, it must
+       be done individually later when doing the special processing. */
+    silc_client_packet_decrypt_rest_special(client, sock, buffer);
+
+    /* Parse the packet header in special way as this is "special"
+       packet type. */
+    ret = silc_packet_parse_special(packet->packetdata);
+    if (ret == SILC_PACKET_NONE)
+      goto out;
+  }
+
+  /* Parse the incoming packet type */
+  silc_client_packet_parse_type(client, sock, packet->packetdata);
+
+ out:
+  silc_buffer_clear(packet->packetdata->buffer);
+  silc_free(packet->packetdata);
+  silc_free(packet);
+}
+
+/* Parses the packet type and calls what ever routines the packet type
+   requires. This is done for all incoming packets. */
+
+void silc_client_packet_parse_type(SilcClient client, 
+                                  SilcSocketConnection sock,
+                                  SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcPacketType type = packet->type;
+
+  SILC_LOG_DEBUG(("Parsing packet type %d", type));
+
+  /* Parse the packet type */
+  switch(type) {
+  case SILC_PACKET_DISCONNECT:
+    silc_client_disconnected_by_server(client, sock, buffer);
+    break;
+  case SILC_PACKET_SUCCESS:
+    /*
+     * Success received for something. For now we can have only
+     * one protocol for connection executing at once hence this
+     * success message is for whatever protocol is executing currently.
+     */
+    if (sock->protocol) {
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    }
+    break;
+  case SILC_PACKET_FAILURE:
+    /*
+     * Failure received for some protocol. Set the protocol state to 
+     * error and call the protocol callback. This fill cause error on
+     * protocol and it will call the final callback.
+     */
+    if (sock->protocol) {
+      sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    }
+    break;
+  case SILC_PACKET_REJECT:
+    break;
+
+  case SILC_PACKET_NOTIFY:
+    /*
+     * Received notify message 
+     */
+    silc_client_notify_by_server(client, sock, buffer);
+    break;
+
+  case SILC_PACKET_ERROR:
+    /*
+     * Received error message
+     */
+    silc_client_error_by_server(client, sock, buffer);
+    break;
+
+  case SILC_PACKET_CHANNEL_MESSAGE:
+    /*
+     * Received message to (from, actually) a channel
+     */
+    silc_client_channel_message(client, sock, packet);
+    break;
+  case SILC_PACKET_CHANNEL_KEY:
+    /*
+     * Received key for a channel. By receiving this key the client will be
+     * able to talk to the channel it has just joined. This can also be
+     * a new key for existing channel as keys expire peridiocally.
+     */
+    silc_client_receive_channel_key(client, sock, buffer);
+    break;
+
+  case SILC_PACKET_PRIVATE_MESSAGE:
+    /*
+     * Received private message
+     */
+    {
+      SilcClientCommandReplyContext ctx;
+      ctx = silc_calloc(1, sizeof(*ctx));
+      ctx->client = client;
+      ctx->sock = sock;
+      ctx->context = buffer;   /* kludge */
+      silc_client_command_reply_msg((void *)ctx);
+    }
+    break;
+  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+    /*
+     * Received private message key
+     */
+    break;
+
+  case SILC_PACKET_COMMAND_REPLY:
+    /*
+     * Recived reply for a command
+     */
+    silc_client_command_reply_process(client, sock, buffer);
+    break;
+
+  case SILC_PACKET_KEY_EXCHANGE:
+    if (sock->protocol) {
+      SilcClientKEInternalContext *proto_ctx = 
+       (SilcClientKEInternalContext *)sock->protocol->context;
+
+      proto_ctx->packet = buffer;
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
+                     "protocol active, packet dropped."));
+
+      /* XXX Trigger KE protocol?? Rekey actually! */
+    }
+    break;
+
+  case SILC_PACKET_KEY_EXCHANGE_1:
+    if (sock->protocol) {
+
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
+                     "protocol active, packet dropped."));
+    }
+    break;
+  case SILC_PACKET_KEY_EXCHANGE_2:
+    if (sock->protocol) {
+      SilcClientKEInternalContext *proto_ctx = 
+       (SilcClientKEInternalContext *)sock->protocol->context;
+
+      if (proto_ctx->packet)
+       silc_buffer_free(proto_ctx->packet);
+
+      proto_ctx->packet = buffer;
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
+                     "protocol active, packet dropped."));
+    }
+    break;
+
+  case SILC_PACKET_NEW_ID:
+    {
+      /*
+       * Received new ID from server. This packet is received at
+       * the connection to the server.  New ID is also received when 
+       * user changes nickname but in that case the new ID is received
+       * as command reply and not as this packet type.
+       */
+      unsigned char *id_string;
+      unsigned short id_type;
+      
+      silc_buffer_unformat(buffer,
+                          SILC_STR_UI_SHORT(&id_type),
+                          SILC_STR_UI16_STRING_ALLOC(&id_string),
+                          SILC_STR_END);
+      
+      if ((SilcIdType)id_type != SILC_ID_CLIENT)
+       break;
+
+      silc_client_receive_new_id(client, sock, id_string);
+      silc_free(id_string);
+      break;
+    }
+
+  default:
+    SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
+    break;
+  }
+}
+
+/* Internal routine that sends packet or marks packet to be sent. This
+   is used directly only in special cases. Normal cases should use
+   silc_server_packet_send. Returns < 0 on error. */
+
+static int silc_client_packet_send_real(SilcClient client,
+                                       SilcSocketConnection sock,
+                                       int force_send)
+{
+  /* Send now if forced to do so */
+  if (force_send == TRUE) {
+    int ret;
+    SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
+    ret = silc_packet_write(sock->sock, sock->outbuf);
+
+    if (ret == -1)
+      SILC_LOG_ERROR(("Packet dropped"));
+    if (ret != -2)
+      return ret;
+
+    SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
+  }  
+
+  SILC_LOG_DEBUG(("Packet in queue"));
+
+  /* Mark that there is some outgoing data available for this connection. 
+     This call sets the connection both for input and output (the input
+     is set always and this call keeps the input setting, actually). 
+     Actual data sending is performed by silc_client_packet_process. */
+  SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+  /* Mark to socket that data is pending in outgoing buffer. This flag
+     is needed if new data is added to the buffer before the earlier
+     put data is sent to the network. */
+  SILC_SET_OUTBUF_PENDING(sock);
+
+  return 0;
+}
+
+/* Prepare outgoing data buffer for packet sending. */
+
+static void silc_client_packet_send_prepare(SilcClient client,
+                                           SilcSocketConnection sock,
+                                           unsigned int header_len,
+                                           unsigned int padlen,
+                                           unsigned int data_len)
+{
+  int totlen, oldlen;
+
+  totlen = header_len + padlen + data_len;
+
+  /* Prepare the outgoing buffer for packet sending. */
+  if (!sock->outbuf) {
+    /* Allocate new buffer. This is done only once per connection. */
+    SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
+    
+    sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+    silc_buffer_pull_tail(sock->outbuf, totlen);
+    silc_buffer_pull(sock->outbuf, header_len + padlen);
+  } else {
+    if (SILC_IS_OUTBUF_PENDING(sock)) {
+      /* There is some pending data in the buffer. */
+
+      if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
+       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+       /* XXX: not done yet */
+      }
+      oldlen = sock->outbuf->len;
+      silc_buffer_pull_tail(sock->outbuf, totlen);
+      silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
+    } else {
+      /* Buffer is free for use */
+      silc_buffer_clear(sock->outbuf);
+      silc_buffer_pull_tail(sock->outbuf, totlen);
+      silc_buffer_pull(sock->outbuf, header_len + padlen);
+    }
+  }
+}
+
+/* Sends packet. This doesn't actually send the packet instead it assembles
+   it and marks it to be sent. However, if force_send is TRUE the packet
+   is sent immediately. if dst_id, cipher and hmac are NULL those parameters
+   will be derived from sock argument. Otherwise the valid arguments sent
+   are used. */
+
+void silc_client_packet_send(SilcClient client, 
+                            SilcSocketConnection sock,
+                            SilcPacketType type, 
+                            void *dst_id,
+                            SilcIdType dst_id_type,
+                            SilcCipher cipher,
+                            SilcHmac hmac,
+                            unsigned char *data, 
+                            unsigned int data_len, 
+                            int force_send)
+{
+  SilcPacketContext packetdata;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+
+  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+  /* Get data used in the packet sending, keys and stuff */
+  if ((!cipher || !hmac || !dst_id) && sock->user_data) {
+    if (!cipher && ((SilcClientWindow)sock->user_data)->send_key)
+      cipher = ((SilcClientWindow)sock->user_data)->send_key;
+    if (!hmac && ((SilcClientWindow)sock->user_data)->hmac) {
+      hmac = ((SilcClientWindow)sock->user_data)->hmac;
+      mac_len = hmac->hash->hash->hash_len;
+      hmac_key = ((SilcClientWindow)sock->user_data)->hmac_key;
+      hmac_key_len = ((SilcClientWindow)sock->user_data)->hmac_key_len;
+    }
+    if (!dst_id && ((SilcClientWindow)sock->user_data)->remote_id) {
+      dst_id = ((SilcClientWindow)sock->user_data)->remote_id;
+      dst_id_type = SILC_ID_SERVER;
+    }
+  }
+
+  /* Set the packet context pointers */
+  packetdata.flags = 0;
+  packetdata.type = type;
+  if (((SilcClientWindow)sock->user_data)->local_id_data)
+    packetdata.src_id = ((SilcClientWindow)sock->user_data)->local_id_data;
+  else 
+    packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.src_id_type = SILC_ID_CLIENT;
+  if (dst_id) {
+    packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
+    packetdata.dst_id_len = silc_id_get_len(dst_id_type);
+    packetdata.dst_id_type = dst_id_type;
+  } else {
+    packetdata.dst_id = NULL;
+    packetdata.dst_id_len = 0;
+    packetdata.dst_id_type = SILC_ID_NONE;
+  }
+  packetdata.rng = client->rng;
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_client_packet_send_prepare(client, sock, 
+                                 SILC_PACKET_HEADER_LEN +
+                                 packetdata.src_id_len + 
+                                 packetdata.dst_id_len,
+                                 packetdata.padlen,
+                                 data_len);
+
+  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Put the data to the buffer */
+  if (data && data_len)
+    silc_buffer_put(sock->outbuf, data, data_len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Compute MAC of the packet */
+  if (hmac) {
+    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                           hmac_key, hmac_key_len, mac);
+    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+    memset(mac, 0, sizeof(mac));
+  }
+
+  /* Encrypt the packet */
+  if (cipher)
+    silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
+
+  /* Pull MAC into the visible data area */
+  if (hmac)
+    silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+  SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_client_packet_send_real(client, sock, force_send);
+}
+
+/* Sends packet to a channel. Packet to channel is always encrypted
+   differently from "normal" packets. SILC header of the packet is 
+   encrypted with the next receiver's key and the rest of the packet is
+   encrypted with the channel specific key. Padding and HMAC is computed
+   with the next receiver's key. */
+
+void silc_client_packet_send_to_channel(SilcClient client, 
+                                       SilcSocketConnection sock,
+                                       SilcChannelEntry channel,
+                                       unsigned char *data, 
+                                       unsigned int data_len, 
+                                       int force_send)
+{
+  int i;
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcBuffer payload;
+  SilcPacketContext packetdata;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+  unsigned char *id_string;
+  SilcCipher cipher;
+  SilcHmac hmac;
+
+  SILC_LOG_DEBUG(("Sending packet to channel"));
+
+  if (!channel || !channel->key) {
+    silc_say(client, "Cannot talk to channel: key does not exist");
+    return;
+  }
+
+  /* Generate IV */
+  if (!channel->iv)
+    for (i = 0; i < 16; i++)
+      channel->iv[i] = silc_rng_get_byte(client->rng);
+  else
+    silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
+
+  /* Encode the channel payload */
+  payload = silc_channel_encode_payload(strlen(win->nickname), win->nickname,
+                                       data_len, data, 16, channel->iv, 
+                                       client->rng);
+  if (!payload) {
+    silc_say(client, 
+            "Error: Could not create packet to be sent to the channel");
+    return;
+  }
+
+  /* Get data used in packet header encryption, keys and stuff. Rest
+     of the packet (the payload) is, however, encrypted with the 
+     specified channel key. */
+  cipher = win->send_key;
+  hmac = win->hmac;
+  mac_len = hmac->hash->hash->hash_len;
+  hmac_key = win->hmac_key;
+  hmac_key_len = win->hmac_key_len;
+  id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+
+  /* Set the packet context pointers. The destination ID is always
+     the Channel ID of the channel. Server and router will handle the
+     distribution of the packet. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+  packetdata.src_id = win->local_id_data;
+  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.src_id_type = SILC_ID_CLIENT;
+  packetdata.dst_id = id_string;
+  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_type = SILC_ID_CHANNEL;
+  packetdata.rng = client->rng;
+  packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_client_packet_send_prepare(client, sock, 
+                                 SILC_PACKET_HEADER_LEN +
+                                 packetdata.src_id_len + 
+                                 packetdata.dst_id_len,
+                                 packetdata.padlen,
+                                 payload->len);
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Encrypt payload of the packet. This is encrypted with the channel key. */
+  channel->channel_key->cipher->encrypt(channel->channel_key->context,
+                                       payload->data, payload->data,
+                                       payload->len - 16, /* -IV_LEN */
+                                       channel->iv);
+
+  SILC_LOG_HEXDUMP(("XXX"), payload->data, payload->len);
+      
+  /* Put the actual encrypted payload data into the buffer. */
+  silc_buffer_put(sock->outbuf, payload->data, payload->len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Compute MAC of the packet */
+  silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                         hmac_key, hmac_key_len, mac);
+  silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+  memset(mac, 0, sizeof(mac));
+
+      SILC_LOG_HEXDUMP(("XXX"), sock->outbuf->data, sock->outbuf->len);
+      
+  /* Encrypt the header and padding of the packet. This is encrypted 
+     with normal session key shared with our server. */
+  silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                     packetdata.src_id_len + packetdata.dst_id_len +
+                     packetdata.padlen);
+
+  /* Pull MAC into the visible data area */
+  silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+  SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_client_packet_send_real(client, sock, force_send);
+  silc_buffer_free(payload);
+  silc_free(id_string);
+}
+
+/* Sends private message to remote client. If private message key has
+   not been set with this client then the message will be encrypted using
+   normal session keys. Private messages are special packets in SILC
+   network hence we need this own function for them. This is similiar
+   to silc_client_packet_send_to_channel except that we send private
+   message. */
+
+void silc_client_packet_send_private_message(SilcClient client,
+                                            SilcSocketConnection sock,
+                                            SilcClientEntry client_entry,
+                                            unsigned char *data, 
+                                            unsigned int data_len, 
+                                            int force_send)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcBuffer buffer;
+  SilcPacketContext packetdata;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+  unsigned int nick_len;
+  SilcCipher cipher;
+  SilcHmac hmac;
+
+  SILC_LOG_DEBUG(("Sending private message"));
+
+  /* Create private message payload */
+  nick_len = strlen(client->current_win->nickname);
+  buffer = silc_buffer_alloc(2 + nick_len + data_len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_format(buffer,
+                    SILC_STR_UI_SHORT(nick_len),
+                    SILC_STR_UI_XNSTRING(client->current_win->nickname,
+                                         nick_len),
+                    SILC_STR_UI_XNSTRING(data, data_len),
+                    SILC_STR_END);
+
+  /* If we don't have private message specific key then private messages
+     are just as any normal packet thus call normal packet sending.  If
+     the key exist then the encryption process is a bit different and
+     will be done in the rest of this function. */
+  if (!client_entry->send_key) {
+    silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
+                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+                           buffer->data, buffer->len, force_send);
+    goto out;
+  }
+
+  /* We have private message specific key */
+
+  /* Get data used in the encryption */
+  cipher = client_entry->send_key;
+  hmac = win->hmac;
+  mac_len = hmac->hash->hash->hash_len;
+  hmac_key = win->hmac_key;
+  hmac_key_len = win->hmac_key_len;
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
+  packetdata.src_id = win->local_id_data;
+  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.src_id_type = SILC_ID_CLIENT;
+  if (client_entry)
+    packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
+  else
+    packetdata.dst_id = win->local_id_data;
+  packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.dst_id_type = SILC_ID_CLIENT;
+  packetdata.rng = client->rng;
+  packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_client_packet_send_prepare(client, sock, 
+                                 SILC_PACKET_HEADER_LEN +
+                                 packetdata.src_id_len + 
+                                 packetdata.dst_id_len,
+                                 packetdata.padlen,
+                                 buffer->len);
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Encrypt payload of the packet. Encrypt with private message specific
+     key if it exist, otherwise with session key. */
+  cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
+                         buffer->len, cipher->iv);
+      
+  /* Put the actual encrypted payload data into the buffer. */
+  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Compute MAC of the packet */
+  silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                         hmac_key, hmac_key_len, mac);
+  silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+  memset(mac, 0, sizeof(mac));
+
+  SILC_LOG_HEXDUMP(("XXX"), sock->outbuf->data, sock->outbuf->len);
+      
+  /* Encrypt the header and padding of the packet. */
+  silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                     packetdata.src_id_len + packetdata.dst_id_len +
+                     packetdata.padlen);
+
+  /* Pull MAC into the visible data area */
+  silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+  SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_client_packet_send_real(client, sock, force_send);
+  silc_free(packetdata.dst_id);
+
+ out:
+  silc_free(buffer);
+}     
+
+/* Closes connection to remote end. Free's all allocated data except
+   for some information such as nickname etc. that are valid at all time. */
+
+void silc_client_close_connection(SilcClient client,
+                                 SilcSocketConnection sock)
+{
+  SilcClientWindow win;
+  int i;
+
+  /* We won't listen for this connection anymore */
+  silc_schedule_unset_listen_fd(sock->sock);
+
+  /* Unregister all tasks */
+  silc_task_unregister_by_fd(client->io_queue, sock->sock);
+  silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
+
+  /* Close the actual connection */
+  silc_net_close_connection(sock->sock);
+
+  silc_say(client, "Closed connection to host %s", sock->hostname ?
+          sock->hostname : sock->ip);
+
+  /* Free everything */
+  if (sock->user_data) {
+    win = (SilcClientWindow)sock->user_data;
+
+    /* Clear ID caches */
+    for (i = 0; i < 96; i++)
+      silc_idcache_del_all(&win->client_id_cache[i], 
+                          win->client_id_cache_count[i]);
+    for (i = 0; i < 96; i++)
+      silc_idcache_del_all(&win->channel_id_cache[i], 
+                          win->channel_id_cache_count[i]);
+
+    /* Free data */
+    if (win->remote_host)
+      silc_free(win->remote_host);
+    if (win->local_id)
+      silc_free(win->local_id);
+    if (win->local_id_data)
+      silc_free(win->local_id_data);
+    if (win->send_key)
+      silc_cipher_free(win->send_key);
+    if (win->receive_key)
+      silc_cipher_free(win->receive_key);
+    if (win->public_key)
+      silc_pkcs_free(win->public_key);
+    if (win->hmac)
+      silc_hmac_free(win->hmac);
+    if (win->hmac_key) {
+      memset(win->hmac_key, 0, win->hmac_key_len);
+      silc_free(win->hmac_key);
+    }
+
+    win->sock = NULL;
+    win->remote_port = 0;
+    win->remote_type = 0;
+    win->send_key = NULL;
+    win->receive_key = NULL;
+    win->public_key = NULL;
+    win->hmac = NULL;
+    win->hmac_key = NULL;
+    win->hmac_key_len = 0;
+    win->local_id = NULL;
+    win->local_id_data = NULL;
+    win->remote_host = NULL;
+  }
+
+  if (sock->protocol) {
+    silc_protocol_free(sock->protocol);
+    sock->protocol = NULL;
+  }
+  silc_socket_free(sock);
+}
+
+/* Called when we receive disconnection packet from server. This 
+   closes our end properly and displays the reason of the disconnection
+   on the screen. */
+
+void silc_client_disconnected_by_server(SilcClient client,
+                                       SilcSocketConnection sock,
+                                       SilcBuffer message)
+{
+  char *msg;
+
+  SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
+
+  msg = silc_calloc(message->len + 1, sizeof(char));
+  memcpy(msg, message->data, message->len);
+  silc_say(client, msg);
+  silc_free(msg);
+
+  SILC_SET_DISCONNECTED(sock);
+  silc_client_close_connection(client, sock);
+}
+
+/* Received error message from server. Display it on the screen. 
+   We don't take any action what so ever of the error message. */
+
+void silc_client_error_by_server(SilcClient client,
+                                SilcSocketConnection sock,
+                                SilcBuffer message)
+{
+  char *msg;
+
+  msg = silc_calloc(message->len + 1, sizeof(char));
+  memcpy(msg, message->data, message->len);
+  silc_say(client, msg);
+  silc_free(msg);
+}
+
+/* Received notify message from server */
+
+void silc_client_notify_by_server(SilcClient client,
+                                 SilcSocketConnection sock,
+                                 SilcBuffer message)
+{
+  char *msg;
+
+  msg = silc_calloc(message->len + 1, sizeof(char));
+  memcpy(msg, message->data, message->len);
+  silc_say(client, msg);
+  silc_free(msg);
+}
+
+/* Processes the received new Client ID from server. Old Client ID is
+   deleted from cache and new one is added. */
+
+void silc_client_receive_new_id(SilcClient client,
+                               SilcSocketConnection sock,
+                               unsigned char *id_string)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  char *nickname = win->nickname;
+
+#define CIDC(x) win->client_id_cache[(x) - 32]
+#define CIDCC(x) win->client_id_cache_count[(x) - 32]
+
+  /* Delete old ID from ID cache */
+  silc_idcache_del_by_id(CIDC(nickname[0]), CIDCC(nickname[0]),
+                        SILC_ID_CLIENT, win->local_id);
+  
+  /* Save the new ID */
+  if (win->local_id)
+    silc_free(win->local_id);
+  win->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+  if (win->local_id_data)
+    silc_free(win->local_id_data);
+  win->local_id_data = 
+    silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+  memcpy(win->local_id_data, id_string, SILC_ID_CLIENT_LEN);
+  win->local_id_data_len = SILC_ID_CLIENT_LEN;
+  if (!win->local_entry)
+    win->local_entry = silc_calloc(1, sizeof(*win->local_entry));
+  win->local_entry->nickname = win->nickname;
+  win->local_entry->id = win->local_id;
+  
+  /* Put it to the ID cache */
+  CIDCC(nickname[0]) = silc_idcache_add(&CIDC(nickname[0]), 
+                                       CIDCC(nickname[0]),
+                                       win->nickname, SILC_ID_CLIENT, 
+                                       win->local_id, 
+                                       (void *)win->local_entry);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Processed received Channel ID for a channel. This is called when client
+   joins to channel and server replies with channel ID. The ID is cached. */
+
+void silc_client_new_channel_id(SilcClient client,
+                               SilcSocketConnection sock,
+                               char *channel_name,
+                               unsigned char *id_string)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcChannelID *id;
+  SilcChannelEntry channel;
+
+  SILC_LOG_DEBUG(("New channel ID"));
+
+#define CIDC(x) win->channel_id_cache[(x) - 32]
+#define CIDCC(x) win->channel_id_cache_count[(x) - 32]
+
+  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+  channel = silc_calloc(1, sizeof(*channel));
+  channel->channel_name = channel_name;
+  channel->id = id;
+  win->current_channel = channel;
+  
+  /* Put it to the ID cache */
+  CIDCC(channel_name[0]) = silc_idcache_add(&CIDC(channel_name[0]), 
+                                           CIDCC(channel_name[0]),
+                                           channel_name, SILC_ID_CHANNEL, 
+                                           id, (void *)channel);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Processes received key for channel. The received key will be used
+   to protect the traffic on the channel for now on. Client must receive
+   the key to the channel before talking on the channel is possible. 
+   This is the key that server has generated, this is not the channel
+   private key, it is entirely local setting. */
+
+void silc_client_receive_channel_key(SilcClient client,
+                                    SilcSocketConnection sock,
+                                    SilcBuffer packet)
+{
+  int i;
+  unsigned char *id_string, *key, *cipher;
+  unsigned int key_len;
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcChannelID *id;
+  SilcIDCache *id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcChannelKeyPayload payload;
+
+  SILC_LOG_DEBUG(("Received key for channel"));
+  
+#define CIDC(x) win->channel_id_cache[(x)]
+#define CIDCC(x) win->channel_id_cache_count[(x)]
+
+  payload = silc_channel_key_parse_payload(packet);
+  if (!payload)
+    return;
+
+  id_string = silc_channel_key_get_id(payload, NULL);
+  if (!id_string) {
+    silc_channel_key_free_payload(payload);
+    return;
+  }
+  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+
+  /* Find channel. XXX: This is bad and slow. */ 
+  for (i = 0; i < 96; i++) {
+    if (CIDC(i) == NULL)
+      continue;
+    if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)id, 
+                               SILC_ID_CHANNEL, &id_cache))
+      break;
+  }
+
+ if (!id_cache)
+    goto out;
+
+  /* Save the key */
+  key = silc_channel_key_get_key(payload, &key_len);
+  cipher = silc_channel_key_get_cipher(payload, NULL);
+
+  channel = (SilcChannelEntry)id_cache->context;
+  channel->key_len = key_len;
+  channel->key = silc_calloc(key_len, sizeof(*channel->key));
+  memcpy(channel->key, key, key_len);
+
+  silc_cipher_alloc(cipher, &channel->channel_key);
+  if (!channel->channel_key) {
+    silc_say(client, "Cannot talk to channel: unsupported cipher %s", cipher);
+    goto out;
+  }
+  channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                       key, key_len);
+
+  /* Client is now joined to the channel */
+  channel->on_channel = TRUE;
+
+ out:
+  silc_free(id);
+  silc_channel_key_free_payload(payload);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Process received message to a channel (or from a channel, really). This
+   decrypts the channel message with channel specific key and parses the
+   channel payload. Finally it displays the message on the screen. */
+
+void silc_client_channel_message(SilcClient client, 
+                                SilcSocketConnection sock, 
+                                SilcPacketContext *packet)
+{
+  int i;
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcBuffer buffer = packet->buffer;
+  SilcChannelPayload payload = NULL;
+  SilcChannelID *id = NULL;
+  SilcChannelEntry channel;
+  SilcIDCache *id_cache = NULL;
+
+#define CIDC(x) win->channel_id_cache[(x)]
+#define CIDCC(x) win->channel_id_cache_count[(x)]
+
+  /* Sanity checks */
+  if (packet->dst_id_type != SILC_ID_CHANNEL)
+    goto out;
+
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+
+  /* Find the channel entry from channels on this window */
+  for (i = 0; i < 96; i++) {
+    if (CIDC(i) == NULL)
+      continue;
+    if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)id, 
+                               SILC_ID_CHANNEL, &id_cache))
+      break;
+  }
+
+  if (!id_cache)
+    goto out;
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  /* Decrypt the channel message payload. Push the IV out of the way,
+     since it is not encrypted (after pushing buffer->tail has the IV). */
+  silc_buffer_push_tail(buffer, 16);
+  channel->channel_key->cipher->decrypt(channel->channel_key->context,
+                                       buffer->data, buffer->data,
+                                       buffer->len, buffer->tail);
+  silc_buffer_pull_tail(buffer, 16);
+
+  /* Parse the channel message payload */
+  payload = silc_channel_parse_payload(buffer);
+  if (!payload)
+    goto out;
+
+  /* Display the message on screen */
+  if (packet->src_id_type == SILC_ID_CLIENT)
+    /* Message from client */
+    silc_print(client, "<%s> %s", silc_channel_get_nickname(payload, NULL),
+              silc_channel_get_data(payload, NULL));
+  else
+    /* Message from server */
+    silc_say(client, "%s", silc_channel_get_data(payload, NULL));
+
+ out:
+  if (id)
+    silc_free(id);
+  if (payload)
+    silc_channel_free_payload(payload);
+#undef CIDC
+#undef CIDCC
+}
diff --git a/apps/silc/client.h b/apps/silc/client.h
new file mode 100644 (file)
index 0000000..661bd83
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+
+  client.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+/* Window structure used in client to associate all the important
+   connection (window) specific data to this structure. How the window
+   actually appears on the screen in handeled by the silc_screen*
+   routines in screen.c. */
+typedef struct {
+  /*
+   * Local data 
+   */
+  char *nickname;
+
+  /* Local client ID for this connection */
+  SilcClientID *local_id;
+
+  /* Decoded local ID so that the above defined ID would not have
+     to be decoded for every packet. */
+  unsigned char *local_id_data;
+  unsigned int local_id_data_len;
+
+  /* Own client entry. */
+  SilcClientEntry local_entry;
+
+  /*
+   * Remote data 
+   */
+  char *remote_host;
+  int remote_port;
+  int remote_type;
+
+  /* Remote client ID for this connection */
+  SilcClientID *remote_id;
+
+  /* Remote local ID so that the above defined ID would not have
+     to be decoded for every packet. */
+  unsigned char *remote_id_data;
+  unsigned int remote_id_data_len;
+
+  /*
+   * Common data 
+   */
+  /* Keys */
+  SilcCipher send_key;
+  SilcCipher receive_key;
+  SilcPKCS public_key;
+  SilcHmac hmac;
+  unsigned char *hmac_key;
+  unsigned int hmac_key_len;
+
+  /* Client ID and Channel ID cache. Messages transmitted in SILC network
+     are done using different unique ID's. These are the cache for
+     thoses ID's used in the communication. */
+  SilcIDCache *client_id_cache[96];
+  unsigned int client_id_cache_count[96];
+  SilcIDCache *channel_id_cache[96];
+  unsigned int channel_id_cache_count[96];
+  SilcIDCache *server_id_cache;
+  unsigned int server_id_cache_count;
+
+  /* Current channel on window. All channel's are saved (allocated) into
+     the cache entries. */
+  SilcChannelEntry current_channel;
+
+  /* Socket connection object for this connection (window). This
+     object will have a back-pointer to this window object for fast
+     referencing (sock->user_data). */
+  SilcSocketConnection sock;
+
+  /* The actual physical screen. This data is handled by the
+     screen handling routines. */
+  void *screen;
+} *SilcClientWindow;
+
+typedef struct {
+  char *username;
+  char *realname;
+
+  /* SILC client task queues */
+  SilcTaskQueue io_queue;
+  SilcTaskQueue timeout_queue;
+  SilcTaskQueue generic_queue;
+
+  /* Input buffer that holds the characters user types. This is
+     used only to store the typed chars for a while. */
+  SilcBuffer input_buffer;
+
+  /* Table of windows in client. All the data, including connection
+     specific data, is saved in here. */
+  SilcClientWindow *windows;
+  unsigned int windows_count;
+
+  /* Currently active window. This is pointer to the window table 
+     defined above. This must never be free'd directly. */
+  SilcClientWindow current_win;
+
+  /* The SILC client screen object */
+  SilcScreen screen;
+
+  /* Generic cipher and hash objects */
+  SilcCipher none_cipher;
+  SilcHash md5hash;
+  SilcHash sha1hash;
+  SilcHmac md5hmac;
+  SilcHmac sha1hmac;
+
+  /* Configuration object */
+  SilcClientConfig config;
+
+  /* Random Number Generator */
+  SilcRng rng;
+
+#ifdef SILC_SIM
+  /* SIM (SILC Module) table */
+  SilcSimContext **sim;
+  unsigned int sim_count;
+#endif
+} SilcClientObject;
+
+typedef SilcClientObject *SilcClient;
+
+/* Macros */
+
+#ifndef CTRL
+#define CTRL(x) ((x) & 0x1f)   /* Ctrl+x */
+#endif
+
+/* Registers generic task for file descriptor for reading from network and
+   writing to network. As being generic task the actual task is allocated 
+   only once and after that the same task applies to all registered fd's. */
+#define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd)                     \
+do {                                                                   \
+  SilcTask tmptask = silc_task_register(client->generic_queue, (fd),   \
+                                       silc_client_packet_process,     \
+                                       context, 0, 0,                  \
+                                       SILC_TASK_GENERIC,              \
+                                       SILC_TASK_PRI_NORMAL);          \
+  silc_task_set_iotype(tmptask, SILC_TASK_WRITE);                      \
+} while(0)
+
+#define SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd)               \
+do {                                                           \
+  silc_schedule_set_listen_fd((fd), (1L << SILC_TASK_READ));   \
+} while(0)                                                     \
+     
+#define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(fd)              \
+do {                                                           \
+  silc_schedule_set_listen_fd((fd), ((1L << SILC_TASK_READ) |  \
+                                    (1L << SILC_TASK_WRITE))); \
+} while(0)
+
+/* Finds socket connection object by file descriptor */
+#define SILC_CLIENT_GET_SOCK(__x, __fd, __sock)                \
+do {                                                   \
+  int __i;                                             \
+                                                       \
+  for (__i = 0; __i < (__x)->windows_count; __i++)     \
+    if ((__x)->windows[__i]->sock->sock == (__fd))     \
+      break;                                           \
+                                                       \
+  if (__i >= (__x)->windows_count)                     \
+    (__sock) = NULL;                                   \
+ (__sock) = (__x)->windows[__i]->sock;                 \
+} while(0)
+
+/* Returns TRUE if windows is currently active window */
+#define SILC_CLIENT_IS_CURRENT_WIN(__x, __win) ((__x)->current_win == (__win))
+
+/* Prototypes */
+int silc_client_alloc(SilcClient *new_client);
+void silc_client_free(SilcClient client);
+int silc_client_init(SilcClient client);
+void silc_client_stop(SilcClient client);
+void silc_client_run(SilcClient client);
+void silc_client_parse_command_line(unsigned char *buffer, 
+                                   unsigned char ***parsed,
+                                   unsigned int **parsed_lens,
+                                   unsigned int **parsed_types,
+                                   unsigned int *parsed_num,
+                                   unsigned int max_args);
+int silc_client_connect_to_server(SilcClient client, int port,
+                                 char *host);
+void silc_client_packet_send(SilcClient client, 
+                            SilcSocketConnection sock,
+                            SilcPacketType type, 
+                            void *dst_id,
+                            SilcIdType dst_id_type,
+                            SilcCipher cipher,
+                            SilcHmac hmac,
+                            unsigned char *data, 
+                            unsigned int data_len, 
+                            int force_send);
+void silc_client_packet_send_to_channel(SilcClient client, 
+                                       SilcSocketConnection sock,
+                                       SilcChannelEntry channel,
+                                       unsigned char *data, 
+                                       unsigned int data_len, 
+                                       int force_send);
+void silc_client_packet_send_private_message(SilcClient client,
+                                            SilcSocketConnection sock,
+                                            SilcClientEntry client_entry,
+                                            unsigned char *data, 
+                                            unsigned int data_len, 
+                                            int force_send);
+void silc_client_close_connection(SilcClient client,
+                                 SilcSocketConnection sock);
+void silc_client_disconnected_by_server(SilcClient client,
+                                       SilcSocketConnection sock,
+                                       SilcBuffer message);
+void silc_client_error_by_server(SilcClient client,
+                                SilcSocketConnection sock,
+                                SilcBuffer message);
+void silc_client_notify_by_server(SilcClient client,
+                                 SilcSocketConnection sock,
+                                 SilcBuffer message);
+void silc_client_receive_new_id(SilcClient client,
+                               SilcSocketConnection sock,
+                               unsigned char *id_string);
+void silc_client_new_channel_id(SilcClient client,
+                               SilcSocketConnection sock,
+                               char *channel_name,
+                               unsigned char *id_string);
+void silc_client_receive_channel_key(SilcClient client,
+                                    SilcSocketConnection sock,
+                                    SilcBuffer packet);
+void silc_client_channel_message(SilcClient client, 
+                                SilcSocketConnection sock, 
+                                SilcPacketContext *packet);
+#endif
diff --git a/apps/silc/clientconfig.c b/apps/silc/clientconfig.c
new file mode 100644 (file)
index 0000000..7cdd815
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+
+  serverconfig.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+#include "clientconfig.h"
+
+/* 
+   All possible configuration sections for SILC client.
+*/
+SilcClientConfigSection silc_client_config_sections[] = {
+  { "[cipher]", 
+    SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER, 4 },
+  { "[pkcs]", 
+    SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS, 2 },
+  { "[hash]", 
+    SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION, 4 },
+  { "[connection]", 
+    SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION, 4 },
+  { "[commands]", 
+    SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND, 0 },
+  
+  { NULL, SILC_CLIENT_CONFIG_SECTION_TYPE_NONE, 0 }
+};
+
+/* Allocates a new configuration object, opens configuration file and
+   parses the file. The parsed data is returned to the newly allocated
+   configuration object. */
+
+SilcClientConfig silc_client_config_alloc(char *filename)
+{
+  SilcClientConfig new;
+  SilcBuffer buffer;
+  SilcClientConfigParse config_parse;
+
+  SILC_LOG_DEBUG(("Allocating new configuration object"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    fprintf(stderr, "Could not allocate new configuration object");
+    return NULL;
+  }
+
+  new->filename = filename;
+
+  /* Open configuration file and parse it */
+  config_parse = NULL;
+  buffer = NULL;
+  silc_config_open(filename, &buffer);
+  if (!buffer)
+    goto fail;
+  if ((silc_client_config_parse(new, buffer, &config_parse)) == FALSE)
+    goto fail;
+  if ((silc_client_config_parse_lines(new, config_parse)) == FALSE)
+    goto fail;
+
+  silc_free(buffer);
+
+  return new;
+
+ fail:
+  silc_free(new);
+  return NULL;
+}
+
+/* Free's a configuration object. */
+
+void silc_client_config_free(SilcClientConfig config)
+{
+  if (config) {
+
+    silc_free(config);
+  }
+}
+
+/* Parses the the buffer and returns the parsed lines into return_config
+   argument. The return_config argument doesn't have to be initialized 
+   before calling this. It will be initialized during the parsing. The
+   buffer sent as argument can be safely free'd after this function has
+   succesfully returned. */
+
+int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer, 
+                            SilcClientConfigParse *return_config)
+{
+  int i, begin;
+  unsigned int linenum;
+  char line[1024], *cp;
+  SilcClientConfigSection *cptr = NULL;
+  SilcClientConfigParse parse = *return_config, first = NULL;
+
+  SILC_LOG_DEBUG(("Parsing configuration file"));
+
+  begin = 0;
+  linenum = 0;
+  while((begin = silc_gets(line, sizeof(line), 
+                          buffer->data, buffer->len, begin)) != EOF) {
+    cp = line;
+    linenum++;
+
+    /* Check for bad line */
+    if (silc_check_line(cp))
+      continue;
+
+    /* Remove tabs and whitespaces from the line */
+    if (strchr(cp, '\t')) {
+      i = 0;
+      while(strchr(cp + i, '\t')) {
+       *strchr(cp + i, '\t') = ' ';
+       i++;
+      }
+    }
+    for (i = 0; i < strlen(cp); i++) {
+      if (cp[i] != ' ') {
+       if (i)
+         cp++;
+       break;
+      }
+      cp++;
+    }
+
+    /* Parse line */
+    switch(cp[0]) {
+    case '[':
+      /*
+       * Start of a section
+       */
+
+      /* Remove new line sign */
+      if (strchr(cp, '\n'))
+       *strchr(cp, '\n') = '\0';
+      
+      /* Check for matching sections */
+      for (cptr = silc_client_config_sections; cptr->section; cptr++)
+       if (!strcmp(cp, cptr->section))
+         break;
+
+      if (!cptr->section) {
+       fprintf(stderr, "%s:%d: Unknown section `%s'\n", 
+                       config->filename, linenum, cp);
+       return FALSE;
+      }
+
+      break;
+    default:
+      /*
+       * Start of a configuration line
+       */
+
+      /* Handle config section */
+      if (cptr->type != SILC_CLIENT_CONFIG_SECTION_TYPE_NONE) {
+       
+       if (strchr(cp, '\n'))
+           *strchr(cp, '\n') = ':';
+
+       if (parse == NULL) {
+         parse = silc_calloc(1, sizeof(*parse));
+         parse->line = NULL;
+         parse->section = NULL;
+         parse->next = NULL;
+         parse->prev = NULL;
+       } else {
+         if (parse->next == NULL) {
+           parse->next = silc_calloc(1, sizeof(*parse->next));
+           parse->next->line = NULL;
+           parse->next->section = NULL;
+           parse->next->next = NULL;
+           parse->next->prev = parse;
+           parse = parse->next;
+         }
+       }
+       
+       if (first == NULL)
+         first = parse;
+
+       /* Add the line to parsing structure for further parsing. */
+       if (parse) {
+         parse->section = cptr;
+         parse->line = silc_buffer_alloc(strlen(cp) + 1);
+         parse->linenum = linenum;
+         silc_buffer_pull_tail(parse->line, strlen(cp));
+         silc_buffer_put(parse->line, cp, strlen(cp));
+       }
+      }
+      break;
+    }
+  }
+  
+  /* Set the return_config argument to its first value so that further
+     parsing can be started from the first line. */
+  *return_config = first;
+
+  return TRUE;
+}
+
+/* Parses the lines earlier read from configuration file. The config object
+   must not be initialized, it will be initialized in this function. The
+   parse_config argument is uninitialized automatically during this
+   function. */
+
+int silc_client_config_parse_lines(SilcClientConfig config, 
+                                  SilcClientConfigParse parse_config)
+{
+  int ret, check = FALSE;
+  char *tmp;
+  SilcClientConfigParse pc = parse_config;
+  SilcBuffer line;
+
+  SILC_LOG_DEBUG(("Parsing configuration lines"));
+  
+  if (!config)
+    return FALSE;
+  
+  while(pc) {
+    check = FALSE;
+    line = pc->line;
+
+    /* Get number of tokens in line (command section is handeled
+       specially and has no tokens at all). */
+    ret = silc_config_check_num_token(line);
+    if (ret != pc->section->maxfields && 
+       pc->section->type != SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND) {
+      /* Bad line */
+      fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
+             config->filename, pc->linenum, ret, 
+             pc->section->maxfields);
+      break;
+    }
+
+    /* Parse the line */
+    switch(pc->section->type) {
+    case SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER:
+
+      if (!config->cipher) {
+       config->cipher = silc_calloc(1, sizeof(*config->cipher));
+       config->cipher->next = NULL;
+       config->cipher->prev = NULL;
+      } else {
+       if (!config->cipher->next) {
+         config->cipher->next = 
+           silc_calloc(1, sizeof(*config->cipher->next));
+         config->cipher->next->next = NULL;
+         config->cipher->next->prev = config->cipher;
+         config->cipher = config->cipher->next;
+       }
+      }
+
+      /* Get cipher name */
+      ret = silc_config_get_token(line, &config->cipher->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Cipher name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+
+      /* Get module name */
+      config->cipher->sim_name = NULL;
+      ret = silc_config_get_token(line, &config->cipher->sim_name);
+      if (ret < 0)
+       break;
+
+      /* Get block length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Cipher block length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->cipher->block_len = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get key length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Cipher key length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->cipher->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      break;
+
+    case SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS:
+
+      if (!config->pkcs) {
+       config->pkcs = silc_calloc(1, sizeof(*config->pkcs));
+       config->pkcs->next = NULL;
+       config->pkcs->prev = NULL;
+      } else {
+       if (!config->pkcs->next) {
+         config->pkcs->next = 
+           silc_calloc(1, sizeof(*config->pkcs->next));
+         config->pkcs->next->next = NULL;
+         config->pkcs->next->prev = config->pkcs;
+         config->pkcs = config->pkcs->next;
+       }
+      }
+
+      /* Get PKCS name */
+      ret = silc_config_get_token(line, &config->pkcs->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: PKCS name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+
+      /* Get key length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: PKCS key length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->pkcs->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      break;
+
+    case SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION:
+
+      if (!config->hash_func) {
+       config->hash_func = silc_calloc(1, sizeof(*config->hash_func));
+       config->hash_func->next = NULL;
+       config->hash_func->prev = NULL;
+      } else {
+       if (!config->hash_func->next) {
+         config->hash_func->next = 
+           silc_calloc(1, sizeof(*config->hash_func->next));
+         config->hash_func->next->next = NULL;
+         config->hash_func->next->prev = config->hash_func;
+         config->hash_func = config->hash_func->next;
+       }
+      }
+
+      /* Get Hash function name */
+      ret = silc_config_get_token(line, &config->hash_func->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      
+      /* Get Hash function module name */
+      config->hash_func->sim_name = NULL;
+      ret = silc_config_get_token(line, &config->hash_func->sim_name);
+      if (ret < 0)
+       break;
+
+      /* Get block length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function block length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->hash_func->block_len = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get hash length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->hash_func->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      break;
+
+    case SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION:
+
+      if (!config->conns) {
+       config->conns = silc_calloc(1, sizeof(*config->conns));
+       config->conns->next = NULL;
+       config->conns->prev = NULL;
+      } else {
+       if (!config->conns->next) {
+         config->conns->next = silc_calloc(1, sizeof(*config->conns));
+         config->conns->next->next = NULL;
+         config->conns->next->prev = config->conns;
+         config->conns = config->conns->next;
+       }
+      }
+      
+      /* Get host */
+      ret = silc_config_get_token(line, &config->conns->host);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any host */
+       config->conns->host = strdup("*");
+
+      /* Get authentication method */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       if (strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD) &&
+           strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY)) {
+         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+
+       if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PASSWD))
+         config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+       if (!strcmp(tmp, SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY))
+         config->conns->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+       silc_free(tmp);
+      }
+
+      /* Get authentication data */
+      ret = silc_config_get_token(line, &config->conns->auth_data);
+      if (ret < 0)
+       break;
+
+      /* Get port */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->conns->port = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      break;
+
+    case SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND:
+
+      if (!config->commands) {
+       config->commands = silc_calloc(1, sizeof(*config->commands));
+       config->commands->next = NULL;
+       config->commands->prev = NULL;
+      } else {
+       if (!config->commands->next) {
+         config->commands->next = silc_calloc(1, sizeof(*config->commands));
+         config->commands->next->next = NULL;
+         config->commands->next->prev = config->commands;
+         config->commands = config->commands->next;
+       }
+      }
+      
+      /* Get command line (this may include parameters as well. They
+        will be parsed later with standard command parser when
+        executing particular command.) */
+      config->commands->command = strdup(line->data);
+      if (ret < 0)
+       break;
+
+      check = TRUE;
+      break;
+
+    case SILC_CLIENT_CONFIG_SECTION_TYPE_NONE:
+    default:
+      break;
+    }
+
+    /* Check for error */
+    if (check == FALSE) {
+      /* Line could not be parsed */
+      fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
+      break;
+    }
+
+    pc = pc->next;
+  }
+
+  if (check == FALSE)
+    return FALSE;;
+
+  /* Before returning all the lists in the config object must be set
+     to their first values (the last value is first here). */
+  while (config->cipher && config->cipher->prev)
+    config->cipher = config->cipher->prev;
+  while (config->pkcs && config->pkcs->prev)
+    config->pkcs = config->pkcs->prev;
+  while (config->hash_func && config->hash_func->prev)
+    config->hash_func = config->hash_func->prev;
+  while (config->conns && config->conns->prev)
+    config->conns = config->conns->prev;
+  while (config->commands && config->commands->prev)
+    config->commands = config->commands->prev;
+  
+  SILC_LOG_DEBUG(("Done"));
+  
+  return TRUE;
+}
+
+/* Registers configured ciphers. These can then be allocated by the
+   client when needed. */
+
+void silc_client_config_register_ciphers(SilcClientConfig config)
+{
+  SilcClientConfigSectionAlg *alg;
+  SilcClient client = (SilcClient)config->client;
+
+  SILC_LOG_DEBUG(("Registering configured ciphers"));
+
+  alg = config->cipher;
+  while(alg) {
+
+    if (!alg->sim_name) {
+      /* Crypto module is supposed to be built in. Nothing to be done
+        here except to test that the cipher really is built in. */
+      SilcCipher tmp = NULL;
+
+      if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
+       SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
+       silc_client_stop(client);
+       exit(1);
+      }
+      silc_cipher_free(tmp);
+
+#ifdef SILC_SIM
+    } else {
+      /* Load (try at least) the crypto SIM module */
+      SilcCipherObject cipher;
+      SilcSimContext *sim;
+
+      memset(&cipher, 0, sizeof(cipher));
+      cipher.name = alg->alg_name;
+      cipher.block_len = alg->block_len;
+      cipher.key_len = alg->key_len * 8;
+
+      sim = silc_sim_alloc();
+      sim->type = SILC_SIM_CIPHER;
+      sim->libname = alg->sim_name;
+
+      if ((silc_sim_load(sim))) {
+       cipher.set_key = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+                                               SILC_CIPHER_SIM_SET_KEY));
+       SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
+       cipher.set_key_with_string = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+                                               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
+       SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
+       cipher.encrypt = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_CIPHER_SIM_ENCRYPT_CBC));
+       SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
+        cipher.decrypt = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_CIPHER_SIM_DECRYPT_CBC));
+       SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
+        cipher.context_len = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_CIPHER_SIM_CONTEXT_LEN));
+       SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
+
+       /* Put the SIM to the table of all SIM's in client */
+       client->sim = silc_realloc(client->sim,
+                                  sizeof(*client->sim) * 
+                                  (client->sim_count + 1));
+       client->sim[client->sim_count] = sim;
+       client->sim_count++;
+      } else {
+       SILC_LOG_ERROR(("Error configuring ciphers"));
+       silc_client_stop(client);
+       exit(1);
+      }
+
+      /* Register the cipher */
+      silc_cipher_register(&cipher);
+#endif
+    }
+
+    alg = alg->next;
+  }
+}
+
+/* Registers configured PKCS's. */
+/* XXX: This really doesn't do anything now since we have statically
+   registered our PKCS's. This should be implemented when PKCS works
+   as SIM's. This checks now only that the PKCS user requested is 
+   really out there. */
+
+void silc_client_config_register_pkcs(SilcClientConfig config)
+{
+  SilcClientConfigSectionAlg *alg = config->pkcs;
+  SilcClient client = (SilcClient)config->client;
+  SilcPKCS tmp = NULL;
+
+  SILC_LOG_DEBUG(("Registering configured PKCS"));
+
+  while(alg) {
+
+    if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
+      SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
+      silc_client_stop(client);
+      exit(1);
+    }
+    silc_free(tmp);
+
+    alg = alg->next;
+  }
+}
+
+/* Registers configured hash functions. These can then be allocated by the
+   client when needed. */
+
+void silc_client_config_register_hashfuncs(SilcClientConfig config)
+{
+  SilcClientConfigSectionAlg *alg;
+  SilcClient client = (SilcClient)config->client;
+
+  SILC_LOG_DEBUG(("Registering configured hash functions"));
+
+  alg = config->hash_func;
+  while(alg) {
+
+    if (!alg->sim_name) {
+      /* Hash module is supposed to be built in. Nothing to be done
+        here except to test that the hash function really is built in. */
+      SilcHash tmp = NULL;
+
+      if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
+       SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
+       silc_client_stop(client);
+       exit(1);
+      }
+      silc_free(tmp);
+
+#ifdef SILC_SIM
+    } else {
+      /* Load (try at least) the hash SIM module */
+      SilcHashObject hash;
+      SilcSimContext *sim;
+
+      memset(&hash, 0, sizeof(hash));
+      hash.name = alg->alg_name;
+      hash.block_len = alg->block_len;
+      hash.hash_len = alg->key_len;
+
+      sim = silc_sim_alloc();
+      sim->type = SILC_SIM_HASH;
+      sim->libname = alg->sim_name;
+
+      if ((silc_sim_load(sim))) {
+       hash.init = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+                                               SILC_HASH_SIM_INIT));
+       SILC_LOG_DEBUG(("init=%p", hash.init));
+       hash.update = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_HASH_SIM_UPDATE));
+       SILC_LOG_DEBUG(("update=%p", hash.update));
+        hash.final = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_HASH_SIM_FINAL));
+       SILC_LOG_DEBUG(("final=%p", hash.final));
+        hash.context_len = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_HASH_SIM_CONTEXT_LEN));
+       SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
+
+       /* Put the SIM to the table of all SIM's in client */
+       client->sim = silc_realloc(client->sim,
+                                  sizeof(*client->sim) * 
+                                  (client->sim_count + 1));
+       client->sim[client->sim_count] = sim;
+       client->sim_count++;
+      } else {
+       SILC_LOG_ERROR(("Error configuring hash functions"));
+       silc_client_stop(client);
+       exit(1);
+      }
+
+      /* Register the cipher */
+      silc_hash_register(&hash);
+#endif
+    }
+
+    alg = alg->next;
+  }
+}
+
+
+SilcClientConfigSectionConnection *
+silc_client_config_find_connection(SilcClientConfig config, 
+                                  char *host, int port)
+{
+  int i;
+  SilcClientConfigSectionConnection *conn = NULL;
+
+  SILC_LOG_DEBUG(("Finding connection"));
+
+  if (!host)
+    return NULL;
+
+  if (!config->conns)
+    return NULL;
+
+  conn = config->conns;
+  for (i = 0; conn; i++) {
+    if (silc_string_compare(conn->host, host))
+      break;
+    conn = conn->next;
+  }
+
+  if (!conn)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Found match"));
+
+  return conn;
+}
diff --git a/apps/silc/clientconfig.h b/apps/silc/clientconfig.h
new file mode 100644 (file)
index 0000000..f2c7a4a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+
+  clientconfig.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENTCONFIG_H
+#define CLIENTCONFIG_H
+
+/* Holds information of configured algorithms */
+typedef struct SilcClientConfigSectionAlgStruct {
+  char *alg_name;
+  char *sim_name;
+  unsigned int block_len;
+  unsigned int key_len;
+  struct SilcClientConfigSectionAlgStruct *next;
+  struct SilcClientConfigSectionAlgStruct *prev;
+#define SILC_CLIENT_CONFIG_MODNAME "builtin"
+} SilcClientConfigSectionAlg;
+
+/* Holds all server connections from config file */
+typedef struct SilcClientConfigSectionConnectionStruct {
+  char *host;
+  int auth_meth;
+  char *auth_data;
+  unsigned short port;
+  struct SilcClientConfigSectionConnectionStruct *next;
+  struct SilcClientConfigSectionConnectionStruct *prev;
+#define SILC_CLIENT_CONFIG_AUTH_METH_PASSWD "passwd"
+#define SILC_CLIENT_CONFIG_AUTH_METH_PUBKEY "pubkey"
+} SilcClientConfigSectionConnection;
+
+/* Holds all given commands from config file */
+typedef struct SilcClientConfigSectionCommandStruct {
+  char *command;
+  struct SilcClientConfigSectionCommandStruct *next;
+  struct SilcClientConfigSectionCommandStruct *prev;
+} SilcClientConfigSectionCommand;
+
+/* 
+   SILC Client Config object.
+
+   This object holds all the data parsed from the SILC client configuration
+   file. This is mainly used at the initialization of the client.
+
+*/
+typedef struct {
+  /* Pointer back to the client */
+  void *client;
+
+  /* Filename of the configuration file */
+  char *filename;
+
+  /* Configuration sections */
+  SilcClientConfigSectionAlg *cipher;
+  SilcClientConfigSectionAlg *pkcs;
+  SilcClientConfigSectionAlg *hash_func;
+  SilcClientConfigSectionConnection *conns;
+  SilcClientConfigSectionCommand *commands;
+} SilcClientConfigObject;
+
+typedef SilcClientConfigObject *SilcClientConfig;
+
+/* Configuration section type enumerations. */
+typedef enum {
+  SILC_CLIENT_CONFIG_SECTION_TYPE_NONE = 0,
+  SILC_CLIENT_CONFIG_SECTION_TYPE_CIPHER,
+  SILC_CLIENT_CONFIG_SECTION_TYPE_PKCS,
+  SILC_CLIENT_CONFIG_SECTION_TYPE_HASH_FUNCTION,
+  SILC_CLIENT_CONFIG_SECTION_TYPE_CONNECTION,
+  SILC_CLIENT_CONFIG_SECTION_TYPE_COMMAND = 253, /* Special section */
+} SilcClientConfigSectionType;
+
+/* SILC Configuration Section structure. */
+typedef struct {
+  const char *section;
+  SilcClientConfigSectionType type;
+  unsigned int maxfields;
+} SilcClientConfigSection;
+
+/* List of all possible config sections in SILC client */
+extern SilcClientConfigSection silc_client_config_sections[];
+
+/* Structure used in parsing the configuration lines. The line is read
+   from a file to this structure before parsing it further. */
+typedef struct SilcClientConfigParseStruct {
+  SilcBuffer line;
+  unsigned int linenum;
+  SilcClientConfigSection *section;
+  struct SilcClientConfigParseStruct *next;
+  struct SilcClientConfigParseStruct *prev;
+} *SilcClientConfigParse;
+
+/* Prototypes */
+SilcClientConfig silc_client_config_alloc(char *filename);
+void silc_client_config_free(SilcClientConfig config);
+int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
+                            SilcClientConfigParse *return_config);
+int silc_client_config_parse_lines(SilcClientConfig config, 
+                                  SilcClientConfigParse parse_config);
+int silc_client_config_check_sections(unsigned int checkmask);
+void silc_client_config_setlogfiles(SilcClientConfig config);
+void silc_client_config_register_ciphers(SilcClientConfig config);
+void silc_client_config_register_pkcs(SilcClientConfig config);
+void silc_client_config_register_hashfuncs(SilcClientConfig config);
+SilcClientConfigSectionConnection *
+silc_client_config_find_connection(SilcClientConfig config, 
+                                  char *host, int port);
+
+#endif
diff --git a/apps/silc/clientutil.c b/apps/silc/clientutil.c
new file mode 100644 (file)
index 0000000..8946b28
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+
+  client.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Internal routine used to print lines to window. This can split the
+   line neatly if a word would overlap the line. */
+
+static void silc_print_to_window(WINDOW *win, char *message)
+{
+  int str_len, len;
+
+  str_len = strlen(message);
+  if (str_len > COLS - 1) {
+    /* Split overlapping words to next line */
+    /* XXX In principal this is wrong as this modifies the original
+       string as it replaces the last ' ' with '\n'. This could be done
+       with little more work so that it would not replace anything. */
+    len = COLS - 1;
+    while (1) {
+
+      while (len && message[len] != ' ')
+       len--;
+
+      if (!len)
+       break;
+
+      message[len] = '\n';
+      len += COLS - 1;
+      if (len > str_len)
+       break;
+    }
+  }
+
+  wprintw(win, "%s", message);
+  wrefresh(win);
+}
+
+/* Prints a message with three star (*) sign before the actual message
+   on the current output window. This is used to print command outputs
+   and error messages. */
+/* XXX Change to accept SilcClientWindow and use output window 
+   from there (the pointer to the output window must be added to the
+   SilcClientWindow object. */
+
+void silc_say(SilcClient client, char *msg, ...)
+{
+  va_list vp;
+  char message[1024];
+  
+  memset(message, 0, sizeof(message));
+  strncat(message, "\n***  ", 5);
+
+  va_start(vp, msg);
+  vsprintf(message + 5, msg, vp);
+  va_end(vp);
+  
+  /* Print the message */
+  silc_print_to_window(client->screen->output_win[0], message);
+}
+
+/* Prints message to the screen. This is used to print the messages
+   user is typed and message that came on channels. */
+
+void silc_print(SilcClient client, char *msg, ...)
+{
+  va_list vp;
+  char message[1024];
+  
+  memset(message, 0, sizeof(message));
+  strncat(message, "\n ", 2);
+
+  va_start(vp, msg);
+  vsprintf(message + 1, msg, vp);
+  va_end(vp);
+  
+  /* Print the message */
+  silc_print_to_window(client->screen->output_win[0], message);
+}
+
+/* Returns user's mail path */
+
+char *silc_get_mail_path()
+{
+  char pathbuf[MAXPATHLEN];
+  char *path;
+  
+  if ((path = (char *)getenv("MAIL")) != 0) {
+    strncpy(pathbuf, path, strlen(path));
+  } else {
+    strcpy(pathbuf, _PATH_MAILDIR);
+    strcat(pathbuf, "/");
+    strcat(pathbuf, silc_get_username());
+  }
+
+  return strdup(pathbuf);
+}
+
+/* gets the number of the user's mails, if possible */
+
+int silc_get_number_of_emails()
+{
+  FILE *tl;
+  int num = 0;
+  char *filename;
+  char data[1024];
+  
+  filename = silc_get_mail_path();
+  
+  tl = fopen(filename, "r");
+  if (!tl) {
+    fprintf(stderr, "Couldn't open mail file (%s).\n", filename);
+  } else {
+    while((fscanf(tl, "%s", data)) != EOF) { 
+      if(!strcmp(data, "Subject:"))
+       num++;
+    }
+    
+    fclose(tl);
+  }
+  
+  return num;
+}
+
+/* Returns the username of the user. If the global variable LOGNAME
+   does not exists we will get the name from the password file. */
+
+char *silc_get_username()
+{
+  char *logname = NULL;
+  
+  logname = strdup(getenv("LOGNAME"));
+  if (!logname) {
+    logname = getlogin();
+    if (!logname) {
+      struct passwd *pw;
+
+      pw = getpwuid(getuid());
+      if (!pw) {
+       fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
+       return NULL;
+      }
+      
+      logname = strdup(pw->pw_name);
+    }
+  }
+  
+  return logname;
+}                          
+
+/* Returns the real name of ther user. */
+
+char *silc_get_real_name()
+{
+  char *realname = NULL;
+  struct passwd *pw;
+    
+  pw = getpwuid(getuid());
+  if (!pw) {
+    fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
+    return NULL;
+  }
+
+  if (strchr(pw->pw_gecos, ','))
+    *strchr(pw->pw_gecos, ',') = 0;
+
+  realname = strdup(pw->pw_gecos);
+
+  return realname;
+}
+
+/* Returns time til next minute changes. Used to update the clock when
+   needed. */
+
+int silc_client_time_til_next_min()
+{
+  time_t curtime;
+  struct tm *min;
+  
+  curtime = time(0);
+  min = localtime(&curtime);
+  
+  return 60 - min->tm_sec;
+}
+
+/* Asks passphrase from user on the input line. */
+
+char *silc_client_ask_passphrase(SilcClient client)
+{
+  char pass1[256], pass2[256];
+  char *ret;
+  int try = 3;
+
+  while(try) {
+
+    /* Print prompt */
+    wattroff(client->screen->input_win, A_INVIS);
+    silc_screen_input_print_prompt(client->screen, "Passphrase: ");
+    wattron(client->screen->input_win, A_INVIS);
+    
+    /* Get string */
+    memset(pass1, 0, sizeof(pass1));
+    wgetnstr(client->screen->input_win, pass1, sizeof(pass1));
+    
+    /* Print retype prompt */
+    wattroff(client->screen->input_win, A_INVIS);
+    silc_screen_input_print_prompt(client->screen, "Retype passphrase: ");
+    wattron(client->screen->input_win, A_INVIS);
+    
+    /* Get string */
+    memset(pass2, 0, sizeof(pass2));
+    wgetnstr(client->screen->input_win, pass2, sizeof(pass2));
+
+    if (!strncmp(pass1, pass2, strlen(pass2)))
+      break;
+
+    try--;
+  }
+
+  ret = silc_calloc(strlen(pass1), sizeof(char));
+  memcpy(ret, pass1, strlen(pass1));
+
+  memset(pass1, 0, sizeof(pass1));
+  memset(pass2, 0, sizeof(pass2));
+
+  wattroff(client->screen->input_win, A_INVIS);
+  silc_screen_input_reset(client->screen);
+
+  return ret;
+}
+
+/* Lists supported (builtin) ciphers */
+
+void silc_client_list_ciphers()
+{
+
+}
+
+/* Lists supported (builtin) hash functions */
+
+void silc_client_list_hash_funcs()
+{
+
+}
+
+/* Lists supported PKCS algorithms */
+
+void silc_client_list_pkcs()
+{
+
+}
+
+/* Displays input prompt on command line and takes input data from user */
+
+char *silc_client_get_input(const char *prompt)
+{
+  char input[2048];
+  int fd;
+
+  fd = open("/dev/tty", O_RDONLY);
+  if (fd < 0) {
+    fprintf(stderr, "silc: %s\n", strerror(errno));
+    exit(1);
+  }
+
+  memset(input, 0, sizeof(input));
+
+  printf("%s", prompt);
+  fflush(stdout);
+
+  if ((read(fd, input, sizeof(input))) < 0) {
+    fprintf(stderr, "silc: %s\n", strerror(errno));
+    exit(1);
+  }
+
+  if (strlen(input) <= 1)
+    return NULL;
+
+  if (strchr(input, '\n'))
+    *strchr(input, '\n') = '\0';
+
+  return strdup(input);
+}
+
+/* Displays prompt on command line and takes passphrase with echo 
+   off from user. */
+
+char *silc_client_get_passphrase(const char *prompt)
+{
+#if 0
+  char input[2048];
+  char *ret;
+  int fd;
+  struct termios to;
+  struct termios to_old;
+
+  fd = open("/dev/tty", O_RDONLY);
+  if (fd < 0) {
+    fprintf(stderr, "silc: %s\n", strerror(errno));
+    exit(1);
+  }
+
+  signal(SIGINT, SIG_IGN);
+
+  /* Get terminal info */
+  tcgetattr(fd, &to);
+  to_old = to;
+
+  /* Echo OFF */
+  to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+  tcsetattr(fd, TCSANOW, &to);
+
+  memset(input, 0, sizeof(input));
+
+  printf("%s", prompt);
+  fflush(stdout);
+
+  if ((read(fd, input, sizeof(input))) < 0) {
+    fprintf(stderr, "silc: %s\n", strerror(errno));
+    exit(1);
+  }
+
+  if (strlen(input) <= 1) {
+    tcsetattr(fd, TCSANOW, &to_old);
+    return NULL;
+  }
+
+  if (strchr(input, '\n'))
+    *strchr(input, '\n') = '\0';
+
+  /* Restore old terminfo */
+  tcsetattr(fd, TCSANOW, &to_old);
+  signal(SIGINT, SIG_DFL);
+
+  ret = silc_calloc(strlen(input), sizeof(char));
+  memcpy(ret, input, strlen(input));
+  memset(input, 0, sizeof(input));
+  return ret;
+#else
+  return NULL;
+#endif
+}
+
+/* Creates new public key and private key pair. This is used only
+   when user wants to create new key pair from command line. */
+
+void silc_client_create_key_pair(char *pkcs_name, int bits)
+{
+  SilcPKCS pkcs;
+  SilcRng rng;
+  unsigned char *key;
+  unsigned int key_len;
+  char *pkfile = NULL, *prvfile = NULL;
+
+  printf("\
+New pair of keys will be created.  Please, answer to following questions.\n\
+");
+
+  if (!pkcs_name) {
+  again_name:
+    pkcs_name = 
+      silc_client_get_input("PKCS name (l to list names) [rsa]: ");
+    if (!pkcs_name)
+      pkcs_name = strdup("rsa");
+
+    if (*pkcs_name == 'l' || *pkcs_name == 'L') {
+      silc_client_list_pkcs();
+      silc_free(pkcs_name);
+      goto again_name;
+    }
+  }
+
+  if (!bits) {
+    char *length = NULL;
+    length = 
+      silc_client_get_input("Key length in bits [1024]: ");
+    if (!length)
+      bits = 1024;
+    else
+      bits = atoi(length);
+  }
+
+  rng = silc_rng_alloc();
+  silc_rng_init(rng);
+  silc_math_primegen_init();
+
+ again_pk:
+  pkfile = silc_client_get_input("Public key filename: ");
+  if (!pkfile) {
+    printf("Public key filename must be defined\n");
+    goto again_pk;
+  }
+
+ again_prv:
+  prvfile = silc_client_get_input("Private key filename: ");
+  if (!prvfile) {
+    printf("Private key filename must be defined\n");
+    goto again_prv;
+  }
+
+  /* Generate keys */
+  silc_pkcs_alloc(pkcs_name, &pkcs);
+  pkcs->pkcs->init(pkcs->context, bits, rng);
+
+  /* Save keys into file */
+  key = silc_pkcs_get_public_key(pkcs, &key_len);
+  silc_pkcs_save_public_key(pkcs, pkfile, key, key_len);
+  memset(key, 0, sizeof(key_len));
+  silc_free(key);
+  key = silc_pkcs_get_private_key(pkcs, &key_len);
+  silc_pkcs_save_private_key(pkcs, prvfile, key, key_len, "");
+  memset(key, 0, sizeof(key_len));
+  silc_free(key);
+
+  silc_math_primegen_uninit();
+  silc_rng_free(rng);
+  silc_pkcs_free(pkcs);
+}
diff --git a/apps/silc/clientutil.h b/apps/silc/clientutil.h
new file mode 100644 (file)
index 0000000..e18cf2d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+
+  client.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENTUTIL_H
+#define CLIENTUTIL_H
+
+/* Prototypes */
+void silc_say(SilcClient client, char *msg, ...);
+void silc_print(SilcClient client, char *msg, ...);
+char *silc_get_mail_path();
+int silc_get_number_of_emails();
+char *silc_get_username();
+char *silc_get_real_name();
+int silc_client_time_til_next_min();
+char *silc_client_ask_passphrase(SilcClient client);
+char *silc_client_get_input(const char *prompt);
+char *silc_client_get_passphrase(const char *prompt);
+void silc_client_list_ciphers();
+void silc_client_list_hash_funcs();
+void silc_client_list_pkcs();
+void silc_client_create_key_pair(char *pkcs_name, int bits);
+
+#endif
diff --git a/apps/silc/command.c b/apps/silc/command.c
new file mode 100644 (file)
index 0000000..5c64ca8
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+
+  command.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Client command list. */
+SilcClientCommand silc_command_list[] =
+{
+  SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 
+                 SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
+  SILC_CLIENT_CMD(kill, KILL, "KILL", 
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(oper, OPER, "OPER",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(restart, RESTART, "RESTART",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(die, DIE, "DIE",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
+  SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
+
+  /*
+   * Local. client specific commands
+   */
+  SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
+  SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
+  SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
+  SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
+  SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
+  SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
+
+  { NULL, 0, NULL, 0},
+};
+
+/* List of pending commands. */
+SilcClientCommandPending *silc_command_pending = NULL;
+
+/* Add new pending command to the list of pending commands. Currently
+   pending commands are executed from command replies, thus we can
+   execute any command after receiving some specific command reply.
+
+   The argument `reply_cmd' is the command reply from where the callback
+   function is to be called, thus, it IS NOT the command to be executed.
+
+   XXX: If needed in the future this support may be extended for
+   commands as well, when any command could be executed after executing
+   some specific command. */
+
+void silc_client_command_pending(SilcCommand reply_cmd,
+                                SilcClientCommandCallback callback,
+                                void *context)
+{
+  SilcClientCommandPending *reply, *r;
+
+  reply = silc_calloc(1, sizeof(*reply));
+  reply->reply_cmd = reply_cmd;
+  reply->context = context;
+  reply->callback = callback;
+
+  if (silc_command_pending == NULL) {
+    silc_command_pending = reply;
+    return;
+  }
+
+  for (r = silc_command_pending; r; r = r->next) {
+    if (r->next == NULL) {
+      r->next = reply;
+      break;
+    }
+  }
+}
+
+/* Deletes pending command by reply command type. */
+
+void silc_client_command_pending_del(SilcCommand reply_cmd)
+{
+  SilcClientCommandPending *r, *tmp;
+  
+  if (silc_command_pending) {
+    if (silc_command_pending->reply_cmd == reply_cmd) {
+      silc_free(silc_command_pending);
+      silc_command_pending = NULL;
+      return;
+    }
+
+    for (r = silc_command_pending; r; r = r->next) {
+      if (r->next && r->next->reply_cmd == reply_cmd) {
+       tmp = r->next;
+       r->next = r->next->next;
+       silc_free(tmp);
+       break;
+      }
+    }
+  }
+}
+
+/* Free command context and its internals */
+
+static void silc_client_command_free(SilcClientCommandContext cmd)
+{
+  int i;
+
+  if (cmd) {
+    for (i = 0; i < cmd->argc; i++)
+      silc_free(cmd->argv[i]);
+    silc_free(cmd);
+  }
+}
+
+/* Command WHOIS. This command is used to query information about 
+   specific user. */
+
+SILC_CLIENT_CMD_FUNC(whois)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcBuffer buffer;
+
+  if (cmd->argc < 2 || cmd->argc > 3) {
+    silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
+    goto out;
+  }
+
+  if (!cmd->client->current_win->sock) {
+    silc_say(cmd->client, 
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(whowas)
+{
+}
+
+/* Command IDENTIFY. This command is used to query information about 
+   specific user, especially ID's. */
+
+SILC_CLIENT_CMD_FUNC(identify)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcBuffer buffer;
+
+  if (cmd->argc < 2 || cmd->argc > 3) {
+    silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
+    goto out;
+  }
+
+  if (!cmd->client->current_win->sock) {
+    silc_say(cmd->client, 
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Command NICK. Shows current nickname/sets new nickname on current
+   window. */
+
+SILC_CLIENT_CMD_FUNC(nick)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientWindow win = NULL;
+  SilcBuffer buffer;
+
+  if (!cmd->sock) {
+    silc_say(cmd->client, 
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  /* Show current nickname */
+  if (cmd->argc < 2) {
+    if (cmd->sock) {
+      silc_say(cmd->client, "Your nickname is %s on server %s", 
+              win->nickname, win->remote_host);
+    } else {
+      silc_say(cmd->client, "Your nickname is %s", win->nickname);
+    }
+    goto out;
+  }
+
+  win = (SilcClientWindow)cmd->sock->user_data;
+
+  /* Set new nickname */
+  buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  silc_client_packet_send(cmd->client, cmd->sock,
+                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+  if (win->nickname)
+    silc_free(win->nickname);
+  win->nickname = strdup(cmd->argv[1]);
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Command SERVER. Connects to remote SILC server. This is local command. */
+
+SILC_CLIENT_CMD_FUNC(server)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  int len, port;
+  char *hostname;
+
+  if (cmd->argc < 2) {
+    /* Show current servers */
+    if (!cmd->client->current_win->sock) {
+      silc_say(cmd->client, "You are not connected to any server");
+      silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
+      goto out;
+    }
+
+    goto out;
+  }
+
+  /* See if port is included and then extract it */
+  if (strchr(cmd->argv[1], ':')) {
+    len = strcspn(cmd->argv[1], ":");
+    hostname = silc_calloc(len + 1, sizeof(char));
+    memcpy(hostname, cmd->argv[1], len);
+    port = atoi(cmd->argv[1] + 1 + len);
+  } else {
+    hostname = cmd->argv[1];
+    /* XXX */
+    port = 334;
+  }
+
+  /* Connect asynchronously to not to block user interface */
+  silc_client_connect_to_server(cmd->client, port, hostname);
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(list)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(topic)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(invite)
+{
+}
+
+/* Command QUIT. Closes connection with current server. */
+SILC_CLIENT_CMD_FUNC(quit)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcBuffer buffer;
+
+  if (!cmd->client->current_win->sock) {
+    silc_say(cmd->client, 
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1, 
+                                      ++cmd->argv, ++cmd->argv_lens,
+                                      ++cmd->argv_types);
+  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+  /* Close connection */
+  silc_client_close_connection(cmd->client, cmd->sock);
+  cmd->client->screen->bottom_line->connection = NULL;
+  silc_screen_print_bottom_line(cmd->client->screen, 0);
+
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(kill)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(info)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(connect)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(ping)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(oper)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(trace)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(notice)
+{
+}
+
+/* Command JOIN. Joins to a channel. */
+
+SILC_CLIENT_CMD_FUNC(join)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientWindow win = NULL;
+  SilcIDCache *id_cache = NULL;
+  SilcBuffer buffer;
+
+#define CIDC(x) win->channel_id_cache[(x) - 32]
+#define CIDCC(x) win->channel_id_cache_count[(x) - 32]
+
+  if (cmd->argc < 2) {
+    /* Show channels currently joined to */
+    if (!cmd->client->current_win->sock) {
+      silc_say(cmd->client, "No current channel for this window");
+      silc_say(cmd->client, 
+              "You are not connected to a server, use /SERVER to connect");
+      goto out;
+
+    }
+
+    goto out;
+  }
+
+  if (!cmd->client->current_win->sock) {
+    silc_say(cmd->client, 
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  win = (SilcClientWindow)cmd->sock->user_data;
+
+  /* See if we have joined to the requested channel already */
+  silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]), 
+                           cmd->argv[1], &id_cache);
+
+  if (id_cache) {
+    silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
+    win->current_channel = (SilcChannelEntry)id_cache->context;
+    cmd->client->screen->bottom_line->channel = cmd->argv[1];
+    silc_screen_print_bottom_line(cmd->client->screen, 0);
+    goto out;
+  }
+
+  /* Send JOIN command to the server */
+  buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
+                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+ out:
+  silc_client_command_free(cmd);
+#undef CIDC
+#undef CIDCC
+}
+
+SILC_CLIENT_CMD_FUNC(motd)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(umode)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(cmode)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(kick)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(restart)
+{
+}
+SILC_CLIENT_CMD_FUNC(close)
+{
+}
+SILC_CLIENT_CMD_FUNC(die)
+{
+}
+SILC_CLIENT_CMD_FUNC(silcoper)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(leave)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(names)
+{
+}
+
+/*
+ * Local commands
+ */
+
+/* HELP command. This is local command and shows help on SILC */
+
+SILC_CLIENT_CMD_FUNC(help)
+{
+
+}
+
+/* CLEAR command. This is local command and clears current output window */
+
+SILC_CLIENT_CMD_FUNC(clear)
+{
+  SilcClient client = (SilcClient)context;
+
+  assert(client->current_win != NULL);
+  wclear((WINDOW *)client->current_win->screen);
+  wrefresh((WINDOW *)client->current_win->screen);
+}
+
+/* VERSION command. This is local command and shows version of the client */
+
+SILC_CLIENT_CMD_FUNC(version)
+{
+
+}
+
+/* Command MSG. Sends private message to user or list of users. */
+/* XXX supports only one destination */
+
+SILC_CLIENT_CMD_FUNC(msg)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientWindow win = NULL;
+  SilcClient client = cmd->client;
+  SilcBuffer buffer;
+  SilcIDCache *id_cache;
+  unsigned int nick_len;
+
+  if (cmd->argc < 3) {
+    silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
+    goto out;
+  }
+
+  if (!cmd->client->current_win->sock) {
+    silc_say(cmd->client, 
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  win = (SilcClientWindow)cmd->sock->user_data;
+
+#define CIDC(x) win->client_id_cache[(x) - 32], \
+                win->client_id_cache_count[(x) - 32]
+
+  /* Find ID from cache */
+  if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1], 
+                               &id_cache) == FALSE) {
+    SilcClientCommandContext ctx;
+    char ident[512];
+
+    SILC_LOG_DEBUG(("Requesting Client ID from server"));
+
+    /* No ID found. Do query from the server. The query is done by 
+       sending simple IDENTIFY command to the server. */
+    ctx = silc_calloc(1, sizeof(*ctx));
+    ctx->client = client;
+    ctx->sock = cmd->sock;
+    memset(ident, 0, sizeof(ident));
+    snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
+    silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
+                                  &ctx->argv_types, &ctx->argc, 2);
+    silc_client_command_identify(ctx);
+
+    /* Mark this command to be pending command and to be executed after
+       we have received the IDENTIFY reply from server. */
+    silc_client_command_pending(SILC_COMMAND_IDENTIFY, 
+                               silc_client_command_msg, context);
+    return;
+  }
+
+  /* Display the message for our eyes. */
+  silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
+
+  /* Send the private message */
+  silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
+                                         cmd->argv[2], cmd->argv_lens[2],
+                                         TRUE);
+ out:
+  silc_client_command_free(cmd);
+#undef CIDC
+}
+
+SILC_CLIENT_CMD_FUNC(away)
+{
+}
diff --git a/apps/silc/command.h b/apps/silc/command.h
new file mode 100644 (file)
index 0000000..19db809
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+
+  command.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+/* 
+   Structure holding one command and pointer to its function. 
+
+   SilcCommandCb cb
+
+       Callback function called when this command is executed.
+
+   SilcCommand cmd
+
+       The actual command. These are defined in silccore/silccommand.h
+
+   char *name
+
+       Logical name of the command. This is the visible command name
+       that user uses when calling command. Eg. NICK.
+
+   SilcCommandFlag flags
+
+       Flags for the command. These set how command behaves on different
+       situations. Server sets these flags as well, but to be sure
+       that our client never sends wrong commands we preserve the
+       flags on client side as well.
+
+       XXX: We preserve these so that we define them but currently we
+       don't check the flags at all.
+
+*/
+typedef struct {
+  SilcCommandCb cb;
+  SilcCommand cmd;
+  char *name;
+  SilcCommandFlag flags;
+  unsigned int max_args;
+} SilcClientCommand;
+
+/* All client commands */
+extern SilcClientCommand silc_command_list[];
+
+/* Client command callback function. This included into Command Context, 
+   and if it is defined it will be executed when executing the command. */
+typedef void (*SilcClientCommandCallback)(void *context);
+
+/* Context sent as argument to all commands */
+typedef struct {
+  SilcClient client;
+  SilcSocketConnection sock;
+  unsigned int argc;
+  unsigned char **argv;
+  unsigned int *argv_lens;
+  unsigned int *argv_types;
+} *SilcClientCommandContext;
+
+/* Structure holding pending commands. If command is pending it will be
+   executed after command reply has been executed. */
+/* XXX This support may added for commands as well and not just command
+   replies, if needed later. */
+typedef struct SilcClientCommandPendingStruct {
+  SilcCommand reply_cmd;
+  void *context;
+  SilcClientCommandCallback callback;
+
+  struct SilcClientCommandPendingStruct *next;
+} SilcClientCommandPending;
+
+/* List of pending commands */
+extern SilcClientCommandPending *silc_command_pending;
+
+/* Macros */
+
+/* Macro used for command declaration in command list structure */
+#define SILC_CLIENT_CMD(func, cmd, name, flags, args) \
+{ silc_client_command_##func, SILC_COMMAND_##cmd, name, flags, args }
+
+/* Macro used to declare command functions */
+#define SILC_CLIENT_CMD_FUNC(func) \
+void silc_client_command_##func(void *context)
+
+/* Checks for pending commands */
+#define SILC_CLIENT_COMMAND_CHECK_PENDING(ctx)         \
+do {                                                   \
+  if (silc_command_pending) {                          \
+    SilcClientCommandPending *r;                       \
+    SilcCommand cmd;                                   \
+                                                       \
+    cmd = silc_command_get(payload);                   \
+    for (r = silc_command_pending; r; r = r->next) {   \
+      if (r->reply_cmd == cmd) {                       \
+       ctx->context = r->context;                      \
+       ctx->callback = r->callback;                    \
+       break;                                          \
+      }                                                        \
+    }                                                  \
+  }                                                    \
+} while(0)
+
+/* Executed pending command */
+#define SILC_CLIENT_COMMAND_EXEC_PENDING(ctx, cmd)     \
+do {                                                   \
+  if (ctx->callback) {                                 \
+    (*ctx->callback)(ctx->context);                    \
+    silc_client_command_pending_del((cmd));            \
+  }                                                    \
+} while(0)
+
+/* Prototypes */
+void silc_client_command_pending(SilcCommand reply_cmd,
+                                SilcClientCommandCallback callback,
+                                void *context);
+void silc_client_command_pending_del(SilcCommand reply_cmd);
+SILC_CLIENT_CMD_FUNC(whois);
+SILC_CLIENT_CMD_FUNC(whowas);
+SILC_CLIENT_CMD_FUNC(identify);
+SILC_CLIENT_CMD_FUNC(nick);
+SILC_CLIENT_CMD_FUNC(server);
+SILC_CLIENT_CMD_FUNC(list);
+SILC_CLIENT_CMD_FUNC(topic);
+SILC_CLIENT_CMD_FUNC(invite);
+SILC_CLIENT_CMD_FUNC(quit);
+SILC_CLIENT_CMD_FUNC(kill);
+SILC_CLIENT_CMD_FUNC(info);
+SILC_CLIENT_CMD_FUNC(connect);
+SILC_CLIENT_CMD_FUNC(ping);
+SILC_CLIENT_CMD_FUNC(oper);
+SILC_CLIENT_CMD_FUNC(join);
+SILC_CLIENT_CMD_FUNC(motd);
+SILC_CLIENT_CMD_FUNC(umode);
+SILC_CLIENT_CMD_FUNC(cmode);
+SILC_CLIENT_CMD_FUNC(kick);
+SILC_CLIENT_CMD_FUNC(restart);
+SILC_CLIENT_CMD_FUNC(close);
+SILC_CLIENT_CMD_FUNC(die);
+SILC_CLIENT_CMD_FUNC(silcoper);
+SILC_CLIENT_CMD_FUNC(leave);
+SILC_CLIENT_CMD_FUNC(names);
+SILC_CLIENT_CMD_FUNC(help);
+SILC_CLIENT_CMD_FUNC(clear);
+SILC_CLIENT_CMD_FUNC(version);
+SILC_CLIENT_CMD_FUNC(msg);
+SILC_CLIENT_CMD_FUNC(away);
+
+#endif
diff --git a/apps/silc/command_reply.c b/apps/silc/command_reply.c
new file mode 100644 (file)
index 0000000..3b54072
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+
+  command_reply.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Command reply functions are "the otherside" of the command functions.
+ * Reply to a command sent by server is handled by these functions.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Client command reply list. */
+SilcClientCommandReply silc_command_reply_list[] =
+{
+  SILC_CLIENT_CMD_REPLY(whois, WHOIS),
+  SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
+  SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
+  SILC_CLIENT_CMD_REPLY(nick, NICK),
+  SILC_CLIENT_CMD_REPLY(list, LIST),
+  SILC_CLIENT_CMD_REPLY(topic, TOPIC),
+  SILC_CLIENT_CMD_REPLY(invite, INVITE),
+  SILC_CLIENT_CMD_REPLY(quit, QUIT),
+  SILC_CLIENT_CMD_REPLY(kill, KILL),
+  SILC_CLIENT_CMD_REPLY(info, INFO),
+  SILC_CLIENT_CMD_REPLY(away, AWAY),
+  SILC_CLIENT_CMD_REPLY(connect, CONNECT),
+  SILC_CLIENT_CMD_REPLY(ping, PING),
+  SILC_CLIENT_CMD_REPLY(oper, OPER),
+  SILC_CLIENT_CMD_REPLY(join, JOIN),
+  SILC_CLIENT_CMD_REPLY(motd, MOTD),
+  SILC_CLIENT_CMD_REPLY(umode, UMODE),
+  SILC_CLIENT_CMD_REPLY(cmode, CMODE),
+  SILC_CLIENT_CMD_REPLY(kick, KICK),
+  SILC_CLIENT_CMD_REPLY(restart, RESTART),
+  SILC_CLIENT_CMD_REPLY(close, CLOSE),
+  SILC_CLIENT_CMD_REPLY(die, DIE),
+  SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
+  SILC_CLIENT_CMD_REPLY(leave, LEAVE),
+  SILC_CLIENT_CMD_REPLY(names, LEAVE),
+
+  { NULL, 0 },
+};
+
+/* Status message structure. Messages are defined below. */
+typedef struct {
+  SilcCommandStatus status;
+  char *message;
+} SilcCommandStatusMessage;
+
+/* Status messages returned by the server */
+#define STAT(x) SILC_STATUS_ERR_##x
+const SilcCommandStatusMessage silc_command_status_messages[] = {
+
+  { STAT(NO_SUCH_NICK),      "No such nickname" },
+  { STAT(NO_SUCH_CHANNEL),   "No such channel" },
+  { STAT(NO_SUCH_SERVER),    "No such server" },
+  { STAT(TOO_MANY_TARGETS),  "Duplicate recipients. No message delivered" },
+  { STAT(NO_RECIPIENT),      "No recipient given" },
+  { STAT(UNKNOWN_COMMAND),   "Unknown command" },
+  { STAT(WILDCARDS),         "Unknown command" },
+  { STAT(NO_CLIENT_ID),      "No Client ID given" },
+  { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
+  { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
+  { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
+  { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
+  { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
+  { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
+  { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
+  { STAT(USER_ON_CHANNEL),   "User already on channel" },
+  { STAT(NOT_REGISTERED),    "You have not registered" },
+  { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
+  { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
+  { STAT(PERM_DENIED),       "Your host is not among the privileged" },
+  { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
+  { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
+  { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
+  { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
+  { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
+  { STAT(UNKNOWN_MODE),    "Unknown mode" },
+  { STAT(NOT_YOU),         "Cannot change mode for other users" },
+  { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
+  { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
+  { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
+  { STAT(BAD_NICKNAME),    "Bad nickname" },
+  { STAT(BAD_CHANNEL),     "Bad channel name" },
+  { STAT(AUTH_FAILED),     "Authentication failed" },
+
+  { 0, NULL }
+};
+
+/* Process received command reply. */
+
+void silc_client_command_reply_process(SilcClient client,
+                                      SilcSocketConnection sock,
+                                      SilcBuffer buffer)
+{
+  SilcClientCommandReplyContext ctx;
+  SilcCommandPayload payload;
+
+  /* Get command reply payload from packet */
+  payload = silc_command_parse_payload(buffer);
+  if (!payload) {
+    /* Silently ignore bad reply packet */
+    SILC_LOG_DEBUG(("Bad command reply packet"));
+    return;
+  }
+  
+  /* Allocate command reply context. This must be free'd by the
+     command reply routine receiving it. */
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->client = client;
+  ctx->sock = sock;
+  ctx->payload = payload;
+      
+  /* Check for pending commands and mark to be exeucted */
+  SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
+  
+  /* Execute command reply */
+  SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
+}
+
+/* Returns status message string */
+
+static char *
+silc_client_command_status_message(SilcCommandStatus status)
+{
+  int i;
+
+  for (i = 0; silc_command_status_messages[i].message; i++) {
+    if (silc_command_status_messages[i].status == status)
+      break;
+  }
+
+  if (silc_command_status_messages[i].message == NULL)
+    return NULL;
+
+  return silc_command_status_messages[i].message;
+}
+
+/* Free command reply context and its internals. */
+
+void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
+{
+  if (cmd) {
+    silc_command_free_payload(cmd->payload);
+    silc_free(cmd);
+  }
+}
+
+/* Received reply for WHOIS command. This maybe called several times
+   for one WHOIS command as server may reply with list of results. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(whois)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClient client = cmd->client;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+      tmp += 2;
+      silc_say(cmd->client, "%s: %s", tmp,
+              silc_client_command_status_message(status));
+      goto out;
+    } else {
+      silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+      goto out;
+    }
+  }
+
+  /* Display one whois reply */
+  if (status == SILC_STATUS_OK) {
+    char buf[256];
+    int argc, len;
+    unsigned char *id_data;
+    char *nickname = NULL, *username = NULL;
+    char *realname = NULL;
+    void *id;
+
+    memset(buf, 0, sizeof(buf));
+
+    argc = silc_command_get_arg_num(cmd->payload);
+    id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
+
+    nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
+    if (nickname) {
+      strncat(buf, nickname, len);
+      strncat(buf, " is ", 4);
+    }
+
+    username = silc_command_get_arg_type(cmd->payload, 4, &len);
+    if (username) {
+      strncat(buf, username, len);
+    }
+
+    realname = silc_command_get_arg_type(cmd->payload, 5, &len);
+    if (realname) {
+      strncat(buf, " (", 2);
+      strncat(buf, realname, len);
+      strncat(buf, ")", 1);
+    }
+
+#if 0
+    /* Save received Client ID to ID cache */
+    /* XXX Maybe should not be saved as /MSG will get confused */
+    id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+    client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
+    silc_idcache_add(&client->current_win->
+                    client_id_cache[(int)nickname[0] - 32],
+                    client->current_win->
+                    client_id_cache_count[(int)nickname[0] - 32],
+                    strdup(nickname), SILC_ID_CLIENT, id, NULL);
+#endif
+
+    silc_say(cmd->client, "%s", buf);
+   }
+
+  if (status == SILC_STATUS_LIST_START) {
+
+  }
+
+  if (status == SILC_STATUS_LIST_END) {
+
+  }
+
+  SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(whowas)
+{
+}
+
+/* Received reply for IDENTIFY command. This maybe called several times
+   for one IDENTIFY command as server may reply with list of results. 
+   This is totally silent and does not print anything on screen. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(identify)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
+  SilcClientEntry client_entry;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+#define CIDC(x) win->client_id_cache[(x) - 32]
+#define CIDCC(x) win->client_id_cache_count[(x) - 32]
+
+  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+      tmp += 2;
+      silc_say(cmd->client, "%s: %s", tmp,
+              silc_client_command_status_message(status));
+      goto out;
+    } else {
+      silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+      goto out;
+    }
+  }
+
+  /* Display one whois reply */
+  if (status == SILC_STATUS_OK) {
+    unsigned char *id_data;
+    char *nickname;
+
+    id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
+    nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
+
+    /* Allocate client entry */
+    client_entry = silc_calloc(1, sizeof(*client_entry));
+    client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+    client_entry->nickname = strdup(nickname);
+
+    /* Save received Client ID to ID cache */
+    CIDCC(nickname[0]) =
+      silc_idcache_add(&CIDC(nickname[0]), CIDCC(nickname[0]),
+                      client_entry->nickname, SILC_ID_CLIENT, 
+                      client_entry->id, client_entry);
+  }
+
+  if (status == SILC_STATUS_LIST_START) {
+
+  }
+
+  if (status == SILC_STATUS_LIST_END) {
+
+  }
+
+  SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
+
+ out:
+  silc_client_command_reply_free(cmd);
+#undef CIDC
+#undef CIDCC
+}
+
+/* Received reply for command NICK. If everything went without errors
+   we just received our new Client ID. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(nick)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp, *id_string;
+  int argc;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    silc_say(cmd->client, "Cannot set nickname: %s", 
+            silc_client_command_status_message(status));
+    goto out;
+  }
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  if (argc < 2 || argc > 2) {
+    silc_say(cmd->client, "Cannot set nickname: bad reply to command");
+    goto out;
+  }
+
+  /* Take received Client ID */
+  id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
+  silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
+
+  /* Update nickname on screen */
+  cmd->client->screen->bottom_line->nickname = win->nickname;
+  silc_screen_print_bottom_line(cmd->client->screen, 0);
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(list)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(topic)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(invite)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(quit)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(kill)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(info)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(away)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(connect)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(ping)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(oper)
+{
+}
+
+/* Received reply for JOIN command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(join)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClient client = cmd->client;
+  SilcCommandStatus status;
+  unsigned int argc;
+  unsigned char *id_string;
+  char *topic, *tmp, *channel_name;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+    goto out;
+  }
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  if (argc < 3 || argc > 4) {
+    silc_say(cmd->client, "Cannot join channel: Bad reply packet");
+    goto out;
+  }
+
+  /* Get channel name */
+  tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+  channel_name = strdup(tmp);
+
+  /* Get channel ID */
+  id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
+
+  /* Get topic */
+  topic = silc_command_get_arg_type(cmd->payload, 4, NULL);
+
+  /* Save received Channel ID */
+  silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, id_string);
+
+  /* Print channel name on screen */
+  client->screen->bottom_line->channel = channel_name;
+  silc_screen_print_bottom_line(client->screen, 0);
+
+  if (topic)
+    silc_say(client, "Topic for %s: %s", channel_name, topic);
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(motd)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(umode)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(cmode)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(kick)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(restart)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(close)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(die)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(leave)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(names)
+{
+}
+
+/* Private message received. This processes the private message and
+   finally displays it on the screen. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(msg)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClient client = cmd->client;
+  SilcBuffer buffer = (SilcBuffer)cmd->context;
+  unsigned short nick_len;
+  unsigned char *nickname, *message;
+  SilcIDCache *id_cache;
+  unsigned char *id_string;
+  void *id;
+
+  /* Get nickname */
+  silc_buffer_unformat(buffer, 
+                      SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
+                      SILC_STR_END);
+  silc_buffer_pull(buffer, 2 + nick_len);
+
+#if 0
+  /* Get ID of the sender */
+  id_string = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char *));
+  silc_buffer_push(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
+  memcpy(id_string, buffer->data, SILC_ID_CLIENT_LEN);
+  silc_buffer_pull(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
+  id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+  silc_free(id_string);
+
+  /* Nickname should be verified if we don't have it in the cache */
+  if (silc_idcache_find_by_data(client->current_win->
+                               client_id_cache[nickname[0] - 32],
+                               client->current_win->
+                               client_id_cache_count[nickname[0] - 32],
+                               nickname, &id_cache) == FALSE) {
+
+    SilcClientCommandContext ctx;
+    char whois[255];
+
+    /* Private message from unknown source, try to resolve it. */
+
+
+    return;
+  }
+#endif
+     
+  message = silc_calloc(buffer->len + 1, sizeof(char));
+  memcpy(message, buffer->data, buffer->len);
+  silc_print(client, "*%s* %s", nickname, message);
+  memset(message, 0, buffer->len);
+  silc_free(message);
+}
diff --git a/apps/silc/command_reply.h b/apps/silc/command_reply.h
new file mode 100644 (file)
index 0000000..36b3128
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+
+  command_reply.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_REPLY_H
+#define COMMAND_REPLY_H
+
+/* Structure holding one command reply and pointer to its function. */
+typedef struct {
+  SilcCommandCb cb;
+  SilcCommand cmd;
+} SilcClientCommandReply;
+
+/* All client command replys */
+extern SilcClientCommandReply silc_command_reply_list[];
+
+/* Context sent as argument to all command reply functions */
+typedef struct {
+  SilcClient client;
+  SilcSocketConnection sock;
+  SilcCommandPayload payload;
+
+  /* If defined this executes the pending command. */
+  void *context;
+  SilcClientCommandCallback callback;
+} *SilcClientCommandReplyContext;
+
+/* Macros */
+
+/* Macro used for command declaration in command reply list structure */
+#define SILC_CLIENT_CMD_REPLY(func, cmd ) \
+{ silc_client_command_reply_##func, SILC_COMMAND_##cmd }
+
+/* Macro used to declare command reply functions */
+#define SILC_CLIENT_CMD_REPLY_FUNC(func) \
+void silc_client_command_reply_##func(void *context)
+
+/* Macro used to execute command replies */
+#define SILC_CLIENT_COMMAND_REPLY_EXEC(ctx)            \
+do {                                                   \
+  SilcClientCommandReply *cmd;                         \
+                                                       \
+  for (cmd = silc_command_reply_list; cmd->cb; cmd++)  \
+    if (cmd->cmd == silc_command_get(ctx->payload)) {  \
+      cmd->cb(ctx);                                    \
+      break;                                           \
+    }                                                  \
+                                                       \
+  if (cmd == NULL) {                                   \
+    silc_free(ctx);                                    \
+    return;                                            \
+  }                                                    \
+} while(0)
+
+/* Prototypes */
+void silc_client_command_reply_process(SilcClient client,
+                                      SilcSocketConnection sock,
+                                      SilcBuffer buffer);
+SILC_CLIENT_CMD_REPLY_FUNC(whois);
+SILC_CLIENT_CMD_REPLY_FUNC(whowas);
+SILC_CLIENT_CMD_REPLY_FUNC(identify);
+SILC_CLIENT_CMD_REPLY_FUNC(nick);
+SILC_CLIENT_CMD_REPLY_FUNC(list);
+SILC_CLIENT_CMD_REPLY_FUNC(topic);
+SILC_CLIENT_CMD_REPLY_FUNC(invite);
+SILC_CLIENT_CMD_REPLY_FUNC(quit);
+SILC_CLIENT_CMD_REPLY_FUNC(kill);
+SILC_CLIENT_CMD_REPLY_FUNC(info);
+SILC_CLIENT_CMD_REPLY_FUNC(links);
+SILC_CLIENT_CMD_REPLY_FUNC(stats);
+SILC_CLIENT_CMD_REPLY_FUNC(users);
+SILC_CLIENT_CMD_REPLY_FUNC(away);
+SILC_CLIENT_CMD_REPLY_FUNC(connect);
+SILC_CLIENT_CMD_REPLY_FUNC(ping);
+SILC_CLIENT_CMD_REPLY_FUNC(pong);
+SILC_CLIENT_CMD_REPLY_FUNC(oper);
+SILC_CLIENT_CMD_REPLY_FUNC(join);
+SILC_CLIENT_CMD_REPLY_FUNC(motd);
+SILC_CLIENT_CMD_REPLY_FUNC(umode);
+SILC_CLIENT_CMD_REPLY_FUNC(cmode);
+SILC_CLIENT_CMD_REPLY_FUNC(kick);
+SILC_CLIENT_CMD_REPLY_FUNC(restart);
+SILC_CLIENT_CMD_REPLY_FUNC(close);
+SILC_CLIENT_CMD_REPLY_FUNC(die);
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper);
+SILC_CLIENT_CMD_REPLY_FUNC(leave);
+SILC_CLIENT_CMD_REPLY_FUNC(names);
+SILC_CLIENT_CMD_REPLY_FUNC(msg);
+
+#endif
diff --git a/apps/silc/idlist.h b/apps/silc/idlist.h
new file mode 100644 (file)
index 0000000..9c769e9
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+
+  idlist.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef IDLIST_H
+#define IDLIST_H
+
+/* Client entry context. When client receives information about new client
+   (it receives its ID, for example, by IDENTIFY request) we create new
+   client entry. This entry also includes the private message keys if
+   they are used. */
+typedef struct SilcClientEntryStruct {
+  char *nickname;
+  SilcClientID *id;
+
+  /* Keys, these are defined if private message key has been defined 
+     with the remote client. */
+  SilcCipher send_key;
+  SilcCipher receive_key;
+} SilcClientEntryObject;
+
+typedef SilcClientEntryObject *SilcClientEntry;
+
+/* Channel entry context. This is allocate for every channel client has
+   joined to. This includes for example the channel specific keys */
+/* XXX channel_key is the server generated key. Later this context must 
+   include the channel private key. */
+typedef struct SilcChannelEntryStruct {
+  char *channel_name;
+  SilcChannelID *id;
+  int on_channel;
+
+  /* Channel keys */
+  SilcCipher channel_key;
+  unsigned char *key;
+  unsigned int key_len;
+  unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+} SilcChannelEntryObject;
+
+typedef SilcChannelEntryObject *SilcChannelEntry;
+
+#endif
diff --git a/apps/silc/protocol.c b/apps/silc/protocol.c
new file mode 100644 (file)
index 0000000..bfbb2aa
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+
+  protocol.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Client side of the protocols.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
+SILC_TASK_CALLBACK(silc_client_protocol_channel_auth);
+SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
+
+/* SILC client protocol list */
+const SilcProtocolObject silc_protocol_list[] =
+{
+  { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
+    silc_client_protocol_connection_auth },
+  { SILC_PROTOCOL_CLIENT_CHANNEL_AUTH, 
+    silc_client_protocol_channel_auth },
+  { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
+    silc_client_protocol_key_exchange },
+
+  { SILC_PROTOCOL_CLIENT_NONE, NULL },
+};
+
+/*
+ * Key Exhange protocol functions
+ */
+
+static void silc_client_protocol_ke_send_packet(SilcSKE ske,
+                                               SilcBuffer packet,
+                                               SilcPacketType type,
+                                               void *context)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientKEInternalContext *ctx = 
+    (SilcClientKEInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+
+  /* Send the packet immediately */
+  silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
+                         packet->data, packet->len, TRUE);
+
+}
+
+static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
+                                             void *context)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientKEInternalContext *ctx = 
+    (SilcClientKEInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+}
+
+static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
+                                             void *context)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientKEInternalContext *ctx = 
+    (SilcClientKEInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+}
+
+/* Sets the negotiated key material into use for particular connection. */
+
+static void silc_client_protocol_ke_set_keys(SilcSKE ske,
+                                            SilcSocketConnection sock,
+                                            SilcSKEKeyMaterial *keymat,
+                                            SilcCipher cipher,
+                                            SilcPKCS pkcs,
+                                            SilcHash hash)
+{
+  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcHash nhash;
+
+  SILC_LOG_DEBUG(("Setting new keys into use"));
+
+  /* Allocate cipher to be used in the communication */
+  silc_cipher_alloc(cipher->cipher->name, &win->send_key);
+  silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
+
+  win->send_key->cipher->set_key(win->send_key->context, 
+                                keymat->send_enc_key, 
+                                keymat->enc_key_len);
+  win->send_key->set_iv(win->send_key, keymat->send_iv);
+  win->receive_key->cipher->set_key(win->receive_key->context, 
+                                   keymat->receive_enc_key, 
+                                   keymat->enc_key_len);
+  win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
+
+  /* Allocate PKCS to be used */
+#if 0
+  /* XXX Do we ever need to allocate PKCS for the connection??
+     If yes, we need to change KE protocol to get the initiators
+     public key. */
+  silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
+  silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data, 
+                          ske->ke2_payload->pk_len);
+#endif
+
+  /* Save HMAC key to be used in the communication. */
+  silc_hash_alloc(hash->hash->name, &nhash);
+  silc_hmac_alloc(nhash, &win->hmac);
+  win->hmac_key_len = keymat->hmac_key_len;
+  win->hmac_key = silc_calloc(win->hmac_key_len,
+                                   sizeof(unsigned char));
+  memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+
+}
+
+/* Performs key exchange protocol. This is used for both initiator
+   and responder key exchange. This may be called recursively. */
+
+SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientKEInternalContext *ctx = 
+    (SilcClientKEInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+  SilcSKEStatus status;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+    protocol->state = SILC_PROTOCOL_STATE_START;
+
+  switch(protocol->state) {
+  case SILC_PROTOCOL_STATE_START:
+    {
+      /*
+       * Start Protocol
+       */
+      SilcSKE ske;
+
+      /* Allocate Key Exchange object */
+      ske = silc_ske_alloc();
+      ctx->ske = ske;
+      
+      if (ctx->responder == TRUE) {
+#if 0
+       SilcBuffer start_payload;
+
+
+       /* Start the key exchange by processing the received security
+          properties packet from initiator. */
+       status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+                                         start_payload,
+                                         silc_client_protocol_ke_send_packet,
+                                         context);
+#endif
+      } else {
+       SilcSKEStartPayload *start_payload;
+
+       /* Assemble security properties. */
+       silc_ske_assemble_security_properties(ske, &start_payload);
+
+       /* Start the key exchange by sending our security properties
+          to the remote end. */
+       status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
+                                         start_payload,
+                                         silc_client_protocol_ke_send_packet,
+                                         context);
+      }
+
+      if (status != SILC_SKE_STATUS_OK) {
+       switch(status) {
+         
+       default:
+         break;
+       }
+      }
+
+      /* Advance the state of the protocol. */
+      protocol->state++;
+    }
+    break;
+  case 2:
+    {
+      /* 
+       * Phase 1 
+       */
+      if (ctx->responder == TRUE) {
+#if 0
+       status = 
+         silc_ske_responder_phase_1(ctx->ske, 
+                                    ctx->ske->start_payload,
+                                    silc_server_protocol_ke_send_packet,
+                                    context);
+#endif
+      } else {
+       /* Call Phase-1 function. This processes the Key Exchange Start
+          paylaod reply we just got from the responder. The callback
+          function will receive the processed payload where we will
+          save it. */
+       status = 
+         silc_ske_initiator_phase_1(ctx->ske,
+                                    ctx->packet,
+                                    silc_client_protocol_ke_phase1_cb,
+                                    context);
+      }
+
+      switch(status) {
+      default:
+       break;
+      }
+
+      /* Advance the state of the protocol and call the next state. */
+      protocol->state++;
+      protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+    }
+    break;
+  case 3:
+    {
+      /* 
+       * Phase 2 
+       */
+      if (ctx->responder == TRUE) {
+#if 0
+       status = 
+         silc_ske_responder_phase_2(ctx->ske, 
+                                    ctx->ske->start_payload,
+                                    silc_server_protocol_ke_send_packet,
+                                    context);
+#endif
+      } else {
+       /* Call the Phase-2 function. This creates Diffie Hellman
+          key exchange parameters and sends our public part inside
+          Key Exhange 1 Payload to the responder. */
+       status = 
+         silc_ske_initiator_phase_2(ctx->ske,
+                                    silc_client_protocol_ke_send_packet,
+                                    context);
+      }
+
+      switch(status) {
+      default:
+       break;
+      }
+
+      /* Advance the state of the protocol. */
+      protocol->state++;
+    }
+    break;
+  case 4:
+    {
+      /* 
+       * Finish protocol
+       */
+      if (ctx->responder == TRUE) {
+#if 0
+       status = 
+         silc_ske_responder_phase_2(ctx->ske, 
+                                    ctx->ske->start_payload,
+                                    silc_server_protocol_ke_send_packet,
+                                    context);
+#endif
+      } else {
+       /* Finish the protocol. This verifies the Key Exchange 2 payload
+          sent by responder. */
+       status = 
+         silc_ske_initiator_finish(ctx->ske,
+                                   ctx->packet,
+                                   silc_client_protocol_ke_finish_cb,
+                                   context);
+      }
+
+      switch(status) {
+      default:
+       break;
+      }
+      
+      /* Send Ok to the other end. We will end the protocol as server
+        sends Ok to us when we will take the new keys into use. */
+      silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
+      
+      /* End the protocol on the next round */
+      protocol->state = SILC_PROTOCOL_STATE_END;
+    }
+    break;
+  case SILC_PROTOCOL_STATE_END:
+    {
+      /* 
+       * End protocol
+       */
+      SilcSKEKeyMaterial *keymat;
+
+      /* Process the key material */
+      keymat = silc_calloc(1, sizeof(*keymat));
+      silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
+
+      /* Take the negotiated keys into use. */
+      silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
+                                      ctx->ske->prop->cipher,
+                                      ctx->ske->prop->pkcs,
+                                      ctx->ske->prop->hash);
+
+      /* Protocol has ended, call the final callback */
+      if (protocol->final_callback)
+       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+      else
+       silc_protocol_free(protocol);
+    }
+    break;
+  case SILC_PROTOCOL_STATE_ERROR:
+    
+    /* On error the final callback is always called. */
+    /*    protocol->final_callback(pptr, context);*/
+    break;
+  case SILC_PROTOCOL_STATE_UNKNOWN:
+    break;
+  }
+}
+
+/*
+ * Connection Authentication protocol functions
+ */
+
+SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientConnAuthInternalContext *ctx = 
+    (SilcClientConnAuthInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+    protocol->state = SILC_PROTOCOL_STATE_START;
+
+  switch(protocol->state) {
+  case SILC_PROTOCOL_STATE_START:
+    {
+      /* 
+       * Start protocol. We send authentication data to the server
+       * to be authenticated.
+       */
+      SilcBuffer packet;
+      int payload_len = 0;
+      unsigned char *auth_data = NULL;
+      unsigned int auth_data_len = 0;
+
+      switch(ctx->auth_meth) {
+      case SILC_PROTOCOL_CONN_AUTH_NONE:
+       /* No authentication required */
+       break;
+
+      case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+       /* Password authentication */
+       if (ctx->auth_data && ctx->auth_data_len) {
+         auth_data = ctx->auth_data;
+         auth_data_len = ctx->auth_data_len;
+         break;
+       }
+
+       silc_say(client, "Password authentication required by server %s",
+                ctx->sock->hostname);
+       auth_data = silc_client_ask_passphrase(client);
+       auth_data_len = strlen(auth_data);
+       break;
+
+      case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+#if 0
+
+#endif
+       break;
+      }
+
+      payload_len = 4 + auth_data_len;
+      packet = silc_buffer_alloc(payload_len);
+      silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+      silc_buffer_format(packet,
+                        SILC_STR_UI_SHORT(payload_len),
+                        SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+                        SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
+                        SILC_STR_END);
+
+      /* Send the packet to server */
+      silc_client_packet_send(client, ctx->sock,
+                             SILC_PACKET_CONNECTION_AUTH,
+                             NULL, 0, NULL, NULL,
+                             packet->data, packet->len, TRUE);
+
+      if (auth_data) {
+       memset(auth_data, 0, auth_data_len);
+       silc_free(auth_data);
+      }
+      silc_buffer_free(packet);
+      
+      /* Next state is end of protocol */
+      protocol->state = SILC_PROTOCOL_STATE_END;
+    }
+    break;
+
+  case SILC_PROTOCOL_STATE_END:
+    {
+      /* 
+       * End protocol. Nothing special to be done here.
+       */
+
+      /* Protocol has ended, call the final callback */
+      if (protocol->final_callback)
+       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+      else
+       silc_protocol_free(protocol);
+    }
+    break;
+
+  case SILC_PROTOCOL_STATE_ERROR:
+    {
+      /* 
+       * Error
+       */
+
+      /* Error in protocol. Send FAILURE packet. Although I don't think
+        this could ever happen on client side. */
+      silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
+                             NULL, 0, NULL, NULL, NULL, 0, TRUE);
+
+      /* On error the final callback is always called. */
+      if (protocol->final_callback)
+       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+      else
+       silc_protocol_free(protocol);
+    }
+    break;
+  case SILC_PROTOCOL_STATE_UNKNOWN:
+    break;
+  }
+}
+
+SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)
+{
+}
diff --git a/apps/silc/protocol.h b/apps/silc/protocol.h
new file mode 100644 (file)
index 0000000..1c40ef3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+
+  protocol.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+/* SILC client protocol types */
+#define SILC_PROTOCOL_CLIENT_NONE 0
+#define SILC_PROTOCOL_CLIENT_CONNECTION_AUTH 1
+#define SILC_PROTOCOL_CLIENT_CHANNEL_AUTH 2
+#define SILC_PROTOCOL_CLIENT_KEY_EXCHANGE 3
+/* #define SILC_PROTOCOL_CLIENT_MAX 255 */
+
+/* Internal context for key exchange protocol */
+typedef struct {
+  void *client;
+  SilcSocketConnection sock;
+  SilcRng rng;
+  int responder;
+  SilcBuffer packet;
+  SilcSKE ske;
+} SilcClientKEInternalContext;
+
+/* Internal context for connection authentication protocol */
+typedef struct {
+  void *client;
+  SilcSocketConnection sock;
+
+  /* SKE object from Key Exchange protocol. */
+  SilcSKE ske;
+
+  /* Auth method that must be used. This is resolved before this
+     connection authentication protocol is started. */
+  unsigned int auth_meth;
+
+  /* Authentication data if we alreay know it. This is filled before
+     starting the protocol if we know the authentication data. Otherwise
+     these are and remain NULL. */
+  unsigned char *auth_data;
+  unsigned int auth_data_len;
+
+  SilcTask timeout_task;
+} SilcClientConnAuthInternalContext;
+
+/* Prototypes */
+
+#endif
diff --git a/apps/silc/pubkey.pub b/apps/silc/pubkey.pub
new file mode 100644 (file)
index 0000000..7dc0bfd
Binary files /dev/null and b/apps/silc/pubkey.pub differ
diff --git a/apps/silc/screen.c b/apps/silc/screen.c
new file mode 100644 (file)
index 0000000..10a52f0
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+
+  screen.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * SILC client screen routines. These implement the user interface
+ * on ncurses routines. Most of these routines were taken from the
+ * old version of the SILC client dating back to 1997.
+ */
+/* XXX: Input line handling is really buggy! */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+
+SilcScreen silc_screen_init()
+{
+  SilcScreen new;
+
+  new = silc_malloc(sizeof(*new));
+  if (new == NULL) {
+    SILC_LOG_ERROR(("Could not create new screen object"));
+    return NULL;
+  }
+
+  new->output_win_count = 0;
+  new->input_pos = 0;
+  new->cursor_pos = 0;
+  new->virtual_window = 0;
+  new->insert = TRUE;
+
+  initscr();
+  cbreak();
+  nonl();
+  noecho();
+
+  silc_screen_create_output_window(new);
+  silc_screen_create_input_window(new);
+
+  return new;
+}
+
+/* Creates one (main) output window. Returns new created physical 
+   window. */
+
+WINDOW *silc_screen_create_output_window(SilcScreen screen)
+{
+  assert(screen != NULL);
+
+  screen->output_win = silc_malloc(sizeof(*screen->output_win) * 1);
+  screen->output_win_count = 1;
+  screen->output_win[0] = newwin(LINES - 3, COLS, 1, 0);
+  scrollok(screen->output_win[0], TRUE);
+  idlok(screen->output_win[0], TRUE);
+  wrefresh(screen->output_win[0]);
+
+  return screen->output_win[0];
+}
+
+/* Adds new output window. Return new created physical window. */
+
+WINDOW *silc_screen_add_output_window(SilcScreen screen)
+{
+  int i;
+
+  assert(screen != NULL);
+
+  screen->output_win = silc_realloc(screen->output_win, 
+                                   (screen->output_win_count + 1) *
+                                   sizeof(*screen->output_win));
+  i = screen->output_win_count;
+  screen->output_win[i] = newwin(LINES - 3, COLS, 1, 0);
+  scrollok(screen->output_win[i], TRUE);
+  idlok(screen->output_win[i], TRUE);
+  wrefresh(screen->output_win[i]);
+  screen->output_win_count++;
+
+  return screen->output_win[i];
+}
+
+void silc_screen_create_input_window(SilcScreen screen)
+{
+  assert(screen != NULL);
+
+  screen->input_win = newwin(0, COLS, LINES - 1, 0);
+  scrollok(screen->input_win, TRUE);
+  keypad(screen->input_win, TRUE);
+  wrefresh(screen->input_win);
+}
+
+void silc_screen_init_upper_status_line(SilcScreen screen)
+{
+  int i;
+  int justify;
+  
+  assert(screen != NULL);
+
+  /* Create upper status line */
+  screen->upper_stat_line = newwin(0, COLS, 0, 0);
+  scrollok(screen->upper_stat_line, FALSE);
+  wattrset(screen->upper_stat_line, A_REVERSE);
+  
+  /* Print empty line */
+  for (i = 0; i < COLS - 1; i++)
+    mvwprintw(screen->upper_stat_line, 0, i, " ");
+  
+  /* Print stuff with justify */
+  justify = COLS / 5;
+  mvwprintw(screen->upper_stat_line, 0, 1, "%s %s", 
+           screen->u_stat_line.program_name, 
+           screen->u_stat_line.program_version);
+  /*
+  mvwprintw(screen->upper_stat_line, 0, justify, "[Your Connection: %s]", 
+           stat.uconnect_status[stat.uconnect]);
+  mvwprintw(screen->upper_stat_line, 0, 
+           (justify + justify + justify), "[SILC: %s]", 
+           stat.silc_status[stat.silc]);
+  */
+
+  /* Prints clock on upper stat line */        
+  silc_screen_print_clock(screen);
+  wrefresh(screen->upper_stat_line);
+}
+
+void silc_screen_init_output_status_line(SilcScreen screen)
+{
+  int i;
+
+  assert(screen != NULL);
+
+  screen->output_stat_line = silc_calloc(1, sizeof(*screen->output_stat_line));
+  
+  screen->output_stat_line[0] = newwin(1, COLS, LINES - 2, 0);
+  scrollok(screen->output_stat_line[0], FALSE);
+  wattrset(screen->output_stat_line[0], A_REVERSE);
+  
+  /* print first just blank line */
+  for (i = 0; i < COLS - 1; i++)
+    mvwprintw(screen->output_stat_line[0], 0, i, " ");
+
+  /* Allocate bottom line */
+  screen->bottom_line = silc_calloc(1, sizeof(*screen->bottom_line));
+
+  wattrset(screen->output_stat_line[0], A_NORMAL);
+  wrefresh(screen->output_stat_line[0]);
+}
+
+void silc_screen_print_clock(SilcScreen screen)
+{
+  time_t curtime;
+  struct tm *tp;
+
+  curtime = time(0);
+  tp = localtime(&curtime);
+
+  mvwprintw(screen->upper_stat_line, 0, COLS - 8, "[%02d:%02d] ", 
+           tp->tm_hour, tp->tm_min);
+  wrefresh(screen->upper_stat_line);
+}
+
+/* Prints current cursor coordinates on some output stat line */
+
+void silc_screen_print_coordinates(SilcScreen screen, int win_index)
+{
+  wattrset(screen->output_stat_line[win_index], A_REVERSE);
+  mvwprintw(screen->output_stat_line[win_index], 0, COLS - 10,
+           "[%4d,%3d]", screen->input_pos, LINES);
+  wrefresh(screen->output_stat_line[win_index]);
+  wattrset(screen->output_stat_line[win_index], A_NORMAL);
+}
+
+/* Prints bottom line (the status line) of the screen. */
+
+void silc_screen_print_bottom_line(SilcScreen screen, int win_index)
+{
+  char buf[512];
+  SilcScreenBottomLine line = screen->bottom_line;
+  int i, len;
+
+  memset(buf, 0, sizeof(buf));
+
+  if (line->mode) {
+    len = strlen(line->mode);
+    strncat(buf, line->mode, len);
+  }
+
+  if (line->nickname) {
+    len = strlen(line->nickname);
+    strncat(buf, line->nickname, len > SILC_SCREEN_MAX_NICK_LEN ? 
+           SILC_SCREEN_MAX_NICK_LEN : len);
+  }
+
+  if (line->connection) {
+    len = strlen(line->connection);
+    strncat(buf, " via ", 5);
+    strncat(buf, line->connection, len > SILC_SCREEN_MAX_CONN_LEN ? 
+           SILC_SCREEN_MAX_CONN_LEN : len);
+  }
+
+  if (line->channel) {
+    len = strlen(line->channel);
+    strncat(buf, " ", 1);
+    strncat(buf, line->channel, len > SILC_SCREEN_MAX_CHANNEL_LEN ?
+           SILC_SCREEN_MAX_CHANNEL_LEN : len);
+  }
+
+  wattrset(screen->output_stat_line[win_index], A_REVERSE);
+
+  for (i = 0; i < COLS - 10; i++)
+    mvwprintw(screen->output_stat_line[win_index], 0, i, " ");
+
+  mvwprintw(screen->output_stat_line[win_index], 0, 0, " %s", buf);
+  silc_screen_print_coordinates(screen, win_index);
+  wrefresh(screen->output_stat_line[win_index]);
+  wattrset(screen->output_stat_line[win_index], A_NORMAL);
+}
+
+/* Refresh all windows */
+
+void silc_screen_refresh_all(SilcScreen screen)
+{
+  int i;
+
+  assert(screen != NULL);
+
+  redrawwin(screen->upper_stat_line);
+
+  for (i = 0; i < screen->output_win_count; i++) {
+    wrefresh(screen->output_win[i]);
+    redrawwin(screen->output_win[i]);
+  }
+
+  wrefresh(screen->input_win);
+  redrawwin(screen->input_win);
+}
+
+/* Refreshes a window */
+
+void silc_screen_refresh_win(WINDOW *win)
+{
+  assert(win != NULL);
+
+  redrawwin(win);
+  wrefresh(win);
+}
+
+/* Resets input window */
+
+void silc_screen_input_reset(SilcScreen screen)
+{
+  int i;
+
+  assert(screen != NULL);
+  for (i = 0; i < COLS - 1; i++)
+    mvwprintw(screen->input_win, 0, i, " ");
+  mvwprintw(screen->input_win, 0, 0, "");
+  wrefresh(screen->input_win);
+  screen->input_pos = 0;
+  screen->input_end = 0;
+  screen->cursor_pos = 0;
+  screen->virtual_window = 0;
+}
+
+/* Backspace. Removes one character from input windows. */
+
+void silc_screen_input_backspace(SilcScreen screen)
+{
+  WINDOW *win;
+  char *buffer;
+
+  assert(screen != NULL);
+  buffer = screen->input_buffer;
+  win = screen->input_win;
+
+  /* Return directly if at the start of input line */
+  if (screen->input_pos == 0)
+    return;
+
+  if (screen->virtual_window) {
+    if (screen->cursor_pos <= 10) {
+      int i;
+
+      /* Clear line */
+      for (i = 0; i < COLS; i++)
+        mvwprintw(win, 0, i, " ");
+      mvwprintw(win, 0, 0, "");
+
+      screen->virtual_window--;
+      
+      waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
+      screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
+      screen->input_end = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
+      screen->cursor_pos = (COLS - 5) + 1;
+      wrefresh(win);
+    }
+  }
+
+  screen->cursor_pos--;
+  screen->input_pos--;
+  screen->input_end--;
+  mvwdelch(win, 0, screen->cursor_pos);
+
+  if (screen->input_pos < screen->input_end)
+    /* Delete from inside the input line */
+    SILC_SCREEN_INPUT_DELETE(buffer, screen->input_pos, screen->input_end);
+  else
+    /* Delete from the end of the input line */
+    buffer[screen->input_pos] = 0;
+
+  wrefresh(win);
+}
+
+/* Switches insert on input window on/off */
+
+void silc_screen_input_insert(SilcScreen screen)
+{
+  assert(screen != NULL);
+
+  screen->insert = screen->insert == TRUE ? FALSE : TRUE;
+}
+
+/* Moves cursor one character length to rightward */
+
+void silc_screen_input_cursor_right(SilcScreen screen)
+{
+  WINDOW *win;
+  char *buffer;
+
+  assert(screen != NULL);
+  buffer = screen->input_buffer;
+  win = screen->input_win;
+
+  /* Return directly if we are at the end of input line */
+  if (screen->cursor_pos >= SILC_SCREEN_INPUT_WIN_SIZE)
+    return;
+
+  /* Make sure cursor doesn't advance over the end of the line */
+  if (screen->input_pos >= screen->input_end)
+    return;
+
+  /* When cursor advances enough we switch to new window and show
+     rest of the typed characters on the screen. */
+  if (screen->cursor_pos >= (COLS - 5)) {
+    int i;
+
+    /* Clear line */
+    for (i = 0; i < COLS; i++)
+      mvwprintw(win, 0, i, " ");
+    mvwprintw(win, 0, 0, "");
+
+    waddnstr(win, &buffer[screen->input_pos - 10], 
+            ((screen->input_pos - 10) - screen->input_end >= COLS) ?
+            COLS : (screen->input_pos - 10) - screen->input_end);
+    screen->cursor_pos = 10;
+    wrefresh(win);
+
+    screen->virtual_window++;
+  }
+
+  screen->cursor_pos++;
+  screen->input_pos++;
+  wmove(win, 0, screen->cursor_pos);
+  wrefresh(win);
+}
+
+/* Moves cursor one character length to leftward */
+
+void silc_screen_input_cursor_left(SilcScreen screen)
+{
+  WINDOW *win;
+  char *buffer;
+
+  assert(screen != NULL);
+  buffer = screen->input_buffer;
+  win = screen->input_win;
+
+  /* Return directly if at the start of input line */
+  if (screen->input_pos == 0)
+    return;
+
+  /* When cursor advances enough we switch to new window and show
+     rest of the typed characters on the screen. */
+  if (screen->virtual_window) {
+    if (screen->cursor_pos <= 10) {
+      int i;
+
+      /* Clear line */
+      for (i = 0; i < COLS; i++)
+        mvwprintw(win, 0, i, " ");
+      mvwprintw(win, 0, 0, "");
+
+      screen->virtual_window--;
+      
+      waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
+      screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
+      screen->cursor_pos = (COLS - 5) + 1;
+      wrefresh(win);
+    }
+  }
+
+  screen->cursor_pos--;
+  screen->input_pos--;
+  wmove(win, 0, screen->cursor_pos);
+  wrefresh(win);
+}
+
+/* Moves cursor at the very start of the input line */
+
+void silc_screen_input_cursor_home(SilcScreen screen)
+{
+  WINDOW *win;
+  char *buffer;
+
+  assert(screen != NULL);
+  buffer = screen->input_buffer;
+  win = screen->input_win;
+
+  wclear(win);
+  waddnstr(win, &buffer[0], COLS);
+  wrefresh(win);
+
+  screen->input_pos = 0;
+  screen->cursor_pos = 0;
+  screen->virtual_window = 0;
+}
+
+/* Moves cursor at the very end of the input line */
+
+void silc_screen_input_cursor_end(SilcScreen screen)
+{
+  WINDOW *win;
+  char *buffer;
+
+  assert(screen != NULL);
+  buffer = screen->input_buffer;
+  win = screen->input_win;
+
+  wclear(win);
+  waddnstr(win, &buffer[screen->input_end - 10], 10);
+  wrefresh(win);
+
+  screen->input_pos = screen->input_end;
+  screen->cursor_pos = 10;
+  /* XXX */
+  screen->virtual_window = 0;
+}
+
+/* Prints typed character into the input window for user to see. Character 
+   attributes must be set separately outside this function. */
+
+void silc_screen_input_print(SilcScreen screen, unsigned char c)
+{
+  WINDOW *win;
+  char *buffer;
+
+  assert(screen != NULL);
+  buffer = screen->input_buffer;
+  win = screen->input_win;
+
+  /* Return directly if input window is full */
+  if (screen->input_pos >= SILC_SCREEN_INPUT_WIN_SIZE)
+    return;
+
+  /* The input window is COLS wide but one can type into it at most
+     SILC_SCREEN_INPUT_SIZE characters. When COLS - 5 characters is
+     typed the window is cleared and the cursor is moved at the tenth
+     character in the input window. Ten last typed character is then
+     showed at the start of the window. */
+  if (screen->cursor_pos >= (COLS - 5)) {
+    int i;
+
+    /* Clear line */
+    for (i = 0; i < COLS; i++)
+      mvwprintw(win, 0, i, " ");
+    mvwprintw(win, 0, 0, "");
+
+    /* Show ten last typed characters from the buffer on the screen */
+    waddnstr(win, &buffer[screen->input_pos - 10], 10);
+    screen->cursor_pos = 10;
+    wrefresh(win);
+
+    screen->virtual_window++;
+  }
+
+  if (screen->input_pos < screen->input_end) {
+    /* User moved cursor into the typed line. We are not adding 
+       character at the end of the line anymore */
+
+    if (screen->insert == FALSE) {
+      /* Add new character somewhere inside typed line. The input
+        line position is not advanced since a character was replaced
+        by the new character. */
+      waddch(win, c);
+      buffer[screen->input_pos] = c;
+      screen->cursor_pos++;
+      screen->input_pos++;
+      screen->input_end = screen->input_pos;
+    } else {
+      /* Insert new character somewhere inside typed line. Other
+        characters are moved forward. We must advance the input line
+        posititon. */
+      winsch(win, c);
+      wmove(win, 0, screen->cursor_pos + 1);
+      SILC_SCREEN_INPUT_INSERT(buffer, screen->input_pos, 
+                              c, screen->input_end);
+      screen->cursor_pos++;
+      screen->input_pos++;
+      screen->input_end++;
+    }
+  } else {
+    /* Add new character at the end of input line */
+    waddch(win, c);
+    buffer[screen->input_pos] = c;
+    screen->input_pos++;
+    screen->cursor_pos++;
+    screen->input_end = screen->input_pos;
+  }
+
+  /* Advance the cursor position. Cursor moves one to rightward always */
+  wrefresh(win);
+}
+
+/* Prints prompt to the input window. Cursors position aftern printing
+   is length of the prompt. */
+
+void silc_screen_input_print_prompt(SilcScreen screen, char *prompt)
+{
+  WINDOW *win;
+
+  assert(screen != NULL);
+  win = screen->input_win;
+
+  wclear(win);
+  waddnstr(win, prompt, strlen(prompt));
+  wrefresh(win);
+
+  screen->input_pos = strlen(prompt);
+  screen->cursor_pos = strlen(prompt);
+  screen->virtual_window = 0;
+}
diff --git a/apps/silc/screen.h b/apps/silc/screen.h
new file mode 100644 (file)
index 0000000..25d083b
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+
+  screen.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SCREEN_H
+#define SCREEN_H
+
+typedef struct {
+  char *mode;
+  char *nickname;
+  char *connection;
+  char *channel;
+} *SilcScreenBottomLine;
+
+typedef struct {
+  /* Status line window top of the screen */
+  WINDOW *upper_stat_line;
+
+  /* Output windows */
+  WINDOW **output_win;
+  WINDOW **output_stat_line;
+  unsigned int output_win_count;
+
+  /* Input window at the bottom of the screen */
+  WINDOW *input_win;
+  unsigned char *input_buffer;
+  unsigned int input_pos;
+  unsigned int input_end;
+  unsigned int cursor_pos;
+  int virtual_window;
+
+  /* Bottom line on screen */
+  SilcScreenBottomLine bottom_line;
+
+  /* On/off flag for insert */
+  int insert;
+
+  /* XXX */
+  struct upper_status_line {
+    char *program_name;
+    char *program_version;
+  } u_stat_line;
+
+} SilcScreenObject;
+
+typedef SilcScreenObject *SilcScreen;
+
+/* Size of the input window. User can type this many characters into
+   the window. After that no more characters may be added into the 
+   window. */
+#define SILC_SCREEN_INPUT_WIN_SIZE 1024
+
+/* Maximum length of nickaname that will be shown on the screen */
+#define SILC_SCREEN_MAX_NICK_LEN 16
+
+/* Maximum length of channel name that will be shown on the screen */
+#define SILC_SCREEN_MAX_CHANNEL_LEN 20
+
+/* Maximum length of connection name that will be shown on the screen */
+#define SILC_SCREEN_MAX_CONN_LEN 20
+
+/* Macros */
+
+/* Macro used to insert typed character into the buffer. The character
+   is not added at the end of the buffer but somewhere in between. */
+#define SILC_SCREEN_INPUT_INSERT(__x, __y, __ch, __end)        \
+do {                                                   \
+  unsigned char __tmp[SILC_SCREEN_INPUT_WIN_SIZE + 1]; \
+  memcpy(__tmp, &(__x)[(__y)], (__end) - (__y));       \
+  (__x)[(__y)] = __ch;                                 \
+  memcpy(&(__x)[(__y) + 1], __tmp, (__end) - (__y));   \
+} while(0)
+
+/* Macro used to delete character from the buffer. The character
+   is not removed from the end of the buffer but somewhere in between. */
+#define SILC_SCREEN_INPUT_DELETE(__x, __y, __end)      \
+do {                                                   \
+  unsigned char __tmp[SILC_SCREEN_INPUT_WIN_SIZE + 1]; \
+  memcpy(__tmp, &(__x)[(__y) + 1], (__end));           \
+  memset(&(__x)[(__y)], 0, (__end) - (__y) + 1);       \
+  memcpy(&(__x)[(__y)], __tmp, strlen(__tmp));         \
+} while(0)
+
+/* Prototypes */
+SilcScreen silc_screen_init();
+WINDOW *silc_screen_create_output_window(SilcScreen screen);
+WINDOW *silc_screen_add_output_window(SilcScreen screen);
+void silc_screen_create_input_window(SilcScreen screen);
+void silc_screen_init_upper_status_line(SilcScreen screen);
+void silc_screen_init_output_status_line(SilcScreen screen);
+void silc_screen_print_clock(SilcScreen screen);
+void silc_screen_print_coordinates(SilcScreen screen, int win_index);
+void silc_screen_print_bottom_line(SilcScreen screen, int win_index);
+void silc_screen_refresh_all(SilcScreen screen);
+void silc_screen_refresh_win(WINDOW *win);
+void silc_screen_input_reset(SilcScreen screen);
+void silc_screen_input_backspace(SilcScreen screen);
+void silc_screen_input_insert(SilcScreen screen);
+void silc_screen_input_cursor_right(SilcScreen screen);
+void silc_screen_input_cursor_left(SilcScreen screen);
+void silc_screen_input_cursor_home(SilcScreen screen);
+void silc_screen_input_cursor_end(SilcScreen screen);
+void silc_screen_input_print(SilcScreen screen, unsigned char c);
+void silc_screen_input_print_prompt(SilcScreen screen, char *prompt);
+
+#endif
diff --git a/apps/silc/silc.c b/apps/silc/silc.c
new file mode 100644 (file)
index 0000000..fa4c189
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+
+  silc.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "clientincludes.h"
+#include "version.h"
+
+/* Long command line options */
+static struct option long_opts[] = 
+{
+  /* Generic options */
+  { "server", 1, NULL, 's' },
+  { "port", 1, NULL, 'p' },
+  { "nickname", 1, NULL, 'n' },
+  { "channel", 1, NULL, 'c' },
+  { "cipher", 1, NULL, 'r' },
+  { "public-key", 1, NULL, 'b' },
+  { "private-key", 1, NULL, 'k' },
+  { "config-file", 1, NULL, 'f' },
+  { "no-silcrc", 0, NULL, 'q' },
+  { "help", 0, NULL, 'h' },
+  { "version", 0, NULL, 'V' },
+  { "list-ciphers", 0, NULL, 1 },
+  { "list-hash-funcs", 0, NULL, 2 },
+  { "list-pkcs", 0, NULL, 3 },
+
+  /* Key management options */
+  { "create-key-pair", 0, NULL, 'C' },
+  { "pkcs", 1, NULL, 10 },
+  { "bits", 1, NULL, 11 },
+
+  { NULL, 0, NULL, 0 }
+};
+
+/* Command line option variables */
+static char *opt_server = NULL;
+static int opt_port = 0;
+static char *opt_nickname = NULL;
+static char *opt_channel = NULL;
+static char *opt_cipher = NULL;
+static char *opt_public_key = NULL;
+static char *opt_private_key = NULL;
+static char *opt_config_file = NULL;
+static int opt_no_silcrc = FALSE;
+
+static int opt_create_keypair = FALSE;
+static char *opt_pkcs = NULL;
+static int opt_bits = 0;
+
+/* Prints out the usage of silc client */
+
+void usage()
+{
+  printf("\
+Usage: silc [options]\n\
+\n\
+  Generic Options:\n\
+  -s, --server=HOST            Open connection to server HOST\n\
+  -p, --port=PORT              Set PORT as default port to connect\n\
+  -n, --nickname=STRING        Set default nickname on startup\n\
+  -c, --channel=STRING         Join channel on startup\n\
+  -r, --cipher=CIPHER          Use CIPHER as default cipher in SILC\n\
+  -b, --public-key=FILE        Public key used in SILC\n\
+  -k, --private-key=FILE       Private key used in SILC\n\
+  -f, --config-file=FILE       Alternate configuration file\n\
+  -q, --no-silcrc              Don't load ~/.silcrc on startup\n\
+  -h, --help                   Display this help message\n\
+  -V, --version                Display version\n\
+      --list-ciphers           List supported ciphers\n\
+      --list-hash-funcs        List supported hash functions\n\
+      --list-pkcs              List supported PKCS's\n\
+\n\
+  Key Management Options:\n\
+  -C, --create-key-pair        Create new public key pair\n\
+      --pkcs=PKCS              Set the PKCS of the public key pair\n\
+      --bits=VALUE             Set length of the public key pair\n\
+\n");
+}
+
+int main(int argc, char **argv)
+{
+  int opt, option_index = 1;
+  int ret;
+  SilcClient silc = NULL;
+  SilcClientConfig config = NULL;
+  
+  if (argc > 1) 
+    {
+      while ((opt = 
+             getopt_long(argc, argv,
+                         "s:p:n:c:b:k:f:qhVC",
+                         long_opts, &option_index)) != EOF)
+       {
+         switch(opt) 
+           {
+             /* 
+              * Generic options
+              */
+           case 's':
+             if (optarg)
+               opt_server = strdup(optarg);
+             break;
+           case 'p':
+             if (optarg)
+               opt_port = atoi(optarg);
+             break;
+           case 'n':
+             if (optarg)
+               opt_nickname = strdup(optarg);
+             break;
+           case 'c':
+             if (optarg)
+               opt_channel = strdup(optarg);
+             break;
+           case 'r':
+             if (optarg)
+               opt_cipher = strdup(optarg);
+             break;
+           case 'b':
+             if (optarg)
+               opt_public_key = strdup(optarg);
+             break;
+           case 'k':
+             if (optarg)
+               opt_private_key = strdup(optarg);
+             break;
+           case 'f':
+             if (optarg)
+               opt_config_file = strdup(optarg);
+             break;
+           case 'q':
+             opt_no_silcrc = TRUE;
+             break;
+           case 'h':
+             usage();
+             exit(0);
+             break;
+           case 'V':
+             printf("\
+SILC Secure Internet Live Conferencing, version %s\n", 
+                    silc_version);
+             printf("\
+(c) 1997 - 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>\n");
+             exit(0);
+             break;
+           case 1:
+             silc_client_list_ciphers();
+             exit(0);
+             break;
+           case 2:
+             silc_client_list_hash_funcs();
+             exit(0);
+             break;
+           case 3:
+             silc_client_list_pkcs();
+             exit(0);
+             break;
+
+             /*
+              * Key management options
+              */
+           case 'C':
+             opt_create_keypair = TRUE;
+             break;
+           case 10:
+             if (optarg)
+               opt_pkcs = strdup(optarg);
+             break;
+           case 11:
+             if (optarg)
+               opt_bits = atoi(optarg);
+             break;
+
+           default:
+             exit(0);
+             break;
+           }
+       }
+    }
+
+  /* Init signals */
+  signal(SIGHUP, SIG_DFL);
+  signal(SIGTERM, SIG_DFL);
+  signal(SIGPIPE, SIG_IGN);
+  signal(SIGCHLD, SIG_DFL);
+  signal(SIGALRM, SIG_IGN);
+  signal(SIGQUIT, SIG_IGN);
+  signal(SIGSEGV, SIG_DFL);
+  signal(SIGBUS, SIG_DFL);
+  signal(SIGFPE, SIG_DFL);
+  //  signal(SIGINT, SIG_IGN);
+  
+  /* Default configuration file */
+  if (!opt_config_file)
+    opt_config_file = strdup(SILC_CLIENT_CONFIG_FILE);
+
+  /* Read global configuration file. */
+  config = silc_client_config_alloc(opt_config_file);
+  if (config == NULL)
+    goto fail;
+
+  if (opt_create_keypair == TRUE) {
+    /* Create new key pair and exit */
+    silc_client_create_key_pair(opt_pkcs, opt_bits);
+    exit(0);
+  }
+
+  /* Read local configuration file */
+
+
+  /* Allocate new client */
+  ret = silc_client_alloc(&silc);
+  if (ret == FALSE)
+    goto fail;
+
+  /* Initialize the client */
+  silc->config = config;
+  ret = silc_client_init(silc);
+  if (ret == FALSE)
+    goto fail;
+
+  /* Run the client */
+  silc_client_run(silc);
+
+  /* Stop the client. This probably has been done already but it
+     doesn't hurt to do it here again. */
+  silc_client_stop(silc);
+  silc_client_free(silc);
+  
+  exit(0);
+
+ fail:
+  if (config)
+    silc_client_config_free(config);
+  if (silc)
+    silc_client_free(silc);
+  exit(1);
+}
diff --git a/apps/silc/silc.h b/apps/silc/silc.h
new file mode 100644 (file)
index 0000000..baa83b3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+
+  silc.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILC_H
+#define SILC_H
+
+/* Default client configuration file. This can be overridden at the
+   compilation time. Otherwise, use default. This can be overridden on
+   command line as well. */
+#ifndef SILC_CLIENT_CONFIG_FILE
+#define SILC_CLIENT_CONFIG_FILE "/etc/silc/silc.conf"
+#endif
+
+/* Default user configuration file. This file is searched from users'
+   home directory. This may override global configuration settings. */
+#define SILC_CLIENT_HOME_CONFIG_FILE ".silcrc"
+
+#endif
diff --git a/apps/silc/testi.conf b/apps/silc/testi.conf
new file mode 100644 (file)
index 0000000..72dbaed
--- /dev/null
@@ -0,0 +1,21 @@
+[cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[hash]
+md5::64:16
+sha1::64:20
+
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+[connection]
+#lassi.kuo.fi.ssh.com:passwd::1333
+
+[commands]
+#/server lassi.kuo.fi.ssh.com:1333
+#/server lassi:1334
+#/server leevi:1333
diff --git a/apps/silc/testi2.conf b/apps/silc/testi2.conf
new file mode 100644 (file)
index 0000000..e1fa600
--- /dev/null
@@ -0,0 +1,21 @@
+[cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[hash]
+md5::64:16
+sha1::64:20
+
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+[connection]
+#lassi.kuo.fi.ssh.com:passwd::1333
+
+[commands]
+#/server lassi:1333
+/server lassi:1334
+#/server leevi:1333
diff --git a/apps/silcd/Makefile.am b/apps/silcd/Makefile.am
new file mode 100644 (file)
index 0000000..385b8cc
--- /dev/null
@@ -0,0 +1,42 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = silcd
+
+silcd_SOURCES = \
+       protocol.c \
+       route.c \
+       server.c \
+       idlist.c \
+       command.c \
+       command_reply.c \
+       serverconfig.c \
+       serverid.c \
+       silcd.c \
+       server_version.c
+
+LDADD = -L. -L.. -L../lib -lsilc
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
+       -I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
+       -I../includes \
+       -I../lib/silcmath/gmp-3.0.1
diff --git a/apps/silcd/command.c b/apps/silcd/command.c
new file mode 100644 (file)
index 0000000..eba9c41
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+
+  command.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Server command list. */
+SilcServerCommand silc_command_list[] =
+{
+  SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(connect, CONNECT, 
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(restart, RESTART, 
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(close, CLOSE,
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(silcoper, SILCOPER,
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
+  SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
+
+  { NULL, 0 },
+};
+
+/* List of pending commands. */
+SilcServerCommandPending *silc_command_pending = NULL;
+
+/* Add new pending command to the list of pending commands. Currently
+   pending commands are executed from command replies, thus we can
+   execute any command after receiving some specific command reply.
+
+   The argument `reply_cmd' is the command reply from where the callback
+   function is to be called, thus, it IS NOT the command to be executed. */
+
+void silc_server_command_pending(SilcCommand reply_cmd,
+                                SilcCommandCb callback,
+                                void *context)
+{
+  SilcServerCommandPending *reply, *r;
+
+  reply = silc_calloc(1, sizeof(*reply));
+  reply->reply_cmd = reply_cmd;
+  reply->context = context;
+  reply->callback = callback;
+
+  if (silc_command_pending == NULL) {
+    silc_command_pending = reply;
+    return;
+  }
+
+  for (r = silc_command_pending; r; r = r->next) {
+    if (r->next == NULL) {
+      r->next = reply;
+      break;
+    }
+  }
+}
+
+/* Deletes pending command by reply command type. */
+
+void silc_server_command_pending_del(SilcCommand reply_cmd)
+{
+  SilcServerCommandPending *r, *tmp;
+  
+  if (silc_command_pending) {
+    if (silc_command_pending->reply_cmd == reply_cmd) {
+      silc_free(silc_command_pending);
+      silc_command_pending = NULL;
+      return;
+    }
+
+    for (r = silc_command_pending; r; r = r->next) {
+      if (r->next && r->next->reply_cmd == reply_cmd) {
+       tmp = r->next;
+       r->next = r->next->next;
+       silc_free(tmp);
+       break;
+      }
+    }
+  }
+}
+
+/* Free's the command context allocated before executing the command */
+
+static void silc_server_command_free(SilcServerCommandContext cmd)
+{
+  if (cmd) {
+    silc_command_free_payload(cmd->payload);
+    silc_free(cmd);
+  }
+}
+
+/* Sends command status message as command reply packet. */
+
+static void 
+silc_server_command_send_status_msg(SilcServerCommandContext cmd,
+                                   SilcCommand command,
+                                   SilcCommandStatus status,
+                                   unsigned char *msg,
+                                   unsigned int msg_len)
+{
+  SilcBuffer sp_buf, buffer;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
+  buffer = silc_command_encode_payload_va(command, 1, 
+                                         sp_buf->data, sp_buf->len);
+  silc_server_packet_send(cmd->server, cmd->sock,
+                         SILC_PACKET_COMMAND_REPLY, 0, 
+                         buffer->data, buffer->len, FALSE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(sp_buf);
+}
+
+/* Sends simple status message as command reply packet */
+
+static void 
+silc_server_command_send_status_reply(SilcServerCommandContext cmd,
+                                     SilcCommand command,
+                                     SilcCommandStatus status)
+{
+  SilcBuffer sp_buf, buffer;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  sp_buf = silc_command_encode_status_payload(status, NULL, 0);
+  buffer = silc_command_encode_payload_va(command, 1, 
+                                         sp_buf->data, sp_buf->len);
+  silc_server_packet_send(cmd->server, cmd->sock,
+                         SILC_PACKET_COMMAND_REPLY, 0, 
+                         buffer->data, buffer->len, FALSE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(sp_buf);
+}
+
+/* Server side of command WHOIS. Processes user's query and sends found 
+   results as command replies back to the client. */
+
+SILC_SERVER_CMD_FUNC(whois)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  char *tmp, *nick = NULL, *server = NULL;
+  unsigned int argc, count = 0, len;
+  SilcClientList *entry;
+  SilcBuffer sp_buf, packet;
+  unsigned char *id_string;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get the nickname@server string and parse it. */
+  tmp = silc_command_get_first_arg(cmd->payload, NULL);
+  if (tmp) {
+    if (strchr(tmp, '@')) {
+      len = strcspn(tmp, "@");
+      nick = silc_calloc(len + 1, sizeof(char));
+      memcpy(nick, tmp, len);
+      server = silc_calloc(strlen(tmp) - len, sizeof(char));
+      memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
+    } else {
+      nick = strdup(tmp);
+    }
+  } else {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Get the max count of reply messages allowed */
+  if (argc == 2) {
+    tmp = silc_command_get_next_arg(cmd->payload, NULL);
+    if (!tmp) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
+      if (nick)
+       silc_free(nick);
+      if (server)
+       silc_free(server);
+      goto out;
+    }
+    count = atoi(tmp);
+  }
+
+  /* Then, make the query from our local client list */
+  entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
+                                             nick, server);
+  if (!entry) {
+
+    /* If we are normal server and are connected to a router we will
+       make global query from the router. */
+    if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
+
+      goto ok;
+    }
+    
+    /* If we are router then we will check our global list as well. */
+    if (cmd->server->server_type == SILC_ROUTER) {
+      entry =
+       silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
+                                           nick, server);
+      if (!entry) {
+       silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
+                                           SILC_STATUS_ERR_NO_SUCH_NICK,
+                                           tmp, strlen(tmp));
+       goto out;
+      }
+      goto ok;
+    }
+
+    silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
+                                       SILC_STATUS_ERR_NO_SUCH_NICK,
+                                       tmp, strlen(tmp));
+    goto out;
+  }
+
+ ok:
+  /* XXX, works only for local server info */
+
+  /* Send WHOIS reply */
+  id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+  tmp = silc_command_get_first_arg(cmd->payload, NULL),
+  sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+
+  /* XXX */
+  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+    char nh[256], uh[256];
+    SilcSocketConnection hsock;
+
+    memset(uh, 0, sizeof(uh));
+    memset(nh, 0, sizeof(nh));
+
+    strncat(nh, entry->nickname, strlen(entry->nickname));
+    strncat(nh, "@", 1);
+    len = entry->router ? strlen(entry->router->server_name) :
+      strlen(cmd->server->server_name);
+    strncat(nh, entry->router ? entry->router->server_name :
+           cmd->server->server_name, len);
+
+    strncat(uh, entry->username, strlen(entry->username));
+    strncat(uh, "@", 1);
+    hsock = (SilcSocketConnection)entry->connection;
+    len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
+    strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+
+    /* XXX */
+    if (entry->userinfo)
+      packet = 
+        silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5, 
+                                      sp_buf->data, sp_buf->len,
+                                      id_string, SILC_ID_CLIENT_LEN,
+                                      nh, strlen(nh),
+                                      uh, strlen(uh),
+                                      entry->userinfo, 
+                                      strlen(entry->userinfo));
+    else
+      packet = 
+        silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
+                                      sp_buf->data, sp_buf->len,
+                                      id_string, SILC_ID_CLIENT_LEN,
+                                      nh, strlen(nh),
+                                      uh, strlen(uh));
+
+  } else {
+    /* XXX */
+    packet = 
+      silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4, 
+                                    sp_buf->data, sp_buf->len,
+                                    id_string, SILC_ID_CLIENT_LEN,
+                                    entry->nickname, strlen(entry->nickname),
+                                    tmp, strlen(tmp)); /* XXX */
+  }
+  silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+                         0, packet->data, packet->len, FALSE);
+
+  silc_free(id_string);
+  silc_buffer_free(packet);
+  silc_free(sp_buf);
+
+ out:
+  silc_server_command_free(cmd);
+}
+
+SILC_SERVER_CMD_FUNC(whowas)
+{
+}
+
+SILC_SERVER_CMD_FUNC(identify)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  char *tmp, *nick = NULL, *server = NULL;
+  unsigned int argc, count = 0, len;
+  SilcClientList *entry;
+  SilcBuffer sp_buf, packet;
+  unsigned char *id_string;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get the nickname@server string and parse it. */
+  tmp = silc_command_get_first_arg(cmd->payload, NULL);
+  if (tmp) {
+    if (strchr(tmp, '@')) {
+      len = strcspn(tmp, "@");
+      nick = silc_calloc(len + 1, sizeof(char));
+      memcpy(nick, tmp, len);
+      server = silc_calloc(strlen(tmp) - len, sizeof(char));
+      memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
+    } else {
+      nick = strdup(tmp);
+    }
+  } else {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Get the max count of reply messages allowed */
+  if (argc == 2) {
+    tmp = silc_command_get_next_arg(cmd->payload, NULL);
+    if (!tmp) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+                                           SILC_STATUS_ERR_TOO_MANY_PARAMS);
+      goto out;
+    }
+    count = atoi(tmp);
+  }
+
+  /* Then, make the query from our local client list */
+  entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
+                                         nick, cmd->server->md5hash);
+  if (!entry) {
+
+    /* If we are normal server and are connected to a router we will
+       make global query from the router. */
+    if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
+      SilcBuffer buffer = cmd->packet->buffer;
+
+      /* Forward the received IDENTIFY command to our router */
+      silc_buffer_push(buffer, buffer->data - buffer->head);
+      silc_server_packet_forward(cmd->server, (SilcSocketConnection)
+                                cmd->server->id_entry->router->connection,
+                                buffer->data, buffer->len,
+                                TRUE);
+      goto out;
+    }
+    
+    /* If we are router then we will check our global list as well. */
+    if (cmd->server->server_type == SILC_ROUTER) {
+      entry = 
+       silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
+                                       nick, cmd->server->md5hash);
+      if (!entry) {
+       silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
+                                           SILC_STATUS_ERR_NO_SUCH_NICK,
+                                           tmp, strlen(tmp));
+       goto out;
+      }
+      goto ok;
+    }
+
+    silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
+                                       SILC_STATUS_ERR_NO_SUCH_NICK,
+                                       tmp, strlen(tmp));
+    goto out;
+  }
+
+ ok:
+  /* Send IDENTIFY reply */
+  id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+  tmp = silc_command_get_first_arg(cmd->payload, NULL);
+  sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+  packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
+                                         sp_buf->data, sp_buf->len,
+                                         id_string, SILC_ID_CLIENT_LEN,
+                                         nick, strlen(nick));
+  if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
+    void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+    silc_server_packet_send_dest(cmd->server, cmd->sock, 
+                                SILC_PACKET_COMMAND_REPLY, 0,
+                                id, cmd->packet->src_id_type,
+                                packet->data, packet->len, FALSE);
+    silc_free(id);
+  } else
+    silc_server_packet_send(cmd->server, cmd->sock, 
+                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           packet->data, packet->len, FALSE);
+
+  silc_free(id_string);
+  silc_buffer_free(packet);
+  silc_free(sp_buf);
+
+ out:
+  if (nick)
+    silc_free(nick);
+  if (server)
+    silc_free(server);
+  silc_server_command_free(cmd);
+}
+
+/* Checks string for bad characters and returns TRUE if they are found. */
+
+static int silc_server_command_bad_chars(char *nick)
+{
+  if (strchr(nick, '\\')) return TRUE;
+  if (strchr(nick, '\"')) return TRUE;
+  if (strchr(nick, '´')) return TRUE;
+  if (strchr(nick, '`')) return TRUE;
+  if (strchr(nick, '\'')) return TRUE;
+  if (strchr(nick, '*')) return TRUE;
+  if (strchr(nick, '/')) return TRUE;
+  if (strchr(nick, '@')) return TRUE;
+
+  return FALSE;
+}
+
+/* Server side of command NICK. Sets nickname for user. Setting
+   nickname causes generation of a new client ID for the client. The
+   new client ID is sent to the client after changing the nickname. */
+
+SILC_SERVER_CMD_FUNC(nick)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
+  SilcServer server = cmd->server;
+  SilcBuffer packet, sp_buf;
+  SilcClientID *new_id;
+  char *id_string;
+  char *nick;
+
+  SILC_LOG_DEBUG(("Start"));
+
+#define LCC(x) server->local_list->client_cache[(x) - 32]
+#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+
+  /* Check number of arguments */
+  if (silc_command_get_arg_num(cmd->payload) < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Check nickname */
+  nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  if (silc_server_command_bad_chars(nick) == TRUE) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+                                         SILC_STATUS_ERR_BAD_NICKNAME);
+    goto out;
+  }
+
+  /* Create new Client ID */
+  silc_id_create_client_id(cmd->server->id, cmd->server->rng, 
+                          cmd->server->md5hash, nick,
+                          &new_id);
+
+  /* Send notify about nickname change to our router. We send the new
+     ID and ask to replace it with the old one. */
+  if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
+    silc_server_send_replace_id(server, server->id_entry->router->connection, 
+                               FALSE, id_entry->id,
+                               SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
+                               new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+
+  /* If we are router we have to distribute the new Client ID to all 
+     routers in SILC. */
+  if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
+    silc_server_send_replace_id(server, server->id_entry->router->connection,  
+                               TRUE, id_entry->id,
+                               SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
+                               new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+
+  /* Remove old cache entry */
+  silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
+                        LCCC(id_entry->nickname[0]), 
+                        SILC_ID_CLIENT, id_entry->id); 
+  
+  /* Free old ID */
+  if (id_entry->id) {
+    memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
+    silc_free(id_entry->id);
+  }
+
+  /* Save the nickname as this client is our local client */
+  if (id_entry->nickname)
+    silc_free(id_entry->nickname);
+
+  id_entry->nickname = strdup(nick);
+  id_entry->id = new_id;
+
+  /* Update client cache */
+  LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
+                                  id_entry->nickname, SILC_ID_CLIENT, 
+                                  id_entry->id, (void *)id_entry);
+
+  /* Send the new Client ID as reply command back to client */
+  id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
+  sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+  packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2, 
+                                         sp_buf->data, sp_buf->len,
+                                         id_string, SILC_ID_CLIENT_LEN);
+  silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+                         0, packet->data, packet->len, FALSE);
+
+  silc_free(id_string);
+  silc_buffer_free(packet);
+  silc_free(sp_buf);
+
+ out:
+  silc_server_command_free(cmd);
+#undef LCC
+#undef LCCC
+}
+
+SILC_SERVER_CMD_FUNC(list)
+{
+}
+
+SILC_SERVER_CMD_FUNC(topic)
+{
+}
+
+SILC_SERVER_CMD_FUNC(invite)
+{
+}
+
+/* Quits connection to client. This gets called if client won't
+   close the connection even when it has issued QUIT command. */
+
+SILC_TASK_CALLBACK(silc_server_command_quit_cb)
+{
+  SilcServer server = (SilcServer)context;
+  SilcSocketConnection sock = server->sockets[fd];
+
+  /* Free all client specific data, such as client entry and entires
+     on channels this client may be on. */
+  silc_server_free_sock_user_data(server, sock);
+
+  /* Close the connection on our side */
+  silc_server_close_connection(server, sock);
+}
+
+/* Quits SILC session. This is the normal way to disconnect client. */
+SILC_SERVER_CMD_FUNC(quit)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* We quit the connection with little timeout */
+  silc_task_register(server->timeout_queue, sock->sock,
+                    silc_server_command_quit_cb, server,
+                    0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+
+  silc_server_command_free(cmd);
+}
+
+SILC_SERVER_CMD_FUNC(kill)
+{
+}
+
+SILC_SERVER_CMD_FUNC(info)
+{
+}
+
+SILC_SERVER_CMD_FUNC(connect)
+{
+}
+
+SILC_SERVER_CMD_FUNC(ping)
+{
+}
+
+SILC_SERVER_CMD_FUNC(oper)
+{
+}
+
+typedef struct {
+  char *channel_name;
+  char *nickname;
+  char *username;
+  char *hostname;
+  SilcChannelList *channel;
+  SilcServer server;
+} JoinInternalContext;
+
+SILC_TASK_CALLBACK(silc_server_command_join_notify)
+{
+  JoinInternalContext *ctx = (JoinInternalContext *)context;
+
+  if (ctx->channel->key && ctx->channel->key_len) {
+    silc_server_send_notify_to_channel(ctx->server, ctx->channel,
+                                      "%s (%s@%s) has joined channel %s",
+                                      ctx->nickname, ctx->username,
+                                      ctx->hostname, ctx->channel_name);
+    silc_free(ctx);
+  } else {
+    silc_task_register(ctx->server->timeout_queue, fd,
+                      silc_server_command_join_notify, context,
+                      0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  }
+}
+
+/* Server side of command JOIN. Joins client into requested channel. If 
+   the channel does not exist it will be created. */
+
+SILC_SERVER_CMD_FUNC(join)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcBuffer buffer = cmd->packet->buffer;
+  int argc, i, tmp_len;
+  char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
+  unsigned char *passphrase;
+  SilcChannelList *channel;
+  SilcServerID *router_id;
+  SilcIDCache *id_cache;
+  SilcBuffer packet, sp_buf;
+  SilcClientList *client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+  /* Check number of parameters */
+  argc = silc_command_get_arg_num(cmd->payload);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 3) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get channel name */
+  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  if (silc_server_command_bad_chars(tmp) == TRUE) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_BAD_CHANNEL);
+    goto out;
+  }
+  channel_name = strdup(tmp);
+
+  /* Get passphrase */
+  tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
+  if (tmp) {
+    passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+    memcpy(passphrase, tmp, tmp_len);
+  }
+  
+  /* Get cipher name */
+  cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
+
+  /* See if the channel exists */
+  if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]), 
+                               channel_name, &id_cache) == FALSE) {
+    /* Channel not found */
+    id_cache = NULL;
+
+    /* If we are standalone server we don't have a router, we just create 
+       the channel by  ourselves. */
+    if (server->standalone) {
+      router_id = server->id;
+      channel = silc_server_new_channel(server, router_id, 
+                                       cipher, channel_name);
+      goto join_channel;
+    }
+
+    /* No channel ID found, the channel does not exist on our server.
+       We send JOIN command to our router which will handle the joining
+       procedure (either creates the channel if it doesn't exist or
+       joins the client to it) - if we are normal server. */
+    if (server->server_type == SILC_SERVER) {
+
+      /* Forward the received JOIN command to the router */
+      silc_buffer_push(buffer, buffer->data - buffer->head);
+      silc_server_packet_forward(server, (SilcSocketConnection)
+                                server->id_entry->router->connection,
+                                buffer->data, buffer->len,
+                                TRUE);
+      
+      /* Add the command to be pending. It will be re-executed after
+        router has replied back to us. */
+      cmd->pending = TRUE;
+      silc_server_command_pending(SILC_COMMAND_JOIN, 
+                                 silc_server_command_join, context);
+      return;
+    }
+  }
+
+  /* If we are router and the channel does not exist we will check our
+     global list for the channel. */
+  if (!id_cache && server->server_type == SILC_ROUTER) {
+
+    /* Notify all routers about the new channel in SILC network. */
+    if (!server->standalone) {
+#if 0
+      silc_server_send_new_id(server, server->id_entry->router->connection, 
+                             TRUE,
+                             xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
+#endif
+    }
+
+  }
+
+  channel = (SilcChannelList *)id_cache->context;
+
+ join_channel:
+
+  /* XXX must check whether the client already is on the channel */
+
+  /* Join the client to the channel */
+  i = channel->user_list_count;
+  channel->user_list = silc_realloc(channel->user_list, 
+                                   sizeof(*channel->user_list) * (i + 1));
+  channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
+
+  /* If the JOIN request was forwarded to us we will make a bit slower
+     query to get the client pointer. Otherwise, we get the client pointer
+     real easy. */
+  if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
+    client = (SilcClientList *)sock->user_data;
+    channel->user_list[i].client = client;
+  } else {
+    void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+    client = silc_idlist_find_client_by_id(server->local_list->clients, id);
+    channel->user_list[i].client = client;
+    silc_free(id);
+  }
+  channel->user_list_count++;
+
+  i = client->channel_count;
+  client->channel = silc_realloc(client->channel, 
+                                sizeof(*client->channel) * (i + 1));
+  client->channel[i] = channel;
+  client->channel_count++;
+
+  /* Notify router about new user on channel. If we are normal server
+     we send it to our router, if we are router we send it to our
+     primary route. */
+  if (!server->standalone) {
+
+  }
+
+  /* Send Channel ID to the client */
+  if (!cmd->pending) {
+    id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+    sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+    if (!channel->topic)
+      packet = 
+       silc_command_encode_payload_va(SILC_COMMAND_JOIN, 3,
+                                      sp_buf->data, sp_buf->len,
+                                      channel_name, strlen(channel_name),
+                                      id_string, SILC_ID_CHANNEL_LEN);
+    else
+      packet = 
+       silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
+                                      sp_buf->data, sp_buf->len,
+                                      channel_name, strlen(channel_name),
+                                      id_string, SILC_ID_CHANNEL_LEN,
+                                      channel->topic, 
+                                      strlen(channel->topic));
+
+    if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
+      void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+      silc_server_packet_send_dest(cmd->server, cmd->sock, 
+                                  SILC_PACKET_COMMAND_REPLY, 0,
+                                  id, cmd->packet->src_id_type,
+                                  packet->data, packet->len, FALSE);
+      silc_free(id);
+    } else
+      silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                             packet->data, packet->len, FALSE);
+    
+    silc_buffer_free(packet);
+    silc_free(sp_buf);
+  }
+
+  /* Send channel key to the client. Client cannot start transmitting
+     to the channel until we have sent the key. */
+  if (!cmd->pending) {
+    tmp_len = strlen(channel->channel_key->cipher->name);
+    packet = 
+      silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, 
+                                     id_string, tmp_len, 
+                                     channel->channel_key->cipher->name,
+                                     channel->key_len, channel->key);
+    
+    silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
+                           packet->data, packet->len, FALSE);
+    silc_buffer_free(packet);
+  }
+
+  if (id_string)
+    silc_free(id_string);
+
+  /* Finally, send notify message to all clients on the channel about
+     new user on the channel. */
+  if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
+    if (!cmd->pending) {
+      silc_server_send_notify_to_channel(server, channel,
+                                        "%s (%s@%s) has joined channel %s",
+                                        client->nickname, client->username,
+                                        sock->hostname ? sock->hostname :
+                                        sock->ip, channel_name);
+    } else {
+      /* This is pending command request. Send the notify after we have
+        received the key for the channel from the router. */
+      JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
+      ctx->channel_name = channel_name;
+      ctx->nickname = client->nickname;
+      ctx->username = client->username;
+      ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
+      ctx->channel = channel;
+      ctx->server = server;
+      silc_task_register(server->timeout_queue, sock->sock,
+                        silc_server_command_join_notify, ctx,
+                        0, 100000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    }
+  }
+
+ out:
+  silc_server_command_free(cmd);
+#undef LCC
+#undef LCCC
+}
+
+/* Server side of command MOTD. Sends servers current "message of the
+   day" to the client. */
+
+SILC_SERVER_CMD_FUNC(motd)
+{
+
+  SILC_LOG_DEBUG(("Start"));
+
+}
+
+SILC_SERVER_CMD_FUNC(umode)
+{
+}
+
+SILC_SERVER_CMD_FUNC(cmode)
+{
+}
+
+SILC_SERVER_CMD_FUNC(kick)
+{
+}
+
+SILC_SERVER_CMD_FUNC(restart)
+{
+}
+SILC_SERVER_CMD_FUNC(close)
+{
+}
+SILC_SERVER_CMD_FUNC(die)
+{
+}
+SILC_SERVER_CMD_FUNC(silcoper)
+{
+}
+
+SILC_SERVER_CMD_FUNC(leave)
+{
+}
+
+SILC_SERVER_CMD_FUNC(names)
+{
+}
diff --git a/apps/silcd/command.h b/apps/silcd/command.h
new file mode 100644 (file)
index 0000000..d7ed494
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+
+  servercommand.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+/* 
+   Structure holding one command and pointer to its function. 
+
+   SilcCommandCb cb
+
+       Callback function called when this command is executed.
+
+   SilcCommand cmd
+
+       The actual command. Defined in silccore/silccommand.h
+
+   SilcCommandFlag flags
+
+       Flags for the command. These set how command behaves on different
+       situations. 
+
+*/
+typedef struct {
+  SilcCommandCb cb;
+  SilcCommand cmd;
+  SilcCommandFlag flags;
+} SilcServerCommand;
+
+/* All server commands */
+extern SilcServerCommand silc_command_list[];
+
+/* Context sent as argument to all commands */
+typedef struct {
+  SilcServer server;
+  SilcSocketConnection sock;
+  SilcCommandPayload payload;
+  SilcPacketContext *packet;
+  int pending;
+} *SilcServerCommandContext;
+
+/* Structure holding pending commands. If command is pending it will be
+   executed after command reply has been received and executed. 
+   Pending commands are used in cases where the original command request
+   had to be forwarded to router. After router replies the pending
+   command is re-executed. */
+typedef struct SilcServerCommandPendingStruct {
+  SilcCommand reply_cmd;
+  void *context;
+  SilcCommandCb callback;
+
+  struct SilcServerCommandPendingStruct *next;
+} SilcServerCommandPending;
+
+/* List of pending commands */
+extern SilcServerCommandPending *silc_command_pending;
+
+/* Macros */
+
+/* Macro used for command declaration in command list structure */
+#define SILC_SERVER_CMD(func, cmd, flags) \
+{ silc_server_command_##func, SILC_COMMAND_##cmd, flags }
+
+/* Macro used to declare command functions */
+#define SILC_SERVER_CMD_FUNC(func) \
+void silc_server_command_##func(void *context)
+
+/* Macro used to execute commands */
+#define SILC_SERVER_COMMAND_EXEC(ctx)                          \
+do {                                                           \
+  SilcServerCommand *cmd;                                      \
+                                                               \
+  for (cmd = silc_command_list; cmd->cb; cmd++)                        \
+    if (cmd->cmd == silc_command_get(ctx->payload)) {          \
+      cmd->cb(ctx);                                            \
+      break;                                                   \
+    }                                                          \
+                                                               \
+  if (cmd == NULL) {                                           \
+    SILC_LOG_ERROR(("Unknown command, packet dropped"));       \
+    silc_free(ctx);                                            \
+    return;                                                    \
+  }                                                            \
+} while(0)
+
+/* Checks for pending commands */
+#define SILC_SERVER_COMMAND_CHECK_PENDING(ctx)         \
+do {                                                   \
+  if (silc_command_pending) {                          \
+    SilcServerCommandPending *r;                       \
+    SilcCommand cmd;                                   \
+                                                       \
+    cmd = silc_command_get(payload);                   \
+    for (r = silc_command_pending; r; r = r->next) {   \
+      if (r->reply_cmd == cmd) {                       \
+       ctx->context = r->context;                      \
+       ctx->callback = r->callback;                    \
+       break;                                          \
+      }                                                        \
+    }                                                  \
+  }                                                    \
+} while(0)
+
+/* Executed pending command */
+#define SILC_SERVER_COMMAND_EXEC_PENDING(ctx, cmd)     \
+do {                                                   \
+  if (ctx->callback) {                                 \
+    (*ctx->callback)(ctx->context);                    \
+    silc_server_command_pending_del(cmd);              \
+  }                                                    \
+} while(0)
+
+/* Prototypes */
+void silc_server_command_pending(SilcCommand reply_cmd,
+                                SilcCommandCb callback,
+                                void *context);
+void silc_server_command_pending_del(SilcCommand reply_cmd);
+SILC_SERVER_CMD_FUNC(whois);
+SILC_SERVER_CMD_FUNC(whowas);
+SILC_SERVER_CMD_FUNC(identify);
+SILC_SERVER_CMD_FUNC(newuser);
+SILC_SERVER_CMD_FUNC(nick);
+SILC_SERVER_CMD_FUNC(list);
+SILC_SERVER_CMD_FUNC(topic);
+SILC_SERVER_CMD_FUNC(invite);
+SILC_SERVER_CMD_FUNC(quit);
+SILC_SERVER_CMD_FUNC(kill);
+SILC_SERVER_CMD_FUNC(info);
+SILC_SERVER_CMD_FUNC(connect);
+SILC_SERVER_CMD_FUNC(ping);
+SILC_SERVER_CMD_FUNC(oper);
+SILC_SERVER_CMD_FUNC(pass);
+SILC_SERVER_CMD_FUNC(admin);
+SILC_SERVER_CMD_FUNC(join);
+SILC_SERVER_CMD_FUNC(motd);
+SILC_SERVER_CMD_FUNC(umode);
+SILC_SERVER_CMD_FUNC(cmode);
+SILC_SERVER_CMD_FUNC(kick);
+SILC_SERVER_CMD_FUNC(ignore);
+SILC_SERVER_CMD_FUNC(restart);
+SILC_SERVER_CMD_FUNC(close);
+SILC_SERVER_CMD_FUNC(die);
+SILC_SERVER_CMD_FUNC(silcoper);
+SILC_SERVER_CMD_FUNC(leave);
+SILC_SERVER_CMD_FUNC(names);
+
+#endif
diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c
new file mode 100644 (file)
index 0000000..57d0260
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+
+  command_reply.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+#include "command_reply.h"
+
+/* Server command reply list. Not all commands have reply function as
+   they are never sent as forwarded command packets by server. More
+   maybe added later if need appears. */
+SilcServerCommandReply silc_command_reply_list[] =
+{
+  SILC_SERVER_CMD_REPLY(join, JOIN),
+
+  { NULL, 0 },
+};
+
+/* Process received command reply. */
+
+void silc_server_command_reply_process(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcBuffer buffer)
+{
+  SilcServerCommandReplyContext ctx;
+  SilcCommandPayload payload;
+
+  /* Get command reply payload from packet */
+  payload = silc_command_parse_payload(buffer);
+  if (!payload) {
+    /* Silently ignore bad reply packet */
+    SILC_LOG_DEBUG(("Bad command reply packet"));
+    return;
+  }
+  
+  /* Allocate command reply context. This must be free'd by the
+     command reply routine receiving it. */
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->server = server;
+  ctx->sock = sock;
+  ctx->payload = payload;
+      
+  /* Check for pending commands and mark to be exeucted */
+  SILC_SERVER_COMMAND_CHECK_PENDING(ctx);
+  
+  /* Execute command reply */
+  SILC_SERVER_COMMAND_REPLY_EXEC(ctx);
+}
+
+/* Free command reply context and its internals. */
+
+void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
+{
+  if (cmd) {
+    silc_command_free_payload(cmd->payload);
+    silc_free(cmd);
+  }
+}
+
+/* Received reply for forwarded JOIN command. Router has created or joined
+   the client to the channel. We save some channel information locally
+   for future use. */
+
+SILC_SERVER_CMD_REPLY_FUNC(join)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcServer server = cmd->server;
+  SilcCommandStatus status;
+  SilcChannelID *id;
+  SilcChannelList *entry;
+  unsigned int argc;
+  unsigned char *id_string;
+  char *channel_name, *tmp;
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK)
+    goto out;
+
+  /* Get channel name */
+  tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+  if (!tmp)
+    goto out;
+
+  /* Get channel ID */
+  id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
+  if (!id_string)
+    goto out;
+
+  channel_name = strdup(tmp);
+
+  /* Add the channel to our local list. */
+  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+  silc_idlist_add_channel(&server->local_list->channels, channel_name, 
+                         SILC_CHANNEL_MODE_NONE, id, 
+                         server->id_entry->router, NULL, &entry);
+  LCCC(channel_name[0]) = silc_idcache_add(&LCC(channel_name[0]), 
+                                          LCCC(channel_name[0]),
+                                          channel_name, SILC_ID_CHANNEL, 
+                                          (void *)id, (void *)entry);
+  entry->global_users = TRUE;
+
+  /* Execute pending JOIN command so that the client who originally
+     wanted to join the channel will be joined after all. */
+  SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
+
+ out:
+  silc_server_command_reply_free(cmd);
+#undef LCC
+#undef LCCC
+}
diff --git a/apps/silcd/command_reply.h b/apps/silcd/command_reply.h
new file mode 100644 (file)
index 0000000..0e67aa2
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+
+  command_reply.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef COMMAND_REPLY_H
+#define COMMAND_REPLY_H
+
+/* Structure holding one command reply and pointer to its function. */
+typedef struct {
+  SilcCommandCb cb;
+  SilcCommand cmd;
+} SilcServerCommandReply;
+
+/* All server command replys */
+extern SilcServerCommandReply silc_command_reply_list[];
+
+/* Context sent as argument to all command reply functions */
+typedef struct {
+  SilcServer server;
+  SilcSocketConnection sock;
+  SilcCommandPayload payload;
+
+  /* If defined this executes the pending command. */
+  void *context;
+  SilcCommandCb callback;
+} *SilcServerCommandReplyContext;
+
+/* Macros */
+
+/* Macro used for command declaration in command reply list structure */
+#define SILC_SERVER_CMD_REPLY(func, cmd ) \
+{ silc_server_command_reply_##func, SILC_COMMAND_##cmd }
+
+/* Macro used to declare command reply functions */
+#define SILC_SERVER_CMD_REPLY_FUNC(func) \
+void silc_server_command_reply_##func(void *context)
+
+/* Macro used to execute command replies */
+#define SILC_SERVER_COMMAND_REPLY_EXEC(ctx)            \
+do {                                                   \
+  SilcServerCommandReply *cmd;                         \
+                                                       \
+  for (cmd = silc_command_reply_list; cmd->cb; cmd++)  \
+    if (cmd->cmd == silc_command_get(ctx->payload)) {  \
+      cmd->cb(ctx);                                    \
+      break;                                           \
+    }                                                  \
+                                                       \
+  if (cmd == NULL) {                                   \
+    silc_free(ctx);                                    \
+    return;                                            \
+  }                                                    \
+} while(0)
+
+/* Prototypes */
+void silc_server_command_reply_process(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcBuffer buffer);
+SILC_SERVER_CMD_REPLY_FUNC(join);
+
+#endif
diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c
new file mode 100644 (file)
index 0000000..aa8409a
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+
+  idlist.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "idlist.h"
+
+/* Adds a new server to the list. The pointer sent as argument is allocated
+   and returned. */
+
+void silc_idlist_add_server(SilcServerList **list, 
+                           char *server_name, int server_type,
+                           SilcServerID *id, SilcServerList *router,
+                           SilcCipher send_key, SilcCipher receive_key,
+                           SilcPKCS public_key, SilcHmac hmac, 
+                           SilcServerList **new_idlist)
+{
+  SilcServerList *last, *idlist;
+
+  SILC_LOG_DEBUG(("Adding new server to id list"));
+
+  idlist = silc_calloc(1, sizeof(*idlist));
+  if (idlist == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new server list object"));
+    *new_idlist = NULL;
+    return;
+  }
+
+  /* Set the pointers */
+  idlist->server_name = server_name;
+  idlist->server_type = server_type;
+  idlist->id = id;
+  idlist->router = router;
+  idlist->send_key = send_key;
+  idlist->receive_key = receive_key;
+  idlist->public_key = public_key;
+  idlist->hmac = hmac;
+  idlist->next = idlist;
+  idlist->prev = idlist;
+
+  /* First on the list? */
+  if (!*list) {
+    *list = idlist;
+    *new_idlist = idlist;
+    return;
+  }
+
+  /* Add it to the list */
+  last = (*list)->prev;
+  last->next = idlist;
+  (*list)->prev = idlist;
+  idlist->next = (*list);
+  idlist->prev = last;
+
+  if (new_idlist)
+    *new_idlist = idlist;
+}
+
+/* Adds a new client to the client list. This is called when new client 
+   connection is accepted to the server. This adds all the relevant data 
+   about the client and session with it to the list. This list is 
+   referenced for example when sending message to the client. */
+
+void silc_idlist_add_client(SilcClientList **list, char *nickname,
+                           char *username, char *userinfo,
+                           SilcClientID *id, SilcServerList *router,
+                           SilcCipher send_key, SilcCipher receive_key,
+                           SilcPKCS public_key, SilcHmac hmac, 
+                           SilcClientList **new_idlist)
+{
+  SilcClientList *last, *idlist;
+
+  SILC_LOG_DEBUG(("Adding new client to id list"));
+
+  idlist = silc_calloc(1, sizeof(*idlist));
+  if (idlist == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new client list object"));
+    return;
+  }
+
+  /* Set the pointers */
+  idlist->nickname = nickname;
+  idlist->username = username;
+  idlist->userinfo = userinfo;
+  idlist->id = id;
+  idlist->router = router;
+  idlist->send_key = send_key;
+  idlist->receive_key = receive_key;
+  idlist->public_key = public_key;
+  idlist->hmac = hmac;
+  idlist->next = idlist;
+  idlist->prev = idlist;
+
+  /* First on the list? */
+  if (!(*list)) {
+    *list = idlist;
+    if (new_idlist)
+      *new_idlist = idlist;
+    return;
+  }
+
+  /* Add it to the list */
+  last = (*list)->prev;
+  last->next = idlist;
+  (*list)->prev = idlist;
+  idlist->next = *list;
+  idlist->prev = last;
+
+  if (new_idlist)
+    *new_idlist = idlist;
+}
+
+/* Free client entry.  This free's everything. */
+
+void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry)
+{
+  if (entry) {
+    if (entry->nickname)
+      silc_free(entry->nickname);
+    if (entry->username)
+      silc_free(entry->username);
+    if (entry->userinfo)
+      silc_free(entry->userinfo);
+    if (entry->id)
+      silc_free(entry->id);
+    if (entry->send_key)
+      silc_cipher_free(entry->send_key);
+    if (entry->receive_key)
+      silc_cipher_free(entry->receive_key);
+    if (entry->public_key)
+      silc_pkcs_free(entry->public_key);
+    if (entry->hmac)
+      silc_hmac_free(entry->hmac);
+    if (entry->hmac_key) {
+      memset(entry->hmac_key, 0, entry->hmac_key_len);
+      silc_free(entry->hmac_key);
+    }
+
+    /* Last one in list? */
+    if (*list == entry && entry->next == entry) {
+      *list = NULL;
+      silc_free(entry);
+      return;
+    }
+
+    /* At the start of list? */
+    if (*list == entry && entry->next != entry) {
+      *list = entry->next;
+      entry->next->prev = entry->prev;
+      entry->prev->next = *list;
+      silc_free(entry);
+      return;
+    }
+
+    /* Remove from list */
+    entry->prev->next = entry->next;
+    entry->next->prev = entry->prev;
+    silc_free(entry);
+    return;
+  }
+}
+
+SilcClientList *
+silc_idlist_find_client_by_nickname(SilcClientList *list,
+                                   char *nickname,
+                                   char *server)
+{
+  SilcClientList *first, *entry;
+
+  SILC_LOG_DEBUG(("Finding client by nickname"));
+
+  if (!list)
+    return NULL;
+
+  first = entry = list;
+  if (!strcmp(entry->nickname, nickname)) {
+    SILC_LOG_DEBUG(("Found"));
+    return entry;
+  }
+  entry = entry->next;
+
+  while(entry != first) {
+    if (!strcmp(entry->nickname, nickname)) {
+      SILC_LOG_DEBUG(("Found"));
+      return entry;
+    }
+
+    entry = entry->next;
+  }
+
+  return NULL;
+}
+
+SilcClientList *
+silc_idlist_find_client_by_hash(SilcClientList *list,
+                               char *nickname, SilcHash md5hash)
+{
+  SilcClientList *first, *entry;
+  unsigned char hash[16];
+
+  SILC_LOG_DEBUG(("Finding client by nickname hash"));
+
+  if (!list)
+    return NULL;
+
+  /* Make hash of the nickname */
+  silc_hash_make(md5hash, nickname, strlen(nickname), hash);
+
+  first = entry = list;
+  if (entry && !SILC_ID_COMPARE_HASH(entry->id, hash)) {
+    SILC_LOG_DEBUG(("Found"));
+    return entry;
+  }
+  entry = entry->next;
+
+  while(entry != first) {
+    if (entry && !SILC_ID_COMPARE_HASH(entry->id, hash)) {
+      SILC_LOG_DEBUG(("Found"));
+      return entry;
+    }
+
+    entry = entry->next;
+  }
+
+  return NULL;
+}
+
+SilcClientList *
+silc_idlist_find_client_by_id(SilcClientList *list, SilcClientID *id)
+{
+  SilcClientList *first, *entry;
+
+  SILC_LOG_DEBUG(("Finding client by Client ID"));
+
+  if (!list)
+    return NULL;
+
+  first = entry = list;
+  if (entry && !SILC_ID_CLIENT_COMPARE(entry->id, id)) {
+    SILC_LOG_DEBUG(("Found"));
+    return entry;
+  }
+  entry = entry->next;
+
+  while(entry != first) {
+    if (entry && !SILC_ID_CLIENT_COMPARE(entry->id, id)) {
+      SILC_LOG_DEBUG(("Found"));
+      return entry;
+    }
+
+    entry = entry->next;
+  }
+
+  return NULL;
+}
+
+/* Adds new channel to the list. */
+
+void silc_idlist_add_channel(SilcChannelList **list, 
+                            char *channel_name, int mode,
+                            SilcChannelID *id, SilcServerList *router,
+                            SilcCipher channel_key,
+                            SilcChannelList **new_idlist)
+{
+  SilcChannelList *last, *idlist;
+
+  SILC_LOG_DEBUG(("Adding new channel to id list"));
+
+  idlist = silc_calloc(1, sizeof(*idlist));
+  if (idlist == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new channel list object"));
+    return;
+  }
+
+  /* Set the pointers */
+  idlist->channel_name = channel_name;
+  idlist->mode = mode;
+  idlist->id = id;
+  idlist->router = router;
+  idlist->channel_key = channel_key;
+  idlist->next = idlist;
+  idlist->prev = idlist;
+
+  /* First on the list? */
+  if (!*list) {
+    *list = idlist;
+    if (new_idlist)
+      *new_idlist = idlist;
+    return;
+  }
+
+  /* Add it to the list */
+  last = (*list)->prev;
+  last->next = idlist;
+  (*list)->prev = idlist;
+  idlist->next = (*list);
+  idlist->prev = last;
+
+  if (new_idlist)
+    *new_idlist = idlist;
+}
+
+SilcChannelList *
+silc_idlist_find_channel_by_id(SilcChannelList *list, SilcChannelID *id)
+{
+  SilcChannelList *first, *entry;
+
+  SILC_LOG_DEBUG(("Finding channel by Channel ID"));
+
+  if (!list)
+    return NULL;
+
+  first = entry = list;
+  if (entry && !SILC_ID_CHANNEL_COMPARE(entry->id, id)) {
+    SILC_LOG_DEBUG(("Found"));
+    return entry;
+  }
+  entry = entry->next;
+
+  while(entry != first) {
+    if (entry && !SILC_ID_CHANNEL_COMPARE(entry->id, id)) {
+      SILC_LOG_DEBUG(("Found"));
+      return entry;
+    }
+
+    entry = entry->next;
+  }
+
+  return NULL;
+}
+
+/* Free channel entry.  This free's everything. */
+
+void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry)
+{
+  if (entry) {
+    if (entry->channel_name)
+      silc_free(entry->channel_name);
+    if (entry->id)
+      silc_free(entry->id);
+    if (entry->topic)
+      silc_free(entry->topic);
+    if (entry->channel_key)
+      silc_cipher_free(entry->channel_key);
+    if (entry->key) {
+      memset(entry->key, 0, entry->key_len);
+      silc_free(entry->key);
+    }
+    memset(entry->iv, 0, sizeof(entry->iv));
+
+    if (entry->user_list_count)
+      silc_free(entry->user_list);
+
+    /* Last one in list? */
+    if (*list == entry && entry->next == entry) {
+      *list = NULL;
+      silc_free(entry);
+      return;
+    }
+
+    /* At the start of list? */
+    if (*list == entry && entry->next != entry) {
+      *list = entry->next;
+      entry->next->prev = entry->prev;
+      entry->prev->next = *list;
+      silc_free(entry);
+      return;
+    }
+
+    /* Remove from list */
+    entry->prev->next = entry->next;
+    entry->next->prev = entry->prev;
+    silc_free(entry);
+    return;
+  }
+}
diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h
new file mode 100644 (file)
index 0000000..b18b90d
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+
+  idlist.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef IDLIST_H
+#define IDLIST_H
+
+/* Forward declarations */
+typedef struct SilcServerListStruct SilcServerList;
+typedef struct SilcClientListStruct SilcClientList;
+typedef struct SilcChannelListStruct SilcChannelList;
+
+/* 
+   SILC Server list object.
+
+   This list holds information about servers in SILC network. However, 
+   contents of this list is highly dependent of what kind of server we are 
+   (normal server or router server) and whether the list is used as a local 
+   list or a global list. These factors dictates the contents of this list.
+
+   This list is defined as follows:
+
+   Server type   List type      Contents
+   =======================================================================
+   server        local list     Server itself
+   server        global list    NULL
+   router        local list     All servers is the cell
+   router        global list    All servers in the SILC network
+
+   Following short description of the fields:
+
+   char *server_name
+
+       Logical name of the server. There is no limit of the length of the
+       server name. This is usually the same name as defined in DNS.
+
+   int server_type
+
+       Type of the server. SILC_SERVER or SILC_ROUTER are the possible
+       choices for this.
+
+   SilcServerID *id
+
+       ID of the server. This includes all the relevant information about
+       the server SILC will ever need. These are also the informations
+       that is broadcasted between servers and routers in the SILC network.
+
+   struct SilcServerListStruct *router
+
+       This is a pointer back to the server list. This is the router server 
+       where this server is connected to. If this is the router itself and 
+       it doesn't have a route this is NULL.
+
+   SilcCipher send_key
+   
+   SilcCipher receive_key
+
+   void *connection
+
+       A pointer, usually, to the socket list for fast referencing to
+       the data used in connection with this server.  This may be anything
+       but as just said, this is usually pointer to the socket connection
+       list.
+   
+*/
+struct SilcServerListStruct {
+  char *server_name;
+  int server_type;
+  SilcServerID *id;
+
+  /* Pointer to the router */
+  struct SilcServerListStruct *router;
+
+  /* Keys */
+  SilcCipher send_key;
+  SilcCipher receive_key;
+  SilcPKCS public_key;
+  SilcHmac hmac;
+  unsigned char *hmac_key;
+  unsigned int hmac_key_len;
+
+  /* Connection data */
+  void *connection;
+
+  struct SilcServerListStruct *next;
+  struct SilcServerListStruct *prev;
+};
+
+/* 
+   SILC Client list object.
+
+   This list holds information about connected clients ie. users in the SILC
+   network. The contents of this list is depended on whether we are normal 
+   server or router server and whether the list is a local or global list.
+
+   This list is defined as follows:
+
+   Server type   List type      Contents
+   =======================================================================
+   server        local list     All clients in server
+   server        global list    NULL
+   router        local list     All clients in cell
+   router        global list    All clients in SILC
+
+   Following short description of the fields:
+
+   char username
+
+       Client's (meaning user's) real name. This is defined in following 
+       manner:
+
+       Server type   List type      Contents
+       ====================================================
+       server        local list     User's name
+       router        local list     NULL
+       router        global list    NULL
+
+       Router doesn't hold this information since it is not vital data 
+       for the router. If this information is needed by the client it is
+       fetched when it is needed.
+
+   char userinfo
+
+       Information about user. This is free information and can be virtually
+       anything. This is defined in following manner:
+       
+       Server type   List type      Contents
+       ====================================================
+       server        local list     User's information
+       router        local list     NULL
+       router        global list    NULL
+
+       Router doesn't hold this information since it is not vital data 
+       for the router. If this information is needed by the client it is
+       fetched when it is needed.
+
+   SilcClientID *id
+
+       ID of the client. This includes all the information SILC will ever
+       need. Notice that no nickname of the user is saved anywhere. This is
+       beacuse of SilcClientID includes 88 bit hash value of the user's 
+       nickname which can be used to track down specific user by their 
+       nickname. Nickname is not relevant information that would need to be 
+       saved as plain.
+
+   int mode
+
+       Client's mode.  Client maybe for example server operator or
+       router operator (SILC operator).
+
+   SilcServerList *router
+
+       This is a pointer to the server list. This is the router server whose 
+       cell this client is coming from. This is used to route messages to 
+       this client.
+
+   SilcCipher session_key
+
+       The actual session key established by key exchange protcol between
+       connecting parties. This is used for both encryption and decryption.
+
+   SilcPKCS public_key
+
+       Public key of the client. This maybe NULL.
+
+   SilcHmac hmac
+   unsigned char *hmac_key
+   unsigned int hmac_key_len
+
+       MAC key used to compute MAC's for packets. 
+
+   void *connection
+
+       A pointer, usually, to the socket list for fast referencing to
+       the data used in connection with this client.  This may be anything
+       but as just said, this is usually pointer to the socket connection
+       list.
+
+*/
+struct SilcClientListStruct {
+  char *nickname;
+  char *username;
+  char *userinfo;
+  SilcClientID *id;
+  int mode;
+
+  /* Pointer to the router */
+  SilcServerList *router;
+
+  /* Pointers to channels this client has joined */
+  SilcChannelList **channel;
+  unsigned int channel_count;
+
+  /* Keys */
+  SilcCipher send_key;
+  SilcCipher receive_key;
+  SilcPKCS public_key;
+  SilcHmac hmac;
+  unsigned char *hmac_key;
+  unsigned int hmac_key_len;
+
+  /* Connection data */
+  void *connection;
+
+  struct SilcClientListStruct *next;
+  struct SilcClientListStruct *prev;
+};
+
+/* 
+   SILC Channel Client list structure.
+
+   This list used only by the SilcChannelList object and it holds information 
+   about current clients (ie. users) on channel. Following short description 
+   of the fields:
+
+   SilcClientList client
+
+       Pointer to the client list. This is the client currently on channel.
+
+   int mode
+
+       Client's current mode on the channel.
+
+*/
+typedef struct SilcChannelClientListStruct {
+  SilcClientList *client;
+  int mode;
+} SilcChannelClientList;
+
+/* 
+   SILC Channel list object.
+
+   This list holds information about channels in SILC network. The contents 
+   of this list is depended on whether we are normal server or router server 
+   and whether the list is a local or global list.
+
+   This list is defined as follows:
+
+   Server type   List type      Contents
+   =======================================================================
+   server        local list     All channels in server
+   server        global list    NULL
+   router        local list     All channels in cell
+   router        global list    All channels in SILC
+
+   Following short description of the fields:
+
+   char *channel_name
+
+       Logical name of the channel.
+
+   int mode
+
+       Current mode of the channel.
+
+   SilcChannelID *id
+
+       ID of the channel. This includes all the information SILC will ever
+       need.
+
+   int global_users
+       Boolean value to tell whether there are users outside this server
+       on this channel. This is set to TRUE if router sends message to
+       the server that there are users outside your server on your
+       channel as well. This way server knows that messages needs to be
+       sent to the router for further routing. If this is a normal 
+       server and this channel is not created on this server this field
+       is always TRUE. If this server is a router this field is ignored.
+
+   char *topic
+
+       Current topic of the channel.
+
+   SilcServerList *router
+
+       This is a pointer to the server list. This is the router server 
+       whose cell this channel belongs to. This is used to route messages 
+       to this channel.
+
+   SilcCipher send_key
+
+
+   SilcCipher receive_key
+
+*/
+struct SilcChannelListStruct {
+  char *channel_name;
+  int mode;
+  SilcChannelID *id;
+  int global_users;
+  char *topic;
+
+  /* List of users on channel */
+  SilcChannelClientList *user_list;
+  unsigned int user_list_count;
+
+  /* Pointer to the router */
+  SilcServerList *router;
+
+  /* Channel keys */
+  SilcCipher channel_key;
+  unsigned char *key;
+  unsigned int key_len;
+  unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+
+  struct SilcChannelListStruct *next;
+  struct SilcChannelListStruct *prev;
+};
+
+/* 
+   SILC ID List object.
+
+   As for remainder these lists are defined as follows:
+
+   List        Server type   List type      Contents
+   =======================================================================
+   servers     server        local list     Server itself
+   servers     server        global list    NULL
+   servers     router        local list     All servers in cell
+   servers     router        global list    All servers in SILC
+
+   clients     server        local list     All clients in server
+   clients     server        global list    NULL
+   clients     router        local list     All clients in cell
+   clients     router        global list    All clients in SILC
+
+   channels    server        local list     All channels in server
+   channels    server        global list    NULL
+   channels    router        local list     All channels in cell
+   channels    router        global list    All channels in SILC
+
+   As seen on the list normal server never defines a global list. This is
+   because of normal server don't know anything about anything global data,
+   they get it from the router if and when they need it. Routers, on the
+   other hand, always define local and global lists because routers really
+   know all the relevant data in the SILC network.
+
+*/
+typedef struct SilcIDListStruct {
+  SilcServerList *servers;
+  SilcClientList *clients;
+  SilcChannelList *channels;
+
+  /* ID Caches. Caches are used to perform fast search on the ID's. */
+  SilcIDCache *server_cache[96];
+  unsigned int server_cache_count[96];
+  SilcIDCache *client_cache[96];
+  unsigned int client_cache_count[96];
+  SilcIDCache *channel_cache[96];
+  unsigned int channel_cache_count[96];
+} SilcIDListObject;
+
+typedef SilcIDListObject *SilcIDList;
+
+/*
+   Temporary ID List object.
+
+   This is used during authentication phases where we still don't
+   know what kind of connection remote connection is, hence, we
+   will use this structure instead until we know what type of
+   connection remote end is.
+
+   This is not in any list. This is always individually allocated
+   and used as such.
+
+*/
+typedef struct {
+  SilcCipher send_key;
+  SilcCipher receive_key;
+  SilcPKCS pkcs;
+
+  SilcHmac hmac;
+  unsigned char *hmac_key;
+  unsigned int hmac_key_len;
+
+  /* SilcComp comp */
+} SilcIDListUnknown;
+
+/* Prototypes */
+void silc_idlist_add_server(SilcServerList **list, 
+                           char *server_name, int server_type,
+                           SilcServerID *id, SilcServerList *router,
+                           SilcCipher send_key, SilcCipher receive_key,
+                           SilcPKCS public_key, SilcHmac hmac, 
+                           SilcServerList **new_idlist);
+void silc_idlist_add_client(SilcClientList **list, char *nickname,
+                           char *username, char *userinfo,
+                           SilcClientID *id, SilcServerList *router,
+                           SilcCipher send_key, SilcCipher receive_key,
+                           SilcPKCS public_key, SilcHmac hmac, 
+                           SilcClientList **new_idlist);
+void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry);
+SilcClientList *
+silc_idlist_find_client_by_nickname(SilcClientList *list,
+                                   char *nickname,
+                                   char *server);
+SilcClientList *
+silc_idlist_find_client_by_hash(SilcClientList *list,
+                               char *nickname, SilcHash hash);
+SilcClientList *
+silc_idlist_find_client_by_id(SilcClientList *list, SilcClientID *id);
+void silc_idlist_add_channel(SilcChannelList **list, 
+                            char *channel_name, int mode,
+                            SilcChannelID *id, SilcServerList *router,
+                            SilcCipher channel_key,
+                            SilcChannelList **new_idlist);
+SilcChannelList *
+silc_idlist_find_channel_by_id(SilcChannelList *list, SilcChannelID *id);
+void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry);
+
+#endif
diff --git a/apps/silcd/leevi.conf b/apps/silcd/leevi.conf
new file mode 100644 (file)
index 0000000..d94631f
--- /dev/null
@@ -0,0 +1,47 @@
+[Cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[ServerInfo]
+leevi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1333
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ListenPort]
+10.2.1.7:10.2.1.7:1333
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:leevi_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+10.2.1.199:passwd:priikone:priikone:1
+
+[ServerConnection]
+10.2.1.7:passwd:priikone:1334:1:1
+
+[RouterConnection]
+
+[DenyConnection]
+[RedirectClient]
diff --git a/apps/silcd/leevi2.conf b/apps/silcd/leevi2.conf
new file mode 100644 (file)
index 0000000..4368321
--- /dev/null
@@ -0,0 +1,47 @@
+[Cipher]
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[ServerInfo]
+leevi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ListenPort]
+10.2.1.7:10.2.1.7:1334
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:leevi2_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+10.2.1.199:passwd:priikone:priikone:1
+
+[ServerConnection]
+
+[RouterConnection]
+10.2.1.7:passwd:priikone:1333:1:1
+
+[DenyConnection]
+[RedirectClient]
diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c
new file mode 100644 (file)
index 0000000..79a487c
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+
+  protocol.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Server side of the protocols.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+SILC_TASK_CALLBACK(silc_server_protocol_connection_auth);
+SILC_TASK_CALLBACK(silc_server_protocol_channel_auth);
+SILC_TASK_CALLBACK(silc_server_protocol_key_exchange);
+
+/* SILC client protocol list */
+const SilcProtocolObject silc_protocol_list[] =
+{
+  { SILC_PROTOCOL_SERVER_CONNECTION_AUTH, 
+    silc_server_protocol_connection_auth },
+  { SILC_PROTOCOL_SERVER_CHANNEL_AUTH, 
+    silc_server_protocol_channel_auth },
+  { SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
+    silc_server_protocol_key_exchange },
+
+  { SILC_PROTOCOL_SERVER_NONE, NULL },
+};
+
+/*
+ * Key Exhange protocol functions
+ */
+
+/* Packet sending callback. This function is provided as packet sending
+   routine to the Key Exchange functions. */
+
+static void silc_server_protocol_ke_send_packet(SilcSKE ske,
+                                               SilcBuffer packet,
+                                               SilcPacketType type,
+                                               void *context)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerKEInternalContext *ctx = 
+    (SilcServerKEInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+
+  /* Send the packet immediately */
+  silc_server_packet_send(server, ske->sock,
+                         type, 0, packet->data, packet->len, TRUE);
+}
+
+/* Sets the negotiated key material into use for particular connection. */
+
+static void silc_server_protocol_ke_set_keys(SilcSKE ske,
+                                            SilcSocketConnection sock,
+                                            SilcSKEKeyMaterial *keymat,
+                                            SilcCipher cipher,
+                                            SilcPKCS pkcs,
+                                            SilcHash hash,
+                                            int is_responder)
+{
+  SilcIDListUnknown *conn_data;
+  SilcHash nhash;
+
+  SILC_LOG_DEBUG(("Setting new key into use"));
+
+  conn_data = silc_calloc(1, sizeof(*conn_data));
+
+  /* Allocate cipher to be used in the communication */
+  silc_cipher_alloc(cipher->cipher->name, &conn_data->send_key);
+  silc_cipher_alloc(cipher->cipher->name, &conn_data->receive_key);
+  
+  if (is_responder == TRUE) {
+    conn_data->send_key->cipher->set_key(conn_data->send_key->context, 
+                                        keymat->receive_enc_key, 
+                                        keymat->enc_key_len);
+    conn_data->send_key->set_iv(conn_data->send_key, keymat->receive_iv);
+    conn_data->receive_key->cipher->set_key(conn_data->receive_key->context, 
+                                           keymat->send_enc_key, 
+                                           keymat->enc_key_len);
+    conn_data->receive_key->set_iv(conn_data->receive_key, keymat->send_iv);
+    
+  } else {
+    conn_data->send_key->cipher->set_key(conn_data->send_key->context, 
+                                        keymat->send_enc_key, 
+                                        keymat->enc_key_len);
+    conn_data->send_key->set_iv(conn_data->send_key, keymat->send_iv);
+    conn_data->receive_key->cipher->set_key(conn_data->receive_key->context, 
+                                           keymat->receive_enc_key, 
+                                           keymat->enc_key_len);
+    conn_data->receive_key->set_iv(conn_data->receive_key, keymat->receive_iv);
+  }
+
+  /* Allocate PKCS to be used */
+#if 0
+  /* XXX Do we ever need to allocate PKCS for the connection??
+     If yes, we need to change KE protocol to get the initiators
+     public key. */
+  silc_pkcs_alloc(pkcs->pkcs->name, &conn_data->pkcs);
+  silc_pkcs_set_public_key(conn_data->pkcs, ske->ke2_payload->pk_data, 
+                          ske->ke2_payload->pk_len);
+#endif
+
+  /* Save HMAC key to be used in the communication. */
+  silc_hash_alloc(hash->hash->name, &nhash);
+  silc_hmac_alloc(nhash, &conn_data->hmac);
+  conn_data->hmac_key_len = keymat->hmac_key_len;
+  conn_data->hmac_key = silc_calloc(conn_data->hmac_key_len,
+                                   sizeof(unsigned char));
+  memcpy(conn_data->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+
+  sock->user_data = (void *)conn_data;
+}
+
+/* Performs key exchange protocol. This is used for both initiator
+   and responder key exchange. This is performed always when accepting
+   new connection to the server. This may be called recursively. */
+
+SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerKEInternalContext *ctx = 
+    (SilcServerKEInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSKEStatus status = 0;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+    protocol->state = SILC_PROTOCOL_STATE_START;
+
+  SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+  switch(protocol->state) {
+  case SILC_PROTOCOL_STATE_START:
+    {
+      /*
+       * Start protocol
+       */
+      SilcSKE ske;
+
+      /* Allocate Key Exchange object */
+      ske = silc_ske_alloc();
+      ctx->ske = ske;
+      
+      if (ctx->responder == TRUE) {
+       /* Start the key exchange by processing the received security
+          properties packet from initiator. */
+       status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+                                         ctx->packet, NULL, NULL);
+      } else {
+       SilcSKEStartPayload *start_payload;
+
+       /* Assemble security properties. */
+       silc_ske_assemble_security_properties(ske, &start_payload);
+
+       /* Start the key exchange by sending our security properties
+          to the remote end. */
+       status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
+                                         start_payload,
+                                         silc_server_protocol_ke_send_packet,
+                                         context);
+      }
+
+      if (status != SILC_SKE_STATUS_OK) {
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+       return;
+      }
+
+      /* Advance protocol state and call the next state if we are responder */
+      protocol->state++;
+      if (ctx->responder == TRUE)
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000);
+    }
+    break;
+  case 2:
+    {
+      /* 
+       * Phase 1 
+       */
+      if (ctx->responder == TRUE) {
+       /* Sends the selected security properties to the initiator. */
+       status = 
+         silc_ske_responder_phase_1(ctx->ske, 
+                                    ctx->ske->start_payload,
+                                    silc_server_protocol_ke_send_packet,
+                                    context);
+      } else {
+       /* Call Phase-1 function. This processes the Key Exchange Start
+          paylaod reply we just got from the responder. The callback
+          function will receive the processed payload where we will
+          save it. */
+       status = 
+         silc_ske_initiator_phase_1(ctx->ske,
+                                    ctx->packet,
+                                    NULL, NULL);
+      }
+
+      if (status != SILC_SKE_STATUS_OK) {
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+       return;
+      }
+
+      /* Advance protocol state and call next state if we are initiator */
+      protocol->state++;
+      if (ctx->responder == FALSE)
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000);
+    }
+    break;
+  case 3:
+    {
+      /* 
+       * Phase 2 
+       */
+      if (ctx->responder == TRUE) {
+       /* Process the received Key Exchange 1 Payload packet from
+          the initiator. This also creates our parts of the Diffie
+          Hellman algorithm. */
+       status = 
+         silc_ske_responder_phase_2(ctx->ske, ctx->packet, NULL, NULL);
+      } else {
+       /* Call the Phase-2 function. This creates Diffie Hellman
+          key exchange parameters and sends our public part inside
+          Key Exhange 1 Payload to the responder. */
+       status = 
+         silc_ske_initiator_phase_2(ctx->ske,
+                                    silc_server_protocol_ke_send_packet,
+                                    context);
+      }
+
+      if (status != SILC_SKE_STATUS_OK) {
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+       return;
+      }
+
+      /* Advance protocol state and call the next state if we are responder */
+      protocol->state++;
+      if (ctx->responder == TRUE)
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 100000);
+    }
+    break;
+  case 4:
+    {
+      /* 
+       * Finish protocol
+       */
+      if (ctx->responder == TRUE) {
+       unsigned char *pk, *prv;
+       unsigned int pk_len, prv_len;
+
+       /* Get our public key to be sent to the initiator */
+       pk = silc_pkcs_get_public_key(server->public_key, &pk_len);
+
+       /* Get out private key to sign some data. */
+       prv = silc_pkcs_get_private_key(server->public_key, &prv_len);
+
+       /* This creates the key exchange material and sends our
+          public parts to the initiator inside Key Exchange 2 Payload. */
+       status = 
+         silc_ske_responder_finish(ctx->ske, 
+                                   pk, pk_len, prv, prv_len,
+                                   SILC_SKE_PK_TYPE_SILC,
+                                   silc_server_protocol_ke_send_packet,
+                                   context);
+
+       memset(pk, 0, pk_len);
+       memset(prv, 0, prv_len);
+       silc_free(pk);
+       silc_free(prv);
+      } else {
+       /* Finish the protocol. This verifies the Key Exchange 2 payload
+          sent by responder. */
+       status = 
+         silc_ske_initiator_finish(ctx->ske,
+                                   ctx->packet, NULL, NULL);
+      }
+
+      if (status != SILC_SKE_STATUS_OK) {
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+       return;
+      }
+
+      /* Send Ok to the other end. We will end the protocol as responder
+        sends Ok to us when we will take the new keys into use. */
+      if (ctx->responder == FALSE)
+       silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context);
+
+      /* End the protocol on the next round */
+      protocol->state = SILC_PROTOCOL_STATE_END;
+    }
+    break;
+  case SILC_PROTOCOL_STATE_END:
+    {
+      /* 
+       * End protocol
+       */
+      SilcSKEKeyMaterial *keymat;
+
+      /* Send Ok to the other end if we are responder. If we are 
+        initiator we have sent this already. */
+      if (ctx->responder == TRUE)
+       silc_ske_end(ctx->ske, silc_server_protocol_ke_send_packet, context);
+
+      /* Process the key material */
+      keymat = silc_calloc(1, sizeof(*keymat));
+      silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
+
+      /* Take the new keys into use. */
+      silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
+                                      ctx->ske->prop->cipher,
+                                      ctx->ske->prop->pkcs,
+                                      ctx->ske->prop->hash,
+                                      ctx->responder);
+
+      /* Unregister the timeout task since the protocol has ended. 
+        This was the timeout task to be executed if the protocol is
+        not completed fast enough. */
+      if (ctx->timeout_task)
+       silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+      /* Call the final callback */
+      if (protocol->final_callback)
+       protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+      else
+       silc_protocol_free(protocol);
+    }
+    break;
+  case SILC_PROTOCOL_STATE_ERROR:
+    /*
+     * Error occured
+     */
+
+    /* Unregister the timeout task since the protocol has ended. 
+       This was the timeout task to be executed if the protocol is
+       not completed fast enough. */
+    if (ctx->timeout_task)
+      silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+  case SILC_PROTOCOL_STATE_UNKNOWN:
+    break;
+  }
+}
+
+/*
+ * Connection Authentication protocol functions
+ */
+
+/* Performs connection authentication protocol. If responder, we 
+   authenticate the remote data received. If initiator, we will send
+   authentication data to the remote end. */
+
+SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerConnAuthInternalContext *ctx = 
+    (SilcServerConnAuthInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
+    protocol->state = SILC_PROTOCOL_STATE_START;
+
+  SILC_LOG_DEBUG(("State=%d", protocol->state));
+
+  switch(protocol->state) {
+  case SILC_PROTOCOL_STATE_START:
+    {
+      /* 
+       * Start protocol.
+       */
+
+      if (ctx->responder == TRUE) {
+       /*
+        * We are receiving party
+        */
+       unsigned short payload_len;
+       unsigned short conn_type;
+       unsigned char *auth_data;
+
+       /* Parse the received authentication data packet. The received
+          payload is Connection Auth Payload. */
+       silc_buffer_unformat(ctx->packet,
+                            SILC_STR_UI_SHORT(&payload_len),
+                            SILC_STR_UI_SHORT(&conn_type),
+                            SILC_STR_END);
+       
+       if (payload_len != ctx->packet->len) {
+         SILC_LOG_ERROR(("Bad payload in authentication packet"));
+         SILC_LOG_DEBUG(("Bad payload in authentication packet"));
+         protocol->state = SILC_PROTOCOL_STATE_ERROR;
+         protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+         return;
+       }
+       
+       payload_len -= 4;
+       
+       if (conn_type < SILC_SOCKET_TYPE_CLIENT || 
+           conn_type > SILC_SOCKET_TYPE_ROUTER) {
+         SILC_LOG_ERROR(("Bad connection type %d", conn_type));
+         SILC_LOG_DEBUG(("Bad connection type %d", conn_type));
+         protocol->state = SILC_PROTOCOL_STATE_ERROR;
+         protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 300000);
+         return;
+       }
+       
+       if (payload_len > 0) {
+         /* Get authentication data */
+         silc_buffer_pull(ctx->packet, 4);
+         silc_buffer_unformat(ctx->packet,
+                              SILC_STR_UI_XNSTRING_ALLOC(&auth_data, 
+                                                         payload_len),
+                              SILC_STR_END);
+       } else {
+         auth_data = NULL;
+       }
+
+       /* 
+        * Check the remote connection type and make sure that we have
+        * configured this connection. If we haven't allowed this connection
+        * the authentication must be failed.
+        */
+
+       SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
+
+       /* Remote end is client */
+       if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
+         SilcConfigServerSectionClientConnection *client = NULL;
+         client = 
+           silc_config_server_find_client_conn(server->config,
+                                               ctx->sock->ip,
+                                               ctx->sock->port);
+         if (!client)
+           client = 
+             silc_config_server_find_client_conn(server->config,
+                                                 ctx->sock->hostname,
+                                                 ctx->sock->port);
+         
+         if (client) {
+           switch(client->auth_meth) {
+           case SILC_PROTOCOL_CONN_AUTH_NONE:
+             /* No authentication required */
+             SILC_LOG_DEBUG(("No authentication required"));
+             break;
+             
+           case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+             /* Password authentication */
+             SILC_LOG_DEBUG(("Password authentication"));
+             if (auth_data) {
+               if (!memcmp(client->auth_data, auth_data, strlen(auth_data))) {
+                 memset(auth_data, 0, payload_len);
+                 silc_free(auth_data);
+                 auth_data = NULL;
+                 break;
+               }
+             }
+
+             /* Authentication failed */
+             SILC_LOG_ERROR(("Authentication failed"));
+             SILC_LOG_DEBUG(("Authentication failed"));
+             protocol->state = SILC_PROTOCOL_STATE_ERROR;
+             protocol->execute(server->timeout_queue, 0, 
+                               protocol, fd, 0, 300000);
+             return;
+             break;
+             
+           case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+             /* Public key authentication */
+             SILC_LOG_DEBUG(("Public key authentication"));
+             if (auth_data) {
+               SilcIDListUnknown *conn_data;
+               SilcPKCS pkcs;
+               
+               conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
+               
+               /* Load public key from file */
+               if (silc_pkcs_load_public_key(client->auth_data,
+                                             &pkcs) == FALSE) {
+                 
+                 /* Authentication failed */
+                 SILC_LOG_ERROR(("Authentication failed "
+                                 "- could not read public key file"));
+                 memset(auth_data, 0, payload_len);
+                 silc_free(auth_data);
+                 auth_data = NULL;
+                 protocol->state = SILC_PROTOCOL_STATE_ERROR;
+                 protocol->execute(server->timeout_queue, 0, 
+                                   protocol, fd, 0, 300000);
+                 return;
+               }
+               
+               /* Verify hash value HASH from KE protocol */
+               if (pkcs->pkcs->verify(pkcs->context,
+                                      auth_data, payload_len,
+                                      ctx->ske->hash, 
+                                      ctx->ske->hash_len)
+                   == TRUE) {
+                 silc_pkcs_free(pkcs);
+                 break;
+               }
+             }
+
+             SILC_LOG_ERROR(("Authentication failed"));
+             SILC_LOG_DEBUG(("Authentication failed"));
+             protocol->state = SILC_PROTOCOL_STATE_ERROR;
+             protocol->execute(server->timeout_queue, 0, 
+                               protocol, fd, 0, 300000);
+             return;
+           }
+         } else {
+           SILC_LOG_DEBUG(("No configuration for remote connection"));
+           SILC_LOG_ERROR(("Remote connection not configured"));
+           SILC_LOG_ERROR(("Authentication failed"));
+           memset(auth_data, 0, payload_len);
+           silc_free(auth_data);
+           auth_data = NULL;
+           protocol->state = SILC_PROTOCOL_STATE_ERROR;
+           protocol->execute(server->timeout_queue, 0, 
+                             protocol, fd, 0, 300000);
+           return;
+         }
+       }
+       
+       /* Remote end is server */
+       if (conn_type == SILC_SOCKET_TYPE_SERVER) {
+         SilcConfigServerSectionServerConnection *serv = NULL;
+         serv = 
+           silc_config_server_find_server_conn(server->config,
+                                               ctx->sock->ip,
+                                               ctx->sock->port);
+         if (!serv)
+           serv = 
+             silc_config_server_find_server_conn(server->config,
+                                                 ctx->sock->hostname,
+                                                 ctx->sock->port);
+         
+         if (serv) {
+           switch(serv->auth_meth) {
+           case SILC_PROTOCOL_CONN_AUTH_NONE:
+             /* No authentication required */
+             SILC_LOG_DEBUG(("No authentication required"));
+             break;
+             
+           case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+             /* Password authentication */
+             SILC_LOG_DEBUG(("Password authentication"));
+             if (auth_data) {
+               if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
+                 memset(auth_data, 0, payload_len);
+                 silc_free(auth_data);
+                 auth_data = NULL;
+                 break;
+               }
+             }
+             
+             /* Authentication failed */
+             SILC_LOG_ERROR(("Authentication failed"));
+             SILC_LOG_DEBUG(("Authentication failed"));
+             protocol->state = SILC_PROTOCOL_STATE_ERROR;
+             protocol->execute(server->timeout_queue, 0, 
+                               protocol, fd, 0, 300000);
+             return;
+             break;
+             
+           case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+             /* Public key authentication */
+             SILC_LOG_DEBUG(("Public key authentication"));
+             if (auth_data) {
+               SilcIDListUnknown *conn_data;
+               SilcPKCS pkcs;
+               
+               conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
+               
+               /* Load public key from file */
+               if (silc_pkcs_load_public_key(serv->auth_data,
+                                             &pkcs) == FALSE) {
+                 
+                 /* Authentication failed */
+                 SILC_LOG_ERROR(("Authentication failed "
+                                 "- could not read public key file"));
+                 memset(auth_data, 0, payload_len);
+                 silc_free(auth_data);
+                 auth_data = NULL;
+                 protocol->state = SILC_PROTOCOL_STATE_ERROR;
+                 protocol->execute(server->timeout_queue, 0, 
+                                   protocol, fd, 0, 300000);
+                 return;
+               }
+               
+               /* Verify hash value HASH from KE protocol */
+               if (pkcs->pkcs->verify(pkcs->context,
+                                      auth_data, payload_len,
+                                      ctx->ske->hash, 
+                                      ctx->ske->hash_len)
+                   == TRUE) {
+                 silc_pkcs_free(pkcs);
+                 break;
+               }
+             }
+
+             SILC_LOG_ERROR(("Authentication failed"));
+             SILC_LOG_DEBUG(("Authentication failed"));
+             protocol->state = SILC_PROTOCOL_STATE_ERROR;
+             protocol->execute(server->timeout_queue, 0, 
+                               protocol, fd, 0, 300000);
+             return;
+           }
+         } else {
+           SILC_LOG_DEBUG(("No configuration for remote connection"));
+           SILC_LOG_ERROR(("Remote connection not configured"));
+           SILC_LOG_ERROR(("Authentication failed"));
+           memset(auth_data, 0, payload_len);
+           silc_free(auth_data);
+           auth_data = NULL;
+           protocol->state = SILC_PROTOCOL_STATE_ERROR;
+           protocol->execute(server->timeout_queue, 0, 
+                             protocol, fd, 0, 300000);
+           return;
+         }
+       }
+       
+       /* Remote end is router */
+       if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
+         SilcConfigServerSectionServerConnection *serv = NULL;
+         serv = 
+           silc_config_server_find_router_conn(server->config,
+                                               ctx->sock->ip,
+                                               ctx->sock->port);
+         if (!serv)
+           serv = 
+             silc_config_server_find_router_conn(server->config,
+                                                 ctx->sock->hostname,
+                                                 ctx->sock->port);
+         
+         if (serv) {
+           switch(serv->auth_meth) {
+           case SILC_PROTOCOL_CONN_AUTH_NONE:
+             /* No authentication required */
+             SILC_LOG_DEBUG(("No authentication required"));
+             break;
+             
+           case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+             /* Password authentication */
+             SILC_LOG_DEBUG(("Password authentication"));
+             if (auth_data) {
+               if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
+                 memset(auth_data, 0, payload_len);
+                 silc_free(auth_data);
+                 auth_data = NULL;
+                 break;
+               }
+             }
+             
+             /* Authentication failed */
+             SILC_LOG_ERROR(("Authentication failed"));
+             SILC_LOG_DEBUG(("Authentication failed"));
+             protocol->state = SILC_PROTOCOL_STATE_ERROR;
+             protocol->execute(server->timeout_queue, 0, 
+                               protocol, fd, 0, 300000);
+             return;
+             break;
+             
+           case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+             /* Public key authentication */
+             SILC_LOG_DEBUG(("Public key authentication"));
+             if (auth_data) {
+               SilcIDListUnknown *conn_data;
+               SilcPKCS pkcs;
+               
+               conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
+               
+               /* Load public key from file */
+               if (silc_pkcs_load_public_key(serv->auth_data,
+                                             &pkcs) == FALSE) {
+                 
+                 /* Authentication failed */
+                 SILC_LOG_ERROR(("Authentication failed "
+                                 "- could not read public key file"));
+                 memset(auth_data, 0, payload_len);
+                 silc_free(auth_data);
+                 auth_data = NULL;
+                 protocol->state = SILC_PROTOCOL_STATE_ERROR;
+                 protocol->execute(server->timeout_queue, 0, 
+                                   protocol, fd, 0, 300000);
+                 return;
+               }
+               
+               /* Verify hash value HASH from KE protocol */
+               if (pkcs->pkcs->verify(pkcs->context,
+                                      auth_data, payload_len,
+                                      ctx->ske->hash, 
+                                      ctx->ske->hash_len)
+                   == TRUE) {
+                 silc_pkcs_free(pkcs);
+                 break;
+               }
+             }
+
+             SILC_LOG_ERROR(("Authentication failed"));
+             SILC_LOG_DEBUG(("Authentication failed"));
+             protocol->state = SILC_PROTOCOL_STATE_ERROR;
+             protocol->execute(server->timeout_queue, 0, 
+                               protocol, fd, 0, 300000);
+             return;
+           }
+         } else {
+           SILC_LOG_DEBUG(("No configuration for remote connection"));
+           SILC_LOG_ERROR(("Remote connection not configured"));
+           SILC_LOG_ERROR(("Authentication failed"));
+           memset(auth_data, 0, payload_len);
+           silc_free(auth_data);
+           auth_data = NULL;
+           protocol->state = SILC_PROTOCOL_STATE_ERROR;
+           protocol->execute(server->timeout_queue, 0, 
+                             protocol, fd, 0, 300000);
+           return;
+         }
+       }
+       
+       if (auth_data) {
+         memset(auth_data, 0, payload_len);
+         silc_free(auth_data);
+       }
+       
+       /* Save connection type. This is later used to create the
+          ID for the connection. */
+       ctx->conn_type = conn_type;
+         
+       /* Advance protocol state. */
+       protocol->state = SILC_PROTOCOL_STATE_END;
+       protocol->execute(server->timeout_queue, 0, protocol, fd, 0, 0);
+
+      } else {
+       /* 
+        * We are initiator. We are authenticating ourselves to a
+        * remote server. We will send the authentication data to the
+        * other end for verify. 
+        */
+       SilcBuffer packet;
+       int payload_len = 0;
+       unsigned char *auth_data = NULL;
+       unsigned int auth_data_len = 0;
+       
+       switch(ctx->auth_meth) {
+       case SILC_PROTOCOL_CONN_AUTH_NONE:
+         /* No authentication required */
+         break;
+         
+       case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
+         /* Password authentication */
+         if (ctx->auth_data && ctx->auth_data_len) {
+           auth_data = ctx->auth_data;
+           auth_data_len = ctx->auth_data_len;
+           break;
+         }
+
+         /* No authentication data exits. Ask interactively from user. */
+         /* XXX */
+
+         break;
+         
+       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
+         /* Public key authentication */
+         /* XXX TODO */
+         break;
+       }
+       
+       payload_len = 4 + auth_data_len;
+       packet = silc_buffer_alloc(payload_len);
+       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+       silc_buffer_format(packet,
+                          SILC_STR_UI_SHORT(payload_len),
+                          SILC_STR_UI_SHORT(server->server_type 
+                                             == SILC_SERVER ?
+                                             SILC_SOCKET_TYPE_SERVER :
+                                             SILC_SOCKET_TYPE_ROUTER),
+                          SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
+                          SILC_STR_END);
+       
+       /* Send the packet to server */
+       silc_server_packet_send(server, ctx->sock,
+                               SILC_PACKET_CONNECTION_AUTH, 0, 
+                               packet->data, packet->len, TRUE);
+       
+       if (auth_data) {
+         memset(auth_data, 0, auth_data_len);
+         silc_free(auth_data);
+       }
+       silc_buffer_free(packet);
+       
+       /* Next state is end of protocol */
+       protocol->state = SILC_PROTOCOL_STATE_END;
+      }
+    }
+    break;
+
+  case SILC_PROTOCOL_STATE_END:
+    {
+      /* 
+       * End protocol
+       */
+
+      /* Succesfully authenticated */
+      silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS, 
+                             0, NULL, 0, TRUE);
+
+      /* Unregister the timeout task since the protocol has ended. 
+        This was the timeout task to be executed if the protocol is
+        not completed fast enough. */
+      if (ctx->timeout_task)
+       silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+      /* Protocol has ended, call the final callback */
+      if (protocol->final_callback)
+       protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+      else
+       silc_protocol_free(protocol);
+    }
+    break;
+  case SILC_PROTOCOL_STATE_ERROR:
+    {
+      /*
+       * Error 
+       */
+
+      /* Authentication failed */
+      silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
+                             0, NULL, 0, TRUE);
+
+      /* Unregister the timeout task since the protocol has ended. 
+        This was the timeout task to be executed if the protocol is
+        not completed fast enough. */
+      if (ctx->timeout_task)
+       silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+      /* On error the final callback is always called. */
+      if (protocol->final_callback)
+       protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+      else
+       silc_protocol_free(protocol);
+    }
+    break;
+  case SILC_PROTOCOL_STATE_UNKNOWN:
+    break;
+  }
+}
+
+SILC_TASK_CALLBACK(silc_server_protocol_channel_auth)
+{
+}
diff --git a/apps/silcd/protocol.h b/apps/silcd/protocol.h
new file mode 100644 (file)
index 0000000..b9505cf
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+
+  protocol.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+/* SILC client protocol types */
+#define SILC_PROTOCOL_SERVER_NONE 0
+#define SILC_PROTOCOL_SERVER_CONNECTION_AUTH 1
+#define SILC_PROTOCOL_SERVER_CHANNEL_AUTH 2
+#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE 3
+/* #define SILC_PROTOCOL_SERVER_MAX 255 */
+
+/* Internal context for Key Exchange protocol. */
+typedef struct {
+  void *server;
+  SilcSocketConnection sock;
+  SilcRng rng;
+
+  /* TRUE if we are receiveing part of the protocol */
+  int responder;
+
+  /* Destinations ID taken from authenticataed packet so that we can
+     get the destinations ID. */
+  void *dest_id;
+  SilcIdType dest_id_type;
+
+  SilcTask timeout_task;
+  SilcBuffer packet;
+  SilcSKE ske;
+} SilcServerKEInternalContext;
+
+/* Internal context for connection authentication protocol */
+typedef struct {
+  void *server;
+  SilcSocketConnection sock;
+
+  /* TRUE if we are receiving part of the protocol */
+  int responder;
+
+  /* SKE object from Key Exchange protocol. */
+  SilcSKE ske;
+
+  /* Auth method that must be used. This is resolved before this
+     connection authentication protocol is started. Used when we are
+     initiating. */
+  unsigned int auth_meth;
+
+  /* Authentication data if we alreay know it. This is filled before
+     starting the protocol if we know the authentication data. Otherwise
+     these are and remain NULL. Used when we are initiating. */
+  unsigned char *auth_data;
+  unsigned int auth_data_len;
+
+  /* Destinations ID from KE protocol context */
+  void *dest_id;
+  SilcIdType dest_id_type;
+
+  SilcTask timeout_task;
+  SilcBuffer packet;
+  unsigned short conn_type;
+} SilcServerConnAuthInternalContext;
+
+/* Prototypes */
+
+#endif
diff --git a/apps/silcd/pubkey.pub b/apps/silcd/pubkey.pub
new file mode 100644 (file)
index 0000000..cf4ed9b
Binary files /dev/null and b/apps/silcd/pubkey.pub differ
diff --git a/apps/silcd/route.c b/apps/silcd/route.c
new file mode 100644 (file)
index 0000000..dad5ae3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+
+  route.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* 
+ * Route cache routines. Server uses these to route packets to specific
+ * routes. If route entry doesn't exist for a specific destination, server
+ * uses primary route (default route).
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "route.h"
+
+/* Route cache hash table */
+SilcServerRouteTable silc_route_cache[SILC_SERVER_ROUTE_SIZE];
+
+/* Adds new route to the route cache. The argument `index' is the
+   index value generated by silc_server_route_hash. */
+
+void silc_server_route_add(unsigned int index, unsigned int dest,
+                          SilcServerList *router)
+{
+  silc_route_cache[index].dest = dest;
+  silc_route_cache[index].router = router;
+}
+
+/* Checksk whether destination has a specific router. Returns the
+   router data if found, NULL otherwise. */
+
+SilcServerList *silc_server_route_check(unsigned int dest, 
+                                       unsigned short port)
+{
+  unsigned int index;
+
+  index = silc_server_route_hash(dest, port);
+
+  if (silc_route_cache[index].router != NULL &&
+      silc_route_cache[index].dest == dest)
+    return silc_route_cache[index].router;
+
+  return NULL;
+}
diff --git a/apps/silcd/route.h b/apps/silcd/route.h
new file mode 100644 (file)
index 0000000..aec76e6
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+
+  route.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef ROUTE_H
+#define ROUTE_H
+
+/* Definitions */
+
+/* Size of the route cache hash table */
+#define SILC_SERVER_ROUTE_SIZE 256
+
+/*
+   SILC Server Route table
+
+   Following short description of the fields.
+
+   unsigned int dest
+
+       Destination IPv4 address.  Can be used to quickly check whether
+       the found route entry is what the caller wanted.
+
+   SilcServerList *router
+
+       Pointer to the router specific data.
+
+*/
+typedef struct {
+  unsigned int dest;
+  SilcServerList *router;
+} SilcServerRouteTable;
+
+/* Route cache hash table */
+extern SilcServerRouteTable silc_route_cache[SILC_SERVER_ROUTE_SIZE];
+
+/* Macros and super macros */
+
+/* Returns route cache hash table entry index. This is IPv4 specific.
+   `port' argument may be zero (0) if it doesn't exist.  This has been
+   taken from Linux kernel's route cache code. */
+extern inline
+unsigned int silc_server_route_hash(unsigned int addr, 
+                                   unsigned short port)
+{
+  unsigned int hash;
+  
+  hash = ((addr & 0xf0f0f0f0) >> 4) | ((addr & 0x0f0f0f0f) << 4);
+  hash ^= port;
+  hash ^= (hash >> 16);
+  hash ^= (hash >> 8);
+  
+  return hash & 0xff;
+}
+
+/* Prototypes */
+void silc_server_route_add(unsigned int index, unsigned int dest,
+                          SilcServerList *router);
+SilcServerList *silc_server_route_check(unsigned int dest, 
+                                       unsigned short port);
+
+#endif
diff --git a/apps/silcd/server.c b/apps/silcd/server.c
new file mode 100644 (file)
index 0000000..4da53bd
--- /dev/null
@@ -0,0 +1,3726 @@
+/*
+
+  server.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * This is the actual SILC server than handles everything relating to
+ * servicing the SILC connections. This is also a SILC router as a router 
+ * is also normal server.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_connect_to_router);
+SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
+SILC_TASK_CALLBACK(silc_server_connect_to_router_final);
+SILC_TASK_CALLBACK(silc_server_accept_new_connection);
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_second);
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_final);
+SILC_TASK_CALLBACK(silc_server_packet_process);
+SILC_TASK_CALLBACK(silc_server_packet_parse);
+SILC_TASK_CALLBACK(silc_server_timeout_remote);
+
+/* XXX */
+void silc_server_packet_parse_type(SilcServer server, 
+                                  SilcSocketConnection sock,
+                                  SilcPacketContext *packet);
+
+static int silc_server_packet_check_mac(SilcServer server,
+                                       SilcSocketConnection sock,
+                                       SilcBuffer buffer);
+static int silc_server_packet_decrypt_rest(SilcServer server, 
+                                          SilcSocketConnection sock,
+                                          SilcBuffer buffer);
+static int silc_server_packet_decrypt_rest_special(SilcServer server, 
+                                                  SilcSocketConnection sock,
+                                                  SilcBuffer buffer);
+
+extern char server_version[];
+
+/* Allocates a new SILC server object. This has to be done before the server
+   can be used. After allocation one must call silc_server_init to initialize
+   the server. The new allocated server object is returned to the new_server
+   argument. */
+
+int silc_server_alloc(SilcServer *new_server)
+{
+  SILC_LOG_DEBUG(("Allocating new server object"));
+
+  *new_server = silc_calloc(1, sizeof(**new_server));
+  if (*new_server == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new server object"));
+    return FALSE;
+  }
+
+  /* Set default values */
+  (*new_server)->server_name = NULL;
+  (*new_server)->server_type = SILC_SERVER;
+  (*new_server)->standalone = FALSE;
+  (*new_server)->id = NULL;
+  (*new_server)->io_queue = NULL;
+  (*new_server)->timeout_queue = NULL;
+  (*new_server)->local_list = silc_calloc(1, sizeof(SilcIDListObject));
+  (*new_server)->global_list = silc_calloc(1, sizeof(SilcIDListObject));
+  (*new_server)->rng = NULL;
+  (*new_server)->md5hash = NULL;
+  (*new_server)->sha1hash = NULL;
+  /*  (*new_server)->public_key = NULL;*/
+
+  return TRUE;
+}
+
+/* Free's the SILC server object. This is called at the very end before
+   the program ends. */
+
+void silc_server_free(SilcServer server)
+{
+  if (server) {
+    if (server->local_list)
+      silc_free(server->local_list);
+    if (server->global_list)
+      silc_free(server->global_list);
+    if (server->rng)
+      silc_rng_free(server->rng);
+
+    silc_math_primegen_uninit(); /* XXX */
+    silc_free(server);
+  }
+}
+
+/* Initializes the entire SILC server. This is called always before running
+   the server. This is called only once at the initialization of the program.
+   This binds the server to its listenning port. After this function returns 
+   one should call silc_server_run to start the server. This returns TRUE 
+   when everything is ok to run the server. Configuration file must be
+   read and parsed before calling this. */
+
+int silc_server_init(SilcServer server)
+{
+  int *sock = NULL, sock_count, i;
+  SilcServerID *id;
+  SilcServerList *id_entry;
+  SilcHashObject hash;
+
+  SILC_LOG_DEBUG(("Initializing server"));
+  assert(server);
+  assert(server->config);
+
+  /* Set log files where log message should be saved. */
+  server->config->server = server;
+  silc_config_server_setlogfiles(server->config);
+  /* Register all configured ciphers, PKCS and hash functions. */
+  silc_config_server_register_ciphers(server->config);
+  silc_config_server_register_pkcs(server->config);
+  silc_config_server_register_hashfuncs(server->config);
+
+  /* Initialize random number generator for the server. */
+  server->rng = silc_rng_alloc();
+  silc_rng_init(server->rng);
+  silc_math_primegen_init(); /* XXX */
+
+  /* Initialize hash functions for server to use */
+  silc_hash_alloc("md5", &server->md5hash);
+  silc_hash_alloc("sha1", &server->sha1hash);
+
+  /* Initialize none cipher */
+  silc_cipher_alloc("none", &server->none_cipher);
+
+  /* XXXXX Generate RSA key pair */
+  {
+    unsigned char *public_key;
+    unsigned char *private_key;
+    unsigned int pk_len, prv_len;
+
+    if (silc_pkcs_alloc("rsa", &server->public_key) == FALSE) {
+      SILC_LOG_ERROR(("Could not create RSA key pair"));
+      goto err0;
+    }
+
+    if (server->public_key->pkcs->init(server->public_key->context, 
+                                      1024, server->rng) == FALSE) {
+      SILC_LOG_ERROR(("Could not generate RSA key pair"));
+      goto err0;
+    }
+
+    public_key = 
+      server->public_key->pkcs->get_public_key(server->public_key->context,
+                                              &pk_len);
+    private_key = 
+      server->public_key->pkcs->get_private_key(server->public_key->context,
+                                               &prv_len);
+
+    SILC_LOG_HEXDUMP(("public key"), public_key, pk_len);
+    SILC_LOG_HEXDUMP(("private key"), private_key, prv_len);
+
+    /* XXX Save keys */
+    silc_pkcs_save_public_key(server->public_key, "pubkey.pub",
+                             public_key,  pk_len);
+
+    memset(public_key, 0, pk_len);
+    memset(private_key, 0, prv_len);
+    silc_free(public_key);
+    silc_free(private_key);
+  }
+
+  /* Create a listening server. Note that our server can listen on
+     multiple ports. All listeners are created here and now. */
+  /* XXX Still check this whether to use server_info or listen_port. */
+  sock_count = 0;
+  while(server->config->listen_port) {
+    int tmp;
+
+    tmp = silc_net_create_server(server->config->listen_port->port,
+                                server->config->listen_port->host);
+    if (tmp < 0)
+      goto err0;
+
+    sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
+    sock[sock_count] = tmp;
+    server->config->listen_port = server->config->listen_port->next;
+    sock_count++;
+  }
+
+  /* Allocate the entire socket list that is used in server. Eventually 
+     all connections will have entry in this table (it is a table of 
+     pointers to the actual object that is allocated individually 
+     later). */
+  server->sockets = silc_calloc(SILC_SERVER_MAX_CONNECTIONS,
+                               sizeof(*server->sockets));
+
+  for (i = 0; i < sock_count; i++) {
+    SilcSocketConnection newsocket = NULL;
+
+    /* Set socket to non-blocking mode */
+    silc_net_set_socket_nonblock(sock[i]);
+    server->sock = sock[i];
+    
+    /* Create a Server ID for the server. */
+    silc_id_create_server_id(sock[i], server->rng, &id);
+    if (!id) {
+      goto err0;
+    }
+    
+    server->id = id;
+    server->id_type = SILC_ID_SERVER;
+    server->server_name = server->config->server_info->server_name;
+
+    /* Add ourselves to the server list. We don't have a router yet 
+       beacuse we haven't established a route yet. It will be done later. 
+       For now, NULL is sent as router. This allocates new entry to
+       the ID list. */
+    silc_idlist_add_server(&server->local_list->servers, 
+                          server->config->server_info->server_name,
+                          server->server_type, server->id, NULL,
+                          server->send_key, server->receive_key,
+                          NULL, NULL, &id_entry);
+    if (!id_entry)
+      goto err0;
+    
+    /* Add ourselves also to the socket table. The entry allocated above
+       is sent as argument for fast referencing in the future. */
+    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry, 
+                     &newsocket);
+    if (!newsocket)
+      goto err0;
+
+    server->sockets[sock[i]] = newsocket;
+
+    /* Put the allocated socket pointer also to the entry allocated above 
+       for fast back-referencing to the socket list. */
+    id_entry->connection = (void *)server->sockets[sock[i]];
+    server->id_entry = id_entry;
+  }
+
+  /* Register the task queues. In SILC we have by default three task queues. 
+     One task queue for non-timeout tasks which perform different kind of 
+     I/O on file descriptors, timeout task queue for timeout tasks, and,
+     generic non-timeout task queue whose tasks apply to all connections. */
+  silc_task_queue_alloc(&server->io_queue, TRUE);
+  if (!server->io_queue) {
+    goto err0;
+  }
+  silc_task_queue_alloc(&server->timeout_queue, TRUE);
+  if (!server->timeout_queue) {
+    goto err1;
+  }
+  silc_task_queue_alloc(&server->generic_queue, TRUE);
+  if (!server->generic_queue) {
+    goto err1;
+  }
+
+  /* Initialize the scheduler */
+  silc_schedule_init(server->io_queue, server->timeout_queue, 
+                    server->generic_queue, 
+                    SILC_SERVER_MAX_CONNECTIONS);
+  
+  /* Add the first task to the queue. This is task that is executed by
+     timeout. It expires as soon as the caller calls silc_server_run. This
+     task performs authentication protocol and key exchange with our
+     primary router. */
+  if (silc_task_register(server->timeout_queue, sock[0], 
+                        silc_server_connect_to_router,
+                        (void *)server, 0, 1,
+                        SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_NORMAL) == NULL) {
+    goto err2;
+  }
+
+  /* If server connections has been configured then we must be router as
+     normal server cannot have server connections, only router connections. */
+  if (server->config->servers)
+    server->server_type = SILC_ROUTER;
+
+  SILC_LOG_DEBUG(("Server initialized"));
+
+  /* We are done here, return succesfully */
+  return TRUE;
+
+ err2:
+  silc_task_queue_free(server->timeout_queue);
+ err1:
+  silc_task_queue_free(server->io_queue);
+ err0:
+  for (i = 0; i < sock_count; i++)
+    silc_net_close_server(sock[i]);
+
+  return FALSE;
+}
+
+/* Stops the SILC server. This function is used to shutdown the server. 
+   This is usually called after the scheduler has returned. After stopping 
+   the server one should call silc_server_free. */
+
+void silc_server_stop(SilcServer server)
+{
+  SILC_LOG_DEBUG(("Stopping server"));
+
+  /* Stop the scheduler, although it might be already stopped. This
+     doesn't hurt anyone. This removes all the tasks and task queues,
+     as well. */
+  silc_schedule_stop();
+  silc_schedule_uninit();
+
+  SILC_LOG_DEBUG(("Server stopped"));
+}
+
+/* The heart of the server. This runs the scheduler thus runs the server. */
+
+void silc_server_run(SilcServer server)
+{
+  SILC_LOG_DEBUG(("Running server"));
+
+  /* Start the scheduler, the heart of the SILC server. When this returns
+     the program will be terminated. */
+  silc_schedule();
+}
+
+/* This function connects to our primary router or if we are a router this
+   establishes all our primary routes. This is called at the start of the
+   server to do authentication and key exchange with our router - called
+   from schedule. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router)
+{
+  SilcServer server = (SilcServer)context;
+  SilcSocketConnection newsocket;
+  int sock;
+
+  SILC_LOG_DEBUG(("Connecting to router(s)"));
+
+  /* if we are normal SILC server we need to connect to our cell's
+     router. */
+  if (server->server_type == SILC_SERVER) {
+    SilcProtocol protocol;
+    SilcServerKEInternalContext *proto_ctx;
+
+    /* Create connection to the router, if configured. */
+    if (server->config->routers) {
+      sock = silc_net_create_connection(server->config->routers->port, 
+                                       server->config->routers->host);
+      if (sock < 0) {
+       SILC_LOG_ERROR(("Could not connect to router"));
+       silc_schedule_stop();
+       return;
+      }
+
+      /* Set socket options */
+      silc_net_set_socket_nonblock(sock);
+      silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+      /* Create socket connection for the connection. Even though we
+        know that we are connecting to a router we will mark the socket
+        to be unknown connection until we have executed authentication
+        protocol. */
+      silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+      server->sockets[sock] = newsocket;
+      newsocket->hostname = server->config->routers->host;
+      newsocket->port = server->config->routers->port;
+
+      /* Allocate internal protocol context. This is sent as context
+        to the protocol. */
+      proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+      proto_ctx->server = context;
+      proto_ctx->sock = newsocket;
+      proto_ctx->rng = server->rng;
+      proto_ctx->responder = FALSE;
+      
+      /* Perform key exchange protocol. silc_server_connect_to_router_second
+        will be called after the protocol is finished. */
+      silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
+                         &protocol, proto_ctx,
+                         silc_server_connect_to_router_second);
+      newsocket->protocol = protocol;
+      
+      /* Register a timeout task that will be executed if the protocol
+        is not executed within 15 seconds. For now, this is a hard coded 
+        limit. After 15 secs the connection will be closed if the key 
+        exchange protocol has not been executed. */
+      proto_ctx->timeout_task = 
+       silc_task_register(server->timeout_queue, sock, 
+                          silc_server_timeout_remote,
+                          context, 15, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
+      /* Register the connection for network input and output. This sets
+        that scheduler will listen for incoming packets for this connection 
+        and sets that outgoing packets may be sent to this connection as 
+        well. However, this doesn't set the scheduler for outgoing traffic,
+        it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+        later when outgoing data is available. */
+      SILC_REGISTER_CONNECTION_FOR_IO(sock);
+      
+      /* Run the protocol */
+      protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+      return;
+    }
+  }
+  
+  /* if we are a SILC router we need to establish all of our primary
+     routes. */
+  if (server->server_type == SILC_ROUTER) {
+    SilcConfigServerSectionServerConnection *ptr;
+
+    /* Create the connections to all our routes */
+    ptr = server->config->routers;
+    while (ptr) {
+      SilcProtocol protocol;
+      SilcServerKEInternalContext *proto_ctx;
+
+      /* Create the connection to the remote end */
+      sock = silc_net_create_connection(ptr->port, ptr->host);
+      if (sock < 0) {
+       SILC_LOG_ERROR(("Could not connect to router"));
+       silc_schedule_stop();
+       return;
+      }
+
+      /* Set socket options */
+      silc_net_set_socket_nonblock(sock);
+      silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+      /* Create socket connection for the connection. Even though we
+        know that we are connecting to a router we will mark the socket
+        to be unknown connection until we have executed authentication
+        protocol. */
+      silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+      server->sockets[sock] = newsocket;
+      newsocket->hostname = ptr->host;
+      newsocket->port = ptr->port;
+
+      /* Allocate internal protocol context. This is sent as context
+        to the protocol. */
+      proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+      proto_ctx->server = context;
+      proto_ctx->sock = newsocket;
+      proto_ctx->rng = server->rng;
+      proto_ctx->responder = FALSE;
+      
+      /* Perform key exchange protocol. silc_server_connect_to_router_final
+        will be called after the protocol is finished. */
+      silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
+                         &protocol, proto_ctx,
+                         silc_server_connect_to_router_second);
+      newsocket->protocol = protocol;
+
+      /* Register a timeout task that will be executed if the protocol
+        is not executed within 15 seconds. For now, this is a hard coded 
+        limit. After 15 secs the connection will be closed if the key 
+        exchange protocol has not been executed. */
+      proto_ctx->timeout_task = 
+       silc_task_register(server->timeout_queue, sock, 
+                          silc_server_timeout_remote,
+                          context, 15, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
+      /* Register the connection for network input and output. This sets
+        that scheduler will listen for incoming packets for this connection 
+        and sets that outgoing packets may be sent to this connection as 
+        well. However, this doesn't set the scheduler for outgoing traffic,
+        it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+        later when outgoing data is available. */
+      SILC_REGISTER_CONNECTION_FOR_IO(sock);
+      
+      /* Run the protocol */
+      protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+
+      if (!ptr->next)
+       return;
+
+      ptr = ptr->next;
+    }
+  }
+
+  SILC_LOG_DEBUG(("No router(s), server will be standalone"));
+  
+  /* There wasn't a configured router, we will continue but we don't
+     have a connection to outside world.  We will be standalone server. */
+  server->standalone = TRUE;
+
+  /* Add a task to the queue. This task receives new connections to the 
+     server. This task remains on the queue until the end of the program. */
+  if (silc_task_register(server->io_queue, fd, 
+                        silc_server_accept_new_connection,
+                        (void *)server, 0, 0, 
+                        SILC_TASK_FD,
+                        SILC_TASK_PRI_NORMAL) == NULL) {
+    silc_schedule_stop();
+    return;
+  }
+}
+
+/* Second part of connecting to router(s). Key exchange protocol has been
+   executed and now we will execute authentication protocol. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerKEInternalContext *ctx = 
+    (SilcServerKEInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSocketConnection sock = NULL;
+  SilcServerConnAuthInternalContext *proto_ctx;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    silc_protocol_free(protocol);
+    if (ctx->packet)
+      silc_buffer_free(ctx->packet);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    silc_free(ctx);
+    sock->protocol = NULL;
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Key exchange failed");
+    return;
+  }
+  
+  /* Allocate internal context for the authentication protocol. This
+     is sent as context for the protocol. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->server = (void *)server;
+  proto_ctx->sock = sock = server->sockets[fd];
+  proto_ctx->ske = ctx->ske;      /* Save SKE object from previous protocol */
+  proto_ctx->dest_id_type = ctx->dest_id_type;
+  proto_ctx->dest_id = ctx->dest_id;
+
+  /* Resolve the authentication method used in this connection */
+  proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+  if (server->config->routers) {
+    SilcConfigServerSectionServerConnection *conn = NULL;
+
+    /* Check if we find a match from user configured connections */
+    conn = silc_config_server_find_router_conn(server->config,
+                                              sock->hostname,
+                                              sock->port);
+    if (conn) {
+      /* Match found. Use the configured authentication method */
+      proto_ctx->auth_meth = conn->auth_meth;
+      if (conn->auth_data) {
+       proto_ctx->auth_data = strdup(conn->auth_data);
+       proto_ctx->auth_data_len = strlen(conn->auth_data);
+      }
+    } else {
+      /* No match found. */
+      /* XXX */
+    }
+  } else {
+    /* XXX */
+  }
+
+  /* Free old protocol as it is finished now */
+  silc_protocol_free(protocol);
+  if (ctx->packet)
+    silc_buffer_free(ctx->packet);
+  silc_free(ctx);
+  sock->protocol = NULL;
+
+  /* Allocate the authentication protocol. This is allocated here
+     but we won't start it yet. We will be receiving party of this
+     protocol thus we will wait that connecting party will make
+     their first move. */
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH, 
+                     &sock->protocol, proto_ctx, 
+                     silc_server_connect_to_router_final);
+
+  /* Register timeout task. If the protocol is not executed inside
+     this timelimit the connection will be terminated. Currently
+     this is 15 seconds and is hard coded limit (XXX). */
+  proto_ctx->timeout_task = 
+    silc_task_register(server->timeout_queue, sock->sock, 
+                      silc_server_timeout_remote,
+                      (void *)server, 15, 0,
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_LOW);
+
+  /* Run the protocol */
+  sock->protocol->execute(server->timeout_queue, 0, 
+                         sock->protocol, sock->sock, 0, 0);
+}
+
+/* Finalizes the connection to router. Registers a server task to the
+   queue so that we can accept new connections. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerConnAuthInternalContext *ctx = 
+    (SilcServerConnAuthInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSocketConnection sock = ctx->sock;
+  SilcServerList *id_entry;
+  SilcIDListUnknown *conn_data;
+  SilcBuffer packet;
+  unsigned char *id_string;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    silc_protocol_free(protocol);
+    if (ctx->packet)
+      silc_buffer_free(ctx->packet);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    silc_free(ctx);
+    sock->protocol = NULL;
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Authentication failed");
+    return;
+  }
+
+  /* Add a task to the queue. This task receives new connections to the 
+     server. This task remains on the queue until the end of the program. */
+  if (!server->listenning) {
+    if (silc_task_register(server->io_queue, server->sock, 
+                          silc_server_accept_new_connection,
+                          (void *)server, 0, 0, 
+                          SILC_TASK_FD,
+                          SILC_TASK_PRI_NORMAL) == NULL) {
+      silc_schedule_stop();
+      return;
+    } else {
+      server->listenning = TRUE;
+    }
+  }
+
+  /* Send NEW_SERVER packet to the router. We will become registered
+     to the SILC network after sending this packet. */
+  id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
+  packet = silc_buffer_alloc(2 + 2 + SILC_ID_SERVER_LEN + 
+                            strlen(server->server_name));
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(SILC_ID_SERVER_LEN),
+                    SILC_STR_UI_XNSTRING(id_string, SILC_ID_SERVER_LEN),
+                    SILC_STR_UI_SHORT(strlen(server->server_name)),
+                    SILC_STR_UI_XNSTRING(server->server_name,
+                                         strlen(server->server_name)),
+                    SILC_STR_END);
+
+  /* Send the packet */
+  silc_server_packet_send(server, ctx->sock, SILC_PACKET_NEW_SERVER, 0,
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+  silc_free(id_string);
+
+  SILC_LOG_DEBUG(("Connected to router %s", sock->hostname));
+
+  /* Add the connected router to local server list */
+  server->standalone = FALSE;
+  conn_data = (SilcIDListUnknown *)sock->user_data;
+  silc_idlist_add_server(&server->local_list->servers, 
+                        sock->hostname ? sock->hostname : sock->ip,
+                        SILC_ROUTER, ctx->dest_id, NULL,
+                        conn_data->send_key, conn_data->receive_key,
+                        conn_data->pkcs, conn_data->hmac, &id_entry);
+
+  id_entry->hmac_key = conn_data->hmac_key;
+  id_entry->hmac_key_len = conn_data->hmac_key_len;
+  id_entry->connection = sock;
+  sock->user_data = (void *)id_entry;
+  sock->type = SILC_SOCKET_TYPE_ROUTER;
+  server->id_entry->router = id_entry;
+
+  /* Free the temporary connection data context from key exchange */
+  silc_free(conn_data);
+
+  /* Free the protocol object */
+  silc_protocol_free(protocol);
+  if (ctx->packet)
+    silc_buffer_free(ctx->packet);
+  if (ctx->ske)
+    silc_ske_free(ctx->ske);
+  silc_free(ctx);
+  sock->protocol = NULL;
+}
+
+/* Accepts new connections to the server. Accepting new connections are
+   done in three parts to make it async. */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+{
+  SilcServer server = (SilcServer)context;
+  SilcSocketConnection newsocket;
+  SilcServerKEInternalContext *proto_ctx;
+  int sock;
+
+  SILC_LOG_DEBUG(("Accepting new connection"));
+
+  sock = silc_net_accept_connection(server->sock);
+  if (sock < 0) {
+    SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
+    return;
+  }
+
+  /* Check max connections */
+  if (sock > SILC_SERVER_MAX_CONNECTIONS) {
+    if (server->config->redirect) {
+      /* XXX Redirecting connection to somewhere else now?? */
+      /*silc_server_send_notify("Server is full, trying to redirect..."); */
+    } else {
+      SILC_LOG_ERROR(("Refusing connection, server is full"));
+    }
+    return;
+  }
+
+  /* Set socket options */
+  silc_net_set_socket_nonblock(sock);
+  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+  /* We don't create a ID yet, since we don't know what type of connection
+     this is yet. But, we do add the connection to the socket table. */
+  silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+  server->sockets[sock] = newsocket;
+
+  /* XXX This MUST be done async as this will block the entire server
+     process. Either we have to do our own resolver stuff or in the future
+     we can use threads. */
+  /* Perform mandatory name and address lookups for the remote host. */
+  silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
+  if (!newsocket->ip || !newsocket->hostname) {
+    SILC_LOG_DEBUG(("IP lookup/DNS lookup failed"));
+    SILC_LOG_ERROR(("IP lookup/DNS lookup failed"));
+    return;
+  }
+
+  /* Allocate internal context for key exchange protocol. This is
+     sent as context for the protocol. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->server = context;
+  proto_ctx->sock = newsocket;
+  proto_ctx->rng = server->rng;
+  proto_ctx->responder = TRUE;
+
+  /* Prepare the connection for key exchange protocol. We allocate the
+     protocol but will not start it yet. The connector will be the
+     initiator of the protocol thus we will wait for initiation from 
+     there before we start the protocol. */
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
+                     &newsocket->protocol, proto_ctx, 
+                     silc_server_accept_new_connection_second);
+
+  /* Register a timeout task that will be executed if the connector
+     will not start the key exchange protocol within 15 seconds. For
+     now, this is a hard coded limit. After 15 secs the connection will
+     be closed if the key exchange protocol has not been started. */
+  proto_ctx->timeout_task = 
+    silc_task_register(server->timeout_queue, newsocket->sock, 
+                      silc_server_timeout_remote,
+                      context, 15, 0,
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_LOW);
+
+  /* Register the connection for network input and output. This sets
+     that scheduler will listen for incoming packets for this connection 
+     and sets that outgoing packets may be sent to this connection as well.
+     However, this doesn't set the scheduler for outgoing traffic, it
+     will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+     later when outgoing data is available. */
+  SILC_REGISTER_CONNECTION_FOR_IO(sock);
+}
+
+/* Second part of accepting new connection. Key exchange protocol has been
+   performed and now it is time to do little connection authentication
+   protocol to figure out whether this connection is client or server
+   and whether it has right to access this server (especially server
+   connections needs to be authenticated). */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerKEInternalContext *ctx = 
+    (SilcServerKEInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSocketConnection sock = NULL;
+  SilcServerConnAuthInternalContext *proto_ctx;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    silc_protocol_free(protocol);
+    if (ctx->packet)
+      silc_buffer_free(ctx->packet);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    silc_free(ctx);
+    sock->protocol = NULL;
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Key exchange failed");
+    return;
+  }
+
+  /* Allocate internal context for the authentication protocol. This
+     is sent as context for the protocol. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->server = (void *)server;
+  proto_ctx->sock = sock = server->sockets[fd];
+  proto_ctx->ske = ctx->ske;   /* Save SKE object from previous protocol */
+  proto_ctx->responder = TRUE;
+  proto_ctx->dest_id_type = ctx->dest_id_type;
+  proto_ctx->dest_id = ctx->dest_id;
+
+  /* Free old protocol as it is finished now */
+  silc_protocol_free(protocol);
+  if (ctx->packet)
+    silc_buffer_free(ctx->packet);
+  silc_free(ctx);
+  sock->protocol = NULL;
+
+  /* Allocate the authentication protocol. This is allocated here
+     but we won't start it yet. We will be receiving party of this
+     protocol thus we will wait that connecting party will make
+     their first move. */
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH, 
+                     &sock->protocol, proto_ctx, 
+                     silc_server_accept_new_connection_final);
+
+  /* Register timeout task. If the protocol is not executed inside
+     this timelimit the connection will be terminated. Currently
+     this is 60 seconds and is hard coded limit (XXX). */
+  proto_ctx->timeout_task = 
+    silc_task_register(server->timeout_queue, sock->sock, 
+                      silc_server_timeout_remote,
+                      (void *)server, 60, 0,
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_LOW);
+}
+
+/* Final part of accepting new connection. The connection has now
+   been authenticated and keys has been exchanged. We also know whether
+   this is client or server connection. */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerConnAuthInternalContext *ctx = 
+    (SilcServerConnAuthInternalContext *)protocol->context;
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSocketConnection sock = ctx->sock;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    silc_protocol_free(protocol);
+    if (ctx->packet)
+      silc_buffer_free(ctx->packet);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    silc_free(ctx);
+    sock->protocol = NULL;
+    silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                 "Authentication failed");
+    return;
+  }
+
+  sock->type = ctx->conn_type;
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    {
+      SilcClientList *id_entry = NULL;
+      SilcIDListUnknown *conn_data = sock->user_data;
+
+      SILC_LOG_DEBUG(("Remote host is client"));
+
+      /* Add the client to the client ID list. We have not created the
+        client ID for the client yet. This is done when client registers
+        itself by sending NEW_CLIENT packet. */
+      silc_idlist_add_client(&server->local_list->clients, 
+                            NULL, NULL, NULL, NULL, NULL,
+                            conn_data->send_key, conn_data->receive_key, 
+                            conn_data->pkcs, conn_data->hmac, &id_entry);
+
+      id_entry->hmac_key = conn_data->hmac_key;
+      id_entry->hmac_key_len = conn_data->hmac_key_len;
+      id_entry->connection = sock;
+
+      /* Free the temporary connection data context from key exchange */
+      silc_free(conn_data);
+
+      /* Mark the entry to the ID list to the socket connection for
+        fast referencing in the future. */
+      sock->user_data = (void *)id_entry;
+      break;
+    }
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    {
+      SilcServerList *id_entry;
+      SilcIDListUnknown *conn_data = sock->user_data;
+      
+      SILC_LOG_DEBUG(("Remote host is %s", 
+                     sock->type == SILC_SOCKET_TYPE_SERVER ? 
+                     "server" : "router"));
+      
+      /* Add the server to the ID list. We don't have the server's ID
+        yet but we will receive it after the server sends NEW_SERVER
+        packet to us. */
+      silc_idlist_add_server(&server->local_list->servers, NULL,
+                            sock->type == SILC_SOCKET_TYPE_SERVER ?
+                            SILC_SERVER : SILC_ROUTER, NULL, NULL,
+                            conn_data->send_key, conn_data->receive_key,
+                            conn_data->pkcs, conn_data->hmac, &id_entry);
+
+      id_entry->hmac_key = conn_data->hmac_key;
+      id_entry->hmac_key_len = conn_data->hmac_key_len;
+      id_entry->connection = sock;
+
+      /* Free the temporary connection data context from key exchange */
+      silc_free(conn_data);
+
+      /* Mark the entry to the ID list to the socket connection for
+        fast referencing in the future. */
+      sock->user_data = (void *)id_entry;
+
+      /* There is connection to other server now, if it is router then
+        we will have connection to outside world.  If we are router but
+        normal server connected to us then we will remain standalone,
+        if we are standlone. */
+      if (server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       SILC_LOG_DEBUG(("We are not standalone server anymore"));
+       server->standalone = FALSE;
+      }
+      break;
+    }
+  default:
+    break;
+  }
+
+  /* Connection has been fully established now. Everything is ok. */
+  SILC_LOG_DEBUG(("New connection authenticated"));
+
+  silc_protocol_free(protocol);
+  if (ctx->packet)
+    silc_buffer_free(ctx->packet);
+  if (ctx->ske)
+    silc_ske_free(ctx->ske);
+  if (ctx->dest_id)
+    silc_free(ctx->dest_id);
+  silc_free(ctx);
+  sock->protocol = NULL;
+}
+
+typedef struct {
+  SilcPacketContext *packetdata;
+  SilcServer server;
+  SilcSocketConnection sock;
+  SilcCipher cipher;
+  SilcHmac hmac;
+} SilcServerInternalPacket;
+
+/* This function is used to read packets from network and send packets to
+   network. This is usually a generic task. */
+
+SILC_TASK_CALLBACK(silc_server_packet_process)
+{
+  SilcServer server = (SilcServer)context;
+  SilcSocketConnection sock = server->sockets[fd];
+  int ret, packetlen, paddedlen;
+
+  SILC_LOG_DEBUG(("Processing packet"));
+
+  /* Packet sending */
+  if (type == SILC_TASK_WRITE) {
+    SILC_LOG_DEBUG(("Writing data to connection"));
+
+    if (sock->outbuf->data - sock->outbuf->head)
+      silc_buffer_push(sock->outbuf, 
+                      sock->outbuf->data - sock->outbuf->head);
+
+    /* Write the packet out to the connection */
+    ret = silc_packet_write(fd, sock->outbuf);
+
+    /* If returned -2 could not write to connection now, will do
+       it later. */
+    if (ret == -2)
+      return;
+    
+    /* Error */
+    if (ret == -1)
+      SILC_LOG_ERROR(("Could not write, packet dropped"));
+
+    /* The packet has been sent and now it is time to set the connection
+       back to only for input. When there is again some outgoing data 
+       available for this connection it will be set for output as well. 
+       This call clears the output setting and sets it only for input. */
+    SILC_SET_CONNECTION_FOR_INPUT(fd);
+    SILC_UNSET_OUTBUF_PENDING(sock);
+
+    silc_buffer_clear(sock->outbuf);
+    return;
+  }
+
+  /* Packet receiving */
+  if (type == SILC_TASK_READ) {
+    SILC_LOG_DEBUG(("Reading data from connection"));
+
+    /* Allocate the incoming data buffer if not done already. */
+    if (!sock->inbuf)
+      sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+
+    /* Read some data from connection */
+    ret = silc_packet_read(fd, sock->inbuf);
+    
+    /* If returned -2 data was not available now, will read it later. */
+    if (ret == -2)
+      return;
+    
+    /* Error */
+    if (ret == -1) {
+      SILC_LOG_ERROR(("Could not read, packet dropped"));
+      return;
+    }
+    
+    /* EOF */
+    if (ret == 0) {
+      SILC_LOG_DEBUG(("Read EOF"));
+      
+      /* If connection is disconnecting already we will finally
+        close the connection */
+      if (SILC_IS_DISCONNECTING(sock)) {
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock);
+       silc_server_close_connection(server, sock);
+       return;
+      }
+      
+      SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+
+      if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock);
+      silc_server_close_connection(server, sock);
+      return;
+    }
+
+    /* If connection is disconnecting or disconnected we will ignore
+       what we read. */
+    if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+      SILC_LOG_DEBUG(("Ignoring read data from invalid connection"));
+      return;
+    }
+
+    /* Check whether we received a whole packet. If reading went without
+       errors we either read a whole packet or the read packet is 
+       incorrect and will be dropped. */
+    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+    if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
+      SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+      silc_buffer_clear(sock->inbuf);
+      silc_server_disconnect_remote(server, sock, "Incorrect packet");
+      return;
+    }
+
+    /* Decrypt a packet coming from client. */
+    if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+      SilcClientList *clnt = (SilcClientList *)sock->user_data;
+      SilcServerInternalPacket *packet;
+      int mac_len = 0;
+      
+      if (clnt->hmac)
+       mac_len = clnt->hmac->hash->hash->hash_len;
+
+      if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+       /* Received possibly many packets at once */
+
+       while(sock->inbuf->len > 0) {
+         SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+         if (sock->inbuf->len < paddedlen) {
+           SILC_LOG_DEBUG(("Receive incorrect packet, dropped"));
+           return;
+         }
+
+         paddedlen += 2;
+         packet = silc_calloc(1, sizeof(*packet));
+         packet->server = server;
+         packet->sock = sock;
+         packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+         packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
+         silc_buffer_pull_tail(packet->packetdata->buffer, 
+                               SILC_BUFFER_END(packet->packetdata->buffer));
+         silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data, 
+                         paddedlen + mac_len);
+         if (clnt) {
+           packet->cipher = clnt->receive_key;
+           packet->hmac = clnt->hmac;
+         }
+
+         SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
+                           packet->packetdata->buffer->len),
+                          packet->packetdata->buffer->data, 
+                          packet->packetdata->buffer->len);
+
+         /* Parse the packet with timeout */
+         silc_task_register(server->timeout_queue, fd, 
+                            silc_server_packet_parse,
+                            (void *)packet, 0, 100000, 
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+
+         /* Pull the packet from inbuf thus we'll get the next one
+            in the inbuf. */
+         silc_buffer_pull(sock->inbuf, paddedlen);
+         if (clnt->hmac)
+           silc_buffer_pull(sock->inbuf, mac_len);
+       }
+       silc_buffer_clear(sock->inbuf);
+       return;
+      } else {
+       SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+                        sock->inbuf->data, sock->inbuf->len);
+       
+       SILC_LOG_DEBUG(("Packet from client, length %d", paddedlen));
+       
+       packet = silc_calloc(1, sizeof(*packet));
+       packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+       packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+       packet->server = server;
+       packet->sock = sock;
+       if (clnt) {
+         packet->cipher = clnt->receive_key;
+         packet->hmac = clnt->hmac;
+       }
+       silc_buffer_clear(sock->inbuf);
+       
+       /* The packet is ready to be parsed now. However, this is a client 
+          connection so we will parse the packet with timeout. */
+       silc_task_register(server->timeout_queue, fd, 
+                          silc_server_packet_parse,
+                          (void *)packet, 0, 100000, 
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
+       return;
+      }
+    }
+    
+    /* Decrypt a packet coming from server connection */
+    if (sock->type == SILC_SOCKET_TYPE_SERVER ||
+       sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      SilcServerList *srvr = (SilcServerList *)sock->user_data;
+      SilcServerInternalPacket *packet;
+      int mac_len = 0;
+      
+      if (srvr->hmac)
+       mac_len = srvr->hmac->hash->hash->hash_len;
+
+      if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+       /* Received possibly many packets at once */
+
+       while(sock->inbuf->len > 0) {
+         SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+         if (sock->inbuf->len < paddedlen) {
+           SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
+           return;
+         }
+
+         paddedlen += 2;
+         packet = silc_calloc(1, sizeof(*packet));
+         packet->server = server;
+         packet->sock = sock;
+         packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+         packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
+         silc_buffer_pull_tail(packet->packetdata->buffer, 
+                               SILC_BUFFER_END(packet->packetdata->buffer));
+         silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data, 
+                         paddedlen + mac_len);
+         if (srvr) {
+           packet->cipher = srvr->receive_key;
+           packet->hmac = srvr->hmac;
+         }
+
+         SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
+                           packet->packetdata->buffer->len),
+                          packet->packetdata->buffer->data, 
+                          packet->packetdata->buffer->len);
+
+         SILC_LOG_DEBUG(("Packet from %s %s, packet length %d", 
+                         srvr->server_type == SILC_SERVER ? 
+                         "server" : "router",
+                         srvr->server_name, paddedlen));
+       
+         /* Parse it real soon as the packet is from server. */
+         silc_task_register(server->timeout_queue, fd, 
+                            silc_server_packet_parse,
+                            (void *)packet, 0, 1, 
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+
+         /* Pull the packet from inbuf thus we'll get the next one
+            in the inbuf. */
+         silc_buffer_pull(sock->inbuf, paddedlen);
+         if (srvr->hmac)
+           silc_buffer_pull(sock->inbuf, mac_len);
+       }
+       silc_buffer_clear(sock->inbuf);
+       return;
+      } else {
+
+       SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+                        sock->inbuf->data, sock->inbuf->len);
+       
+       SILC_LOG_DEBUG(("Packet from %s %s, packet length %d", 
+                       srvr->server_type == SILC_SERVER ? 
+                       "server" : "router",
+                       srvr->server_name, paddedlen));
+       
+       packet = silc_calloc(1, sizeof(*packet));
+       packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+       packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+       packet->server = server;
+       packet->sock = sock;
+       if (srvr) {
+         packet->cipher = srvr->receive_key;
+         packet->hmac = srvr->hmac;
+       }
+       silc_buffer_clear(sock->inbuf);
+       
+       /* The packet is ready to be parsed now. However, this is a client 
+          connection so we will parse the packet with timeout. */
+       silc_task_register(server->timeout_queue, fd, 
+                          silc_server_packet_parse,
+                          (void *)packet, 0, 1, 
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
+       return;
+      }
+    }
+
+    /* Decrypt a packet coming from client. */
+    if (sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
+      SilcIDListUnknown *conn_data = (SilcIDListUnknown *)sock->user_data;
+      SilcServerInternalPacket *packet;
+      
+      SILC_LOG_HEXDUMP(("Incoming packet, len %d", sock->inbuf->len),
+                      sock->inbuf->data, sock->inbuf->len);
+
+      SILC_LOG_DEBUG(("Packet from unknown connection, length %d", 
+                     paddedlen));
+
+      packet = silc_calloc(1, sizeof(*packet));
+      packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
+      packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
+      packet->server = server;
+      packet->sock = sock;
+      if (conn_data) {
+       packet->cipher = conn_data->receive_key;
+       packet->hmac = conn_data->hmac;
+      }
+
+      silc_buffer_clear(sock->inbuf);
+
+      /* The packet is ready to be parsed now. However, this is unknown 
+        connection so we will parse the packet with timeout. */
+      silc_task_register(server->timeout_queue, fd, 
+                        silc_server_packet_parse,
+                        (void *)packet, 0, 100000, 
+                        SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_NORMAL);
+      return;
+    }
+  }
+
+  SILC_LOG_ERROR(("Weird, nothing happened - ignoring"));
+}
+
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
+   after packet has been totally decrypted and parsed. */
+
+static int silc_server_packet_check_mac(SilcServer server,
+                                       SilcSocketConnection sock,
+                                       SilcBuffer buffer)
+{
+  SilcHmac hmac = NULL;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned int mac_len = 0;
+
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    if (sock->user_data) {
+      hmac = ((SilcClientList *)sock->user_data)->hmac;
+      hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
+      hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
+    }
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    if (sock->user_data) {
+      hmac = ((SilcServerList *)sock->user_data)->hmac;
+      hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
+      hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
+    }
+    break;
+  default:
+    if (sock->user_data) {
+      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+      hmac_key = ((SilcIDListUnknown *)sock->user_data)->hmac_key;
+      hmac_key_len = ((SilcIDListUnknown *)sock->user_data)->hmac_key_len;
+    }
+  }
+
+  /* Check MAC */
+  if (hmac) {
+    int headlen = buffer->data - buffer->head;
+    unsigned char *packet_mac, mac[32];
+    
+    SILC_LOG_DEBUG(("Verifying MAC"));
+
+    mac_len = hmac->hash->hash->hash_len;
+
+    silc_buffer_push(buffer, headlen);
+    
+    /* Take mac from packet */
+    packet_mac = buffer->tail;
+    
+    /* Make MAC and compare */
+    memset(mac, 0, sizeof(mac));
+    silc_hmac_make_with_key(hmac, 
+                           buffer->data, buffer->len,
+                           hmac_key, hmac_key_len, mac);
+#if 0
+    SILC_LOG_HEXDUMP(("PMAC"), packet_mac, mac_len);
+    SILC_LOG_HEXDUMP(("CMAC"), mac, mac_len);
+#endif
+    if (memcmp(mac, packet_mac, mac_len)) {
+      SILC_LOG_DEBUG(("MAC failed"));
+      return FALSE;
+    }
+    
+    SILC_LOG_DEBUG(("MAC is Ok"));
+    memset(mac, 0, sizeof(mac));
+
+    silc_buffer_pull(buffer, headlen);
+  }
+  
+  return TRUE;
+}
+
+/* Decrypts rest of the packet (after decrypting just the SILC header).
+   After calling this function the packet is ready to be parsed by calling 
+   silc_packet_parse. */
+
+static int silc_server_packet_decrypt_rest(SilcServer server, 
+                                          SilcSocketConnection sock,
+                                          SilcBuffer buffer)
+{
+  SilcCipher session_key = NULL;
+  SilcHmac hmac = NULL;
+  unsigned int mac_len = 0;
+
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    if (sock->user_data) {
+      session_key = ((SilcClientList *)sock->user_data)->receive_key;
+      hmac = ((SilcClientList *)sock->user_data)->hmac;
+    }
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    if (sock->user_data) {
+      session_key = ((SilcServerList *)sock->user_data)->receive_key;
+      hmac = ((SilcServerList *)sock->user_data)->hmac;
+    }
+    break;
+  default:
+    if (sock->user_data) {
+      session_key = ((SilcIDListUnknown *)sock->user_data)->receive_key;
+      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+    }
+  }
+  
+  /* Decrypt */
+  if (session_key) {
+
+    /* Pull MAC from packet before decryption */
+    if (hmac) {
+      mac_len = hmac->hash->hash->hash_len;
+      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, mac_len);
+      } else {
+       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       return FALSE;
+      }
+    }
+
+    SILC_LOG_DEBUG(("Decrypting rest of the packet"));
+
+    /* Decrypt rest of the packet */
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    silc_packet_decrypt(session_key, buffer, buffer->len);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+
+    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
+                    buffer->data, buffer->len);
+  }
+
+  return TRUE;
+}
+
+/* Decrypts rest of the SILC Packet header that has been decrypted partly
+   already. This decrypts the padding of the packet also.  After calling 
+   this function the packet is ready to be parsed by calling function 
+   silc_packet_parse. */
+
+static int silc_server_packet_decrypt_rest_special(SilcServer server, 
+                                                  SilcSocketConnection sock,
+                                                  SilcBuffer buffer)
+{
+  SilcCipher session_key = NULL;
+  SilcHmac hmac = NULL;
+  unsigned int mac_len = 0;
+
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    if (sock->user_data) {
+      session_key = ((SilcClientList *)sock->user_data)->receive_key;
+      hmac = ((SilcClientList *)sock->user_data)->hmac;
+    }
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    if (sock->user_data) {
+      session_key = ((SilcServerList *)sock->user_data)->receive_key;
+      hmac = ((SilcServerList *)sock->user_data)->hmac;
+    }
+    break;
+  default:
+    if (sock->user_data) {
+      session_key = ((SilcIDListUnknown *)sock->user_data)->receive_key;
+      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+    }
+  }
+  
+  /* Decrypt rest of the header plus padding */
+  if (session_key) {
+    unsigned short truelen, len1, len2, padlen;
+
+    /* Pull MAC from packet before decryption */
+    if (hmac) {
+      mac_len = hmac->hash->hash->hash_len;
+      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, mac_len);
+      } else {
+       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       return FALSE;
+      }
+    }
+  
+    SILC_LOG_DEBUG(("Decrypting rest of the header"));
+
+    SILC_GET16_MSB(len1, &buffer->data[4]);
+    SILC_GET16_MSB(len2, &buffer->data[6]);
+
+    truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
+    padlen = SILC_PACKET_PADLEN(truelen);
+    len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
+
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    silc_packet_decrypt(session_key, buffer, len1);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+  }
+
+  return TRUE;
+}
+
+/* Parses whole packet, received earlier. This packet is usually received
+   from client. */
+
+SILC_TASK_CALLBACK(silc_server_packet_parse)
+{
+  SilcServerInternalPacket *packet = (SilcServerInternalPacket *)context;
+  SilcServer server = packet->server;
+  SilcSocketConnection sock = packet->sock;
+  SilcBuffer buffer = packet->packetdata->buffer;
+  int ret;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Decrypt start of the packet header */
+  if (packet->cipher)
+    silc_packet_decrypt(packet->cipher, buffer, SILC_PACKET_MIN_HEADER_LEN);
+
+  /* If the packet type is not any special type lets decrypt rest
+     of the packet here. */
+  if (buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE &&
+      buffer->data[3] != SILC_PACKET_PRIVATE_MESSAGE) {
+  normal:
+    /* Normal packet, decrypt rest of the packet */
+    if (!silc_server_packet_decrypt_rest(server, sock, buffer))
+      goto out;
+
+    /* Parse the packet. Packet type is returned. */
+    ret = silc_packet_parse(packet->packetdata);
+    if (ret == SILC_PACKET_NONE)
+      goto out;
+
+    /* Check MAC */
+    if (!silc_server_packet_check_mac(server, sock, buffer))
+      goto out;
+  } else {
+    /* If private message key is not set for private message it is
+       handled as normal packet. Go back up. */
+    if (buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+       !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+      goto normal;
+
+    /* Packet requires special handling, decrypt rest of the header.
+       This only decrypts. This does not do any MAC checking, it must
+       be done individually later when doing the special processing. */
+    silc_server_packet_decrypt_rest_special(server, sock, buffer);
+
+    /* Parse the packet header in special way as this is "special"
+       packet type. */
+    ret = silc_packet_parse_special(packet->packetdata);
+    if (ret == SILC_PACKET_NONE)
+      goto out;
+  }
+  
+  /* Parse the incoming packet type */
+  silc_server_packet_parse_type(server, sock, packet->packetdata);
+
+ out:
+  silc_buffer_clear(sock->inbuf);
+  //  silc_buffer_free(packetdata->packetdata->buffer);
+  silc_free(packet->packetdata);
+  silc_free(packet);
+}
+
+/* Parses the packet type and calls what ever routines the packet type
+   requires. This is done for all incoming packets. */
+
+void silc_server_packet_parse_type(SilcServer server, 
+                                  SilcSocketConnection sock,
+                                  SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcPacketType type = packet->type;
+
+  SILC_LOG_DEBUG(("Parsing packet type %d", type));
+
+  /* Parse the packet type */
+  switch(type) {
+  case SILC_PACKET_DISCONNECT:
+    SILC_LOG_DEBUG(("Disconnect packet"));
+    break;
+  case SILC_PACKET_SUCCESS:
+    /*
+     * Success received for something. For now we can have only
+     * one protocol for connection executing at once hence this
+     * success message is for whatever protocol is executing currently.
+     */
+    SILC_LOG_DEBUG(("Success packet"));
+    if (sock->protocol) {
+      sock->protocol->execute(server->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    }
+    break;
+  case SILC_PACKET_FAILURE:
+    SILC_LOG_DEBUG(("Failure packet"));
+    break;
+  case SILC_PACKET_REJECT:
+    SILC_LOG_DEBUG(("Reject packet"));
+    return;
+    break;
+
+    /* 
+     * Channel packets
+     */
+  case SILC_PACKET_CHANNEL_MESSAGE:
+    /*
+     * Received channel message. Channel messages are special packets
+     * (although probably most common ones) hence they are handled
+     * specially.
+     */
+    SILC_LOG_DEBUG(("Channel Message packet"));
+    silc_server_channel_message(server, sock, packet);
+    break;
+
+  case SILC_PACKET_CHANNEL_KEY:
+    /*
+     * Received key for channel. As channels are created by the router
+     * the keys are as well. We will distribute the key to all of our
+     * locally connected clients on the particular channel. Router
+     * never receives this channel and thus is ignored.
+     */
+    SILC_LOG_DEBUG(("Channel Key packet"));
+    silc_server_channel_key(server, sock, packet);
+    break;
+
+    /*
+     * Command packets
+     */
+  case SILC_PACKET_COMMAND:
+    {
+      /*
+       * Recived command. Allocate command context and execute the command.
+       */
+      SilcServerCommandContext ctx;
+
+      SILC_LOG_DEBUG(("Command packet"));
+
+      /* Router cannot send command packet */
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER)
+       break;
+
+      /* Allocate command context. This must be free'd by the
+        command routine receiving it. */
+      ctx = silc_calloc(1, sizeof(*ctx));
+      ctx->server = server;
+      ctx->sock = sock;
+      ctx->packet = packet;    /* Save original packet */
+
+      /* Parse the command payload in the packet */
+      ctx->payload = silc_command_parse_payload(buffer);
+      if (!ctx->payload) {
+       SILC_LOG_ERROR(("Bad command payload, packet dropped"));
+       silc_free(ctx);
+       return;
+      }
+
+      /* Execute command. If this fails the packet is dropped. */
+      SILC_SERVER_COMMAND_EXEC(ctx);
+      silc_buffer_free(buffer);
+    }
+    break;
+
+  case SILC_PACKET_COMMAND_REPLY:
+    /*
+     * Received command reply packet. Servers never send commands thus
+     * they don't receive command reply packets either, except in cases
+     * where server has forwarded command packet coming from client. 
+     * This must be the case here or we will ignore the packet.
+     */
+    SILC_LOG_DEBUG(("Command Reply packet"));
+    silc_server_packet_relay_command_reply(server, sock, packet);
+    break;
+
+    /*
+     * Private Message packets
+     */
+  case SILC_PACKET_PRIVATE_MESSAGE:
+    /*
+     * Received private message packet. The packet is coming from either
+     * client or server.
+     */
+    SILC_LOG_DEBUG(("Private Message packet"));
+    silc_server_private_message(server, sock, packet);
+    break;
+
+  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+    break;
+
+    /*
+     * Key Exchange protocol packets
+     */
+  case SILC_PACKET_KEY_EXCHANGE:
+    SILC_LOG_DEBUG(("KE packet"));
+    if (sock->protocol && sock->protocol->protocol->type 
+       == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+
+      SilcServerKEInternalContext *proto_ctx = 
+       (SilcServerKEInternalContext *)sock->protocol->context;
+
+      proto_ctx->packet = buffer;
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(server->timeout_queue, 0, 
+                             sock->protocol, sock->sock, 0, 100000);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
+                     "protocol active, packet dropped."));
+
+      /* XXX Trigger KE protocol?? Rekey actually, maybe. */
+    }
+    break;
+
+  case SILC_PACKET_KEY_EXCHANGE_1:
+    SILC_LOG_DEBUG(("KE 1 packet"));
+    if (sock->protocol && sock->protocol->protocol->type 
+       == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+
+      SilcServerKEInternalContext *proto_ctx = 
+       (SilcServerKEInternalContext *)sock->protocol->context;
+
+      if (proto_ctx->packet)
+       silc_buffer_free(proto_ctx->packet);
+
+      proto_ctx->packet = buffer;
+      proto_ctx->dest_id_type = packet->src_id_type;
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(server->timeout_queue, 0, 
+                             sock->protocol, sock->sock,
+                             0, 100000);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
+                     "protocol active, packet dropped."));
+    }
+    break;
+
+  case SILC_PACKET_KEY_EXCHANGE_2:
+    SILC_LOG_DEBUG(("KE 2 packet"));
+    if (sock->protocol && sock->protocol->protocol->type 
+       == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+
+      SilcServerKEInternalContext *proto_ctx = 
+       (SilcServerKEInternalContext *)sock->protocol->context;
+
+      if (proto_ctx->packet)
+       silc_buffer_free(proto_ctx->packet);
+
+      proto_ctx->packet = buffer;
+      proto_ctx->dest_id_type = packet->src_id_type;
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(server->timeout_queue, 0, 
+                             sock->protocol, sock->sock,
+                             0, 100000);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
+                     "protocol active, packet dropped."));
+    }
+    break;
+
+  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+    /* If we receive this packet we will send to the other end information
+       about our mandatory authentication method for the connection. 
+       This packet maybe received at any time. */
+
+    /*
+     * Connection Authentication protocol packets
+     */
+  case SILC_PACKET_CONNECTION_AUTH:
+    /* Start of the authentication protocol. We receive here the 
+       authentication data and will verify it. */
+    SILC_LOG_DEBUG(("Connection auth packet"));
+    if (sock->protocol && sock->protocol->protocol->type 
+       == SILC_PROTOCOL_SERVER_CONNECTION_AUTH) {
+
+      SilcServerConnAuthInternalContext *proto_ctx = 
+       (SilcServerConnAuthInternalContext *)sock->protocol->context;
+
+      proto_ctx->packet = buffer;
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(server->timeout_queue, 0, 
+                             sock->protocol, sock->sock, 0, 0);
+    } else {
+      SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
+                     "protocol active, packet dropped."));
+    }
+    break;
+
+  case SILC_PACKET_NEW_ID:
+    /*
+     * Received New ID packet. This includes some new ID that has been
+     * created. It may be for client, server or channel. This is the way
+     * to distribute information about new registered entities in the
+     * SILC network.
+     */
+    SILC_LOG_DEBUG(("New ID packet"));
+    silc_server_new_id(server, sock, packet);
+    break;
+
+  case SILC_PACKET_NEW_CLIENT:
+    /*
+     * Received new client packet. This includes client information that
+     * we will use to create initial client ID. After creating new
+     * ID we will send it to the client.
+     */
+    SILC_LOG_DEBUG(("New Client packet"));
+    silc_server_new_client(server, sock, packet);
+    break;
+
+  case SILC_PACKET_NEW_SERVER:
+    /*
+     * Received new server packet. This includes Server ID and some other
+     * information that we may save. This is after server as connected to us.
+     */
+    SILC_LOG_DEBUG(("New Server packet"));
+    silc_server_new_server(server, sock, packet);
+    break;
+
+  default:
+    SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
+    break;
+  }
+  
+}
+
+/* Internal routine that sends packet or marks packet to be sent. This
+   is used directly only in special cases. Normal cases should use
+   silc_server_packet_send. Returns < 0 error. */
+
+static int silc_server_packet_send_real(SilcServer server,
+                                       SilcSocketConnection sock,
+                                       int force_send)
+{
+  /* Send now if forced to do so */
+  if (force_send == TRUE) {
+    int ret;
+    SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
+    ret = silc_packet_write(sock->sock, sock->outbuf);
+
+    silc_buffer_clear(sock->outbuf);
+
+    if (ret == -1)
+      SILC_LOG_ERROR(("Could not write, packet dropped"));
+    if (ret != -2) {
+      silc_buffer_clear(sock->outbuf);
+      return ret;
+    }
+
+    SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
+  }  
+
+  SILC_LOG_DEBUG(("Packet in queue"));
+
+  /* Mark that there is some outgoing data available for this connection. 
+     This call sets the connection both for input and output (the input
+     is set always and this call keeps the input setting, actually). 
+     Actual data sending is performed by silc_server_packet_process. */
+  SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+  /* Mark to socket that data is pending in outgoing buffer. This flag
+     is needed if new data is added to the buffer before the earlier
+     put data is sent to the network. */
+  SILC_SET_OUTBUF_PENDING(sock);
+
+  return 0;
+}
+
+/* Prepare outgoing data buffer for packet sending. This is internal
+   routine and must always be called before sending any packets out. */
+
+static void silc_server_packet_send_prepare(SilcServer server, 
+                                           SilcSocketConnection sock,
+                                           unsigned int header_len,
+                                           unsigned int padlen,
+                                           unsigned int data_len)
+{
+  int totlen, oldlen;
+
+  totlen = header_len + padlen + data_len;
+
+  /* Prepare the outgoing buffer for packet sending. */
+  if (!sock->outbuf) {
+    /* Allocate new buffer. This is done only once per connection. */
+    SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
+    
+    sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+    silc_buffer_pull_tail(sock->outbuf, totlen);
+    silc_buffer_pull(sock->outbuf, header_len + padlen);
+  } else {
+    if (SILC_IS_OUTBUF_PENDING(sock)) {
+      /* There is some pending data in the buffer. */
+
+      if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
+       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+       /* XXX: not done yet */
+      }
+      oldlen = sock->outbuf->len;
+      silc_buffer_pull_tail(sock->outbuf, totlen);
+      silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
+    } else {
+      /* Buffer is free for use */
+      silc_buffer_clear(sock->outbuf);
+      silc_buffer_pull_tail(sock->outbuf, totlen);
+      silc_buffer_pull(sock->outbuf, header_len + padlen);
+    }
+  }
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+   send the packet but creates the packet and fills the outgoing data
+   buffer and marks the packet ready to be sent to network. However, If 
+   argument force_send is TRUE the packet is sent immediately and not put 
+   to queue. Normal case is that the packet is not sent immediately. */
+
+void silc_server_packet_send(SilcServer server,
+                            SilcSocketConnection sock, 
+                            SilcPacketType type, 
+                            SilcPacketFlags flags,
+                            unsigned char *data, 
+                            unsigned int data_len,
+                            int force_send)
+{
+  void *dst_id = NULL;
+  SilcIdType dst_id_type = SILC_ID_NONE;
+
+  /* Get data used in the packet sending, keys and stuff */
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    if (((SilcClientList *)sock->user_data)->id) {
+      dst_id = ((SilcClientList *)sock->user_data)->id;
+      dst_id_type = SILC_ID_CLIENT;
+    }
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    if (((SilcServerList *)sock->user_data)->id) {
+      dst_id = ((SilcServerList *)sock->user_data)->id;
+      dst_id_type = SILC_ID_SERVER;
+    }
+    break;
+  default:
+    break;
+  }
+
+  silc_server_packet_send_dest(server, sock, type, flags, dst_id,
+                              dst_id_type, data, data_len, force_send);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+   send the packet but creates the packet and fills the outgoing data
+   buffer and marks the packet ready to be sent to network. However, If 
+   argument force_send is TRUE the packet is sent immediately and not put 
+   to queue. Normal case is that the packet is not sent immediately. 
+   Destination information is sent as argument for this function. */
+
+void silc_server_packet_send_dest(SilcServer server,
+                                 SilcSocketConnection sock, 
+                                 SilcPacketType type, 
+                                 SilcPacketFlags flags,
+                                 void *dst_id,
+                                 SilcIdType dst_id_type,
+                                 unsigned char *data, 
+                                 unsigned int data_len,
+                                 int force_send)
+{
+  SilcPacketContext packetdata;
+  SilcCipher cipher = NULL;
+  SilcHmac hmac = NULL;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+  unsigned char *dst_id_data = NULL;
+  unsigned int dst_id_len = 0;
+
+  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+  /* Get data used in the packet sending, keys and stuff */
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    if (sock->user_data) {
+      cipher = ((SilcClientList *)sock->user_data)->send_key;
+      hmac = ((SilcClientList *)sock->user_data)->hmac;
+      if (hmac) {
+       mac_len = hmac->hash->hash->hash_len;
+       hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
+       hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
+      }
+    }
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    if (sock->user_data) {
+      cipher = ((SilcServerList *)sock->user_data)->send_key;
+      hmac = ((SilcServerList *)sock->user_data)->hmac;
+      if (hmac) {
+       mac_len = hmac->hash->hash->hash_len;
+       hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
+       hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
+      }
+    }
+    break;
+  default:
+    if (sock->user_data) {
+      /* We don't know what type of connection this is thus it must
+        be in authentication phase. */
+      cipher = ((SilcIDListUnknown *)sock->user_data)->send_key;
+      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
+      if (hmac) {
+       mac_len = hmac->hash->hash->hash_len;
+       hmac_key = ((SilcIDListUnknown *)sock->user_data)->hmac_key;
+       hmac_key_len = ((SilcIDListUnknown *)sock->user_data)->hmac_key_len;
+      }
+    }
+    break;
+  }
+
+  if (dst_id) {
+    dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+    dst_id_len = silc_id_get_len(dst_id_type);
+  }
+
+  /* Set the packet context pointers */
+  packetdata.type = type;
+  packetdata.flags = flags;
+  packetdata.src_id = silc_id_id2str(server->id, server->id_type);
+  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_type = server->id_type;
+  packetdata.dst_id = dst_id_data;
+  packetdata.dst_id_len = dst_id_len;
+  packetdata.dst_id_type = dst_id_type;
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+  packetdata.rng = server->rng;
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_server_packet_send_prepare(server, sock, 
+                                 SILC_PACKET_HEADER_LEN +
+                                 packetdata.src_id_len + 
+                                 packetdata.dst_id_len,
+                                 packetdata.padlen,
+                                 data_len);
+
+  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Put the data to the buffer */
+  if (data && data_len)
+    silc_buffer_put(sock->outbuf, data, data_len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Compute MAC of the packet */
+  if (hmac) {
+    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                           hmac_key, hmac_key_len, mac);
+    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+    memset(mac, 0, sizeof(mac));
+  }
+
+  /* Encrypt the packet */
+  if (cipher)
+    silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
+
+  /* Pull MAC into the visible data area */
+  if (hmac)
+    silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+  SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+
+  if (packetdata.src_id)
+    silc_free(packetdata.src_id);
+  if (packetdata.dst_id)
+    silc_free(packetdata.dst_id);
+}
+
+/* Forwards packet. Packets sent with this function will be marked as
+   forwarded (in the SILC header flags) so that the receiver knows that
+   we have forwarded the packet to it. Forwarded packets are handled
+   specially by the receiver as they are not destined to the receiver
+   originally. However, the receiver knows this because the forwarded
+   flag has been set (and the flag is authenticated). */
+
+void silc_server_packet_forward(SilcServer server,
+                               SilcSocketConnection sock,
+                               unsigned char *data, unsigned int data_len,
+                               int force_send)
+{
+  SilcCipher cipher = NULL;
+  SilcHmac hmac = NULL;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+
+  SILC_LOG_DEBUG(("Forwarding packet"));
+
+  /* Get data used in the packet sending, keys and stuff */
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    if (sock->user_data) {
+      cipher = ((SilcClientList *)sock->user_data)->send_key;
+      hmac = ((SilcClientList *)sock->user_data)->hmac;
+      if (hmac) {
+       mac_len = hmac->hash->hash->hash_len;
+       hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
+       hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
+      }
+    }
+    break;
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    if (sock->user_data) {
+      cipher = ((SilcServerList *)sock->user_data)->send_key;
+      hmac = ((SilcServerList *)sock->user_data)->hmac;
+      if (hmac) {
+       mac_len = hmac->hash->hash->hash_len;
+       hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
+       hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
+      }
+    }
+    break;
+  default:
+    /* We won't forward to unknown destination - keys must exist with
+       the destination before forwarding. */
+    return;
+  }
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_server_packet_send_prepare(server, sock, 0, 0, data_len);
+
+  /* Mungle the packet flags and add the FORWARDED flag */
+  if (data)
+    data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
+
+  /* Put the data to the buffer */
+  if (data && data_len)
+    silc_buffer_put(sock->outbuf, data, data_len);
+
+  /* Compute MAC of the packet */
+  if (hmac) {
+    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                           hmac_key, hmac_key_len, mac);
+    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+    memset(mac, 0, sizeof(mac));
+  }
+
+  /* Encrypt the packet */
+  if (cipher)
+    silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
+
+  /* Pull MAC into the visible data area */
+  if (hmac)
+    silc_buffer_pull_tail(sock->outbuf, mac_len);
+
+  SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* This routine is used by the server to send packets to channel. The 
+   packet sent with this function is distributed to all clients on
+   the channel. Usually this is used to send notify messages to the
+   channel, things like notify about new user joining to the channel. */
+
+void silc_server_packet_send_to_channel(SilcServer server,
+                                       SilcChannelList *channel,
+                                       unsigned char *data,
+                                       unsigned int data_len,
+                                       int force_send)
+{
+  int i;
+  SilcSocketConnection sock = NULL;
+  SilcPacketContext packetdata;
+  SilcClientList *client = NULL;
+  SilcServerList **routed = NULL;
+  unsigned int routed_count = 0;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+  SilcCipher cipher;
+  SilcHmac hmac;
+  SilcBuffer payload;
+
+  SILC_LOG_DEBUG(("Sending packet to channel"));
+
+  /* Generate IV */
+  for (i = 0; i < 16; i++)
+    channel->iv[i] = silc_rng_get_byte(server->rng);
+
+  /* Encode the channel payload */
+  payload = silc_channel_encode_payload(0, "", data_len, data, 
+                                       16, channel->iv, server->rng);
+  if (!payload)
+    return;
+  
+  /* Encrypt payload of the packet. This is encrypted with the 
+     channel key. */
+  channel->channel_key->cipher->encrypt(channel->channel_key->context,
+                                       payload->data, payload->data,
+                                       payload->len - 16, /* -IV_LEN */
+                                       channel->iv);
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_type = SILC_ID_SERVER;
+  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_type = SILC_ID_CHANNEL;
+  packetdata.rng = server->rng;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* If there are global users in the channel we will send the message
+     first to our router for further routing. */
+  if (server->server_type == SILC_SERVER && !server->standalone &&
+      channel->global_users) {
+    SilcServerList *router;
+
+    /* Get data used in packet header encryption, keys and stuff. */
+    router = server->id_entry->router;
+    sock = (SilcSocketConnection)router->connection;
+    cipher = router->send_key;
+    hmac = router->hmac;
+    mac_len = hmac->hash->hash->hash_len;
+    hmac_key = router->hmac_key;
+    hmac_key_len = router->hmac_key_len;
+    
+    SILC_LOG_DEBUG(("Sending packet to router for routing"));
+
+    packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
+      packetdata.src_id_len + packetdata.dst_id_len;
+
+    /* Prepare outgoing data buffer for packet sending */
+    silc_server_packet_send_prepare(server, sock, 
+                                   SILC_PACKET_HEADER_LEN +
+                                   packetdata.src_id_len + 
+                                   packetdata.dst_id_len,
+                                   packetdata.padlen,
+                                   payload->len);
+    packetdata.buffer = sock->outbuf;
+
+    /* Put the original packet into the buffer. */
+    silc_buffer_put(sock->outbuf, payload->data, payload->len);
+    
+    /* Create the outgoing packet */
+    silc_packet_assemble(&packetdata);
+    
+    /* Compute MAC of the packet. MAC is computed from the header,
+       padding and the relayed packet. */
+    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                           hmac_key, hmac_key_len, mac);
+    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+    memset(mac, 0, sizeof(mac));
+
+    /* Encrypt the header and padding of the packet. This is encrypted 
+       with normal session key shared with the client. */
+    silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                       packetdata.src_id_len + packetdata.dst_id_len +
+                       packetdata.padlen);
+    
+    /* Pull MAC into the visible data area */
+    silc_buffer_pull_tail(sock->outbuf, mac_len);
+    
+    SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+                    sock->outbuf->data, sock->outbuf->len);
+
+    /* Now actually send the packet */
+    silc_server_packet_send_real(server, sock, force_send);
+  }
+
+  /* Send the message to clients on the channel's client list. */
+  for (i = 0; i < channel->user_list_count; i++) {
+    client = channel->user_list[i].client;
+
+    /* If client has router set it is not locally connected client and
+       we will route the message to the router set in the client. */
+    if (client && client->router && server->server_type == SILC_ROUTER) {
+      int k;
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         continue;
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->router->connection;
+      cipher = client->router->send_key;
+      hmac = client->router->hmac;
+      mac_len = hmac->hash->hash->hash_len;
+      hmac_key = client->router->hmac_key;
+      hmac_key_len = client->router->hmac_key_len;
+      
+      packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
+       packetdata.src_id_len + packetdata.dst_id_len;
+
+      /* Prepare outgoing data buffer for packet sending */
+      silc_server_packet_send_prepare(server, sock, 
+                                     SILC_PACKET_HEADER_LEN +
+                                     packetdata.src_id_len + 
+                                     packetdata.dst_id_len,
+                                     packetdata.padlen,
+                                     payload->len);
+      packetdata.buffer = sock->outbuf;
+
+      /* Put the encrypted payload data into the buffer. */
+      silc_buffer_put(sock->outbuf, payload->data, payload->len);
+      
+      /* Create the outgoing packet */
+      silc_packet_assemble(&packetdata);
+      
+      /* Compute MAC of the packet. MAC is computed from the header,
+        padding and the relayed packet. */
+      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                             hmac_key, hmac_key_len, mac);
+      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+      memset(mac, 0, sizeof(mac));
+
+      /* Encrypt the header and padding of the packet. This is encrypted 
+        with normal session key shared with the client. */
+      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                         packetdata.src_id_len + packetdata.dst_id_len +
+                         packetdata.padlen);
+      
+      /* Pull MAC into the visible data area */
+      silc_buffer_pull_tail(sock->outbuf, mac_len);
+      
+      SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+                      sock->outbuf->data, sock->outbuf->len);
+
+      /* Now actually send the packet */
+      silc_server_packet_send_real(server, sock, force_send);
+
+      /* We want to make sure that the packet is routed to same router
+        only once. Mark this route as sent route. */
+      k = routed_count;
+      routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+      routed[k] = client->router;
+      routed_count++;
+
+      continue;
+    }
+
+    /* Send to locally connected client */
+    if (client) {
+
+      /* XXX Check client's mode on the channel. */
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->connection;
+      cipher = client->send_key;
+      hmac = client->hmac;
+      mac_len = hmac->hash->hash->hash_len;
+      hmac_key = client->hmac_key;
+      hmac_key_len = client->hmac_key_len;
+      
+      packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
+       packetdata.src_id_len + packetdata.dst_id_len;
+
+      /* Prepare outgoing data buffer for packet sending */
+      silc_server_packet_send_prepare(server, sock, 
+                                     SILC_PACKET_HEADER_LEN +
+                                     packetdata.src_id_len + 
+                                     packetdata.dst_id_len,
+                                     packetdata.padlen,
+                                     payload->len);
+      packetdata.buffer = sock->outbuf;
+
+      /* Put the encrypted payload data into the buffer. */
+      silc_buffer_put(sock->outbuf, payload->data, payload->len);
+      
+      /* Create the outgoing packet */
+      silc_packet_assemble(&packetdata);
+      
+      /* Compute MAC of the packet. MAC is computed from the header,
+        padding and the relayed packet. */
+      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                             hmac_key, hmac_key_len, mac);
+      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+      memset(mac, 0, sizeof(mac));
+
+      /* Encrypt the header and padding of the packet. This is encrypted 
+        with normal session key shared with the client. */
+      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                         packetdata.src_id_len + packetdata.dst_id_len +
+                         packetdata.padlen);
+      
+      /* Pull MAC into the visible data area */
+      silc_buffer_pull_tail(sock->outbuf, mac_len);
+      
+      SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+                      sock->outbuf->data, sock->outbuf->len);
+
+      /* Now actually send the packet */
+      silc_server_packet_send_real(server, sock, force_send);
+    }
+  }
+
+  if (routed_count)
+    silc_free(routed);
+  silc_free(packetdata.src_id);
+  silc_free(packetdata.dst_id);
+  silc_buffer_free(payload);
+}
+
+/* This routine is explicitly used to relay messages to some channel.
+   Packets sent with this function we have received earlier and are
+   totally encrypted. This just sends the packet to all clients on
+   the channel. If the sender of the packet is someone on the channel 
+   the message will not be sent to that client. The SILC Packet header
+   is encrypted with the session key shared between us and the client.
+   MAC is also computed before encrypting the header. Rest of the
+   packet will be untouched. */
+
+void silc_server_packet_relay_to_channel(SilcServer server,
+                                        SilcSocketConnection sender_sock,
+                                        SilcChannelList *channel,
+                                        void *sender, 
+                                        SilcIdType sender_type,
+                                        unsigned char *data,
+                                        unsigned int data_len,
+                                        int force_send)
+{
+  int i, found = FALSE;
+  SilcSocketConnection sock = NULL;
+  SilcPacketContext packetdata;
+  SilcClientList *client = NULL;
+  SilcServerList **routed = NULL;
+  unsigned int routed_count = 0;
+  unsigned char *hmac_key = NULL;
+  unsigned int hmac_key_len = 0;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+  SilcCipher cipher;
+  SilcHmac hmac;
+
+  SILC_LOG_DEBUG(("Relaying packet to channel"));
+
+  SILC_LOG_HEXDUMP(("XXX %d", data_len), data, data_len);
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+  packetdata.src_id = silc_id_id2str(sender, sender_type);
+  packetdata.src_id_len = silc_id_get_len(sender_type);
+  packetdata.src_id_type = sender_type;
+  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_type = SILC_ID_CHANNEL;
+  packetdata.rng = server->rng;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* If there are global users in the channel we will send the message
+     first to our router for further routing. */
+  if (server->server_type == SILC_SERVER && !server->standalone &&
+      channel->global_users) {
+    SilcServerList *router;
+
+    router = server->id_entry->router;
+
+    /* Check that the sender is not our router. */
+    if (sender_sock != (SilcSocketConnection)router->connection) {
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)router->connection;
+      cipher = router->send_key;
+      hmac = router->hmac;
+      mac_len = hmac->hash->hash->hash_len;
+      hmac_key = router->hmac_key;
+      hmac_key_len = router->hmac_key_len;
+      
+      SILC_LOG_DEBUG(("Sending packet to router for routing"));
+      
+      packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+       packetdata.src_id_len + packetdata.dst_id_len;
+      
+      /* Prepare outgoing data buffer for packet sending */
+      silc_server_packet_send_prepare(server, sock, 
+                                     SILC_PACKET_HEADER_LEN +
+                                     packetdata.src_id_len + 
+                                     packetdata.dst_id_len,
+                                     packetdata.padlen,
+                                     data_len);
+      packetdata.buffer = sock->outbuf;
+      
+      /* Put the original packet into the buffer. */
+      silc_buffer_put(sock->outbuf, data, data_len);
+      
+      /* Create the outgoing packet */
+      silc_packet_assemble(&packetdata);
+      
+      /* Compute MAC of the packet. MAC is computed from the header,
+        padding and the relayed packet. */
+      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                             hmac_key, hmac_key_len, mac);
+      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+      memset(mac, 0, sizeof(mac));
+      
+      /* Encrypt the header and padding of the packet. This is encrypted 
+        with normal session key shared with the client. */
+      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                         packetdata.src_id_len + packetdata.dst_id_len +
+                         packetdata.padlen);
+      
+      /* Pull MAC into the visible data area */
+      silc_buffer_pull_tail(sock->outbuf, mac_len);
+      
+      SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+                      sock->outbuf->data, sock->outbuf->len);
+      
+      /* Now actually send the packet */
+      silc_server_packet_send_real(server, sock, force_send);
+    }
+  }
+
+  /* Send the message to clients on the channel's client list. */
+  for (i = 0; i < channel->user_list_count; i++) {
+    client = channel->user_list[i].client;
+
+    if (client) {
+
+      /* If sender is one on the channel do not send it the packet. */
+      if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+       found = TRUE;
+       continue;
+      }
+
+      /* If the client has set router it means that it is not locally
+        connected client and we won't send message to those in this
+        function (they will be routed separately by the caller). */
+      if (server->server_type == SILC_ROUTER && client->router) {
+       int k;
+
+       /* Sender maybe server as well so we want to make sure that
+          we won't send the message to the server it came from. */
+       if (!found && !SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
+         found = TRUE;
+         continue;
+       }
+
+       /* Check if we have sent the packet to this route already */
+       for (k = 0; k < routed_count; k++)
+         if (routed[k] == client->router)
+           continue;
+       
+       /* Get data used in packet header encryption, keys and stuff. */
+       sock = (SilcSocketConnection)client->router->connection;
+       cipher = client->router->send_key;
+       hmac = client->router->hmac;
+       mac_len = hmac->hash->hash->hash_len;
+       hmac_key = client->router->hmac_key;
+       hmac_key_len = client->router->hmac_key_len;
+       
+       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+         packetdata.src_id_len + packetdata.dst_id_len;
+       
+       /* Prepare outgoing data buffer for packet sending */
+       silc_server_packet_send_prepare(server, sock, 
+                                       SILC_PACKET_HEADER_LEN +
+                                       packetdata.src_id_len + 
+                                       packetdata.dst_id_len,
+                                       packetdata.padlen,
+                                       data_len);
+       packetdata.buffer = sock->outbuf;
+       
+       /* Put the original packet into the buffer. */
+       silc_buffer_put(sock->outbuf, data, data_len);
+       
+       /* Create the outgoing packet */
+       silc_packet_assemble(&packetdata);
+       
+       /* Compute MAC of the packet. MAC is computed from the header,
+          padding and the relayed packet. */
+       silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                               hmac_key, hmac_key_len, mac);
+       silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+       memset(mac, 0, sizeof(mac));
+       
+       /* Encrypt the header and padding of the packet. This is encrypted 
+          with normal session key shared with the client. */
+       silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                           packetdata.src_id_len + packetdata.dst_id_len +
+                           packetdata.padlen);
+       
+       /* Pull MAC into the visible data area */
+       silc_buffer_pull_tail(sock->outbuf, mac_len);
+       
+       SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+                        sock->outbuf->data, sock->outbuf->len);
+       
+       /* Now actually send the packet */
+       silc_server_packet_send_real(server, sock, force_send);
+       
+       /* We want to make sure that the packet is routed to same router
+          only once. Mark this route as sent route. */
+       k = routed_count;
+       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+       routed[k] = client->router;
+       routed_count++;
+       
+       continue;
+      }
+      
+      /* XXX Check client's mode on the channel. */
+
+
+      /* Get data used in packet header encryption, keys and stuff. */
+      sock = (SilcSocketConnection)client->connection;
+      cipher = client->send_key;
+      hmac = client->hmac;
+      mac_len = hmac->hash->hash->hash_len;
+      hmac_key = client->hmac_key;
+      hmac_key_len = client->hmac_key_len;
+      
+      SILC_LOG_DEBUG(("Sending packet to client %s", 
+                     sock->hostname ? sock->hostname : sock->ip));
+
+      packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+       packetdata.src_id_len + packetdata.dst_id_len;
+
+      /* Prepare outgoing data buffer for packet sending */
+      silc_server_packet_send_prepare(server, sock, 
+                                     SILC_PACKET_HEADER_LEN +
+                                     packetdata.src_id_len + 
+                                     packetdata.dst_id_len,
+                                     packetdata.padlen,
+                                     data_len);
+      packetdata.buffer = sock->outbuf;
+
+      /* Put the original packet into the buffer. */
+      silc_buffer_put(sock->outbuf, data, data_len);
+      
+      /* Create the outgoing packet */
+      silc_packet_assemble(&packetdata);
+      
+      /* Compute MAC of the packet. MAC is computed from the header,
+        padding and the relayed packet. */
+      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
+                             hmac_key, hmac_key_len, mac);
+      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
+      memset(mac, 0, sizeof(mac));
+
+      /* Encrypt the header and padding of the packet. This is encrypted 
+        with normal session key shared with the client. */
+      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                         packetdata.src_id_len + packetdata.dst_id_len +
+                         packetdata.padlen);
+      
+      /* Pull MAC into the visible data area */
+      silc_buffer_pull_tail(sock->outbuf, mac_len);
+      
+      SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+                      sock->outbuf->data, sock->outbuf->len);
+
+      /* Now actually send the packet */
+      silc_server_packet_send_real(server, sock, force_send);
+    }
+  }
+
+  silc_free(packetdata.src_id);
+  silc_free(packetdata.dst_id);
+}
+
+/* Relays received command reply packet to the correct destination. The
+   destination must be one of our locally connected client or the packet
+   will be ignored. This is called when server has forwarded one of
+   client's command request to router and router has now replied to the 
+   command. */
+
+void silc_server_packet_relay_command_reply(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientList *client;
+  SilcClientID *id;
+  SilcSocketConnection dst_sock;
+  unsigned char mac[32];
+  unsigned int mac_len = 0;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Source must be server or router */
+  /* XXX: actually it must be only router */
+  if (packet->src_id_type != SILC_ID_SERVER &&
+      (sock->type != SILC_SOCKET_TYPE_SERVER ||
+       sock->type != SILC_SOCKET_TYPE_ROUTER))
+    goto out;
+
+  /* Destination must be client */
+  if (packet->dst_id_type != SILC_ID_CLIENT)
+    goto out;
+
+  /* Execute command reply locally for the command */
+  silc_server_command_reply_process(server, sock, buffer);
+
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+
+  /* Destination must be one of ours */
+  client = silc_idlist_find_client_by_id(server->local_list->clients, id);
+  if (!client) {
+    silc_free(id);
+    goto out;
+  }
+
+  /* Relay the packet to the client */
+  if (client->hmac)
+    mac_len = client->hmac->hash->hash->hash_len;
+
+  dst_sock = (SilcSocketConnection)client->connection;
+
+  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                  + packet->dst_id_len + packet->padlen);
+  silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+  silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+  
+  /* Compute new HMAC */
+  if (client->hmac) {
+    memset(mac, 0, sizeof(mac));
+    silc_hmac_make_with_key(client->hmac, 
+                           dst_sock->outbuf->data, 
+                           dst_sock->outbuf->len,
+                           client->hmac_key, 
+                           client->hmac_key_len, 
+                           mac);
+    silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
+    memset(mac, 0, sizeof(mac));
+  }
+    
+  /* Encrypt */
+  if (client && client->send_key)
+    silc_packet_encrypt(client->send_key, dst_sock->outbuf, buffer->len);
+    
+  if (client->hmac)
+    silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+    
+  /* Send the packet */
+  silc_server_packet_send_real(server, dst_sock, FALSE);
+
+  silc_free(id);
+
+ out:
+  silc_buffer_free(buffer);
+}
+
+/* Closes connection to socket connection */
+
+void silc_server_close_connection(SilcServer server,
+                                 SilcSocketConnection sock)
+{
+
+  SILC_LOG_DEBUG(("Closing connection %d", sock->sock));
+
+  /* We won't listen for this connection anymore */
+  silc_schedule_unset_listen_fd(sock->sock);
+
+  /* Unregister all tasks */
+  silc_task_unregister_by_fd(server->io_queue, sock->sock);
+  silc_task_unregister_by_fd(server->timeout_queue, sock->sock);
+
+  /* Close the actual connection */
+  silc_net_close_connection(sock->sock);
+  server->sockets[sock->sock] = NULL;
+  silc_socket_free(sock);
+}
+
+/* Sends disconnect message to remote connection and disconnects the 
+   connection. */
+
+void silc_server_disconnect_remote(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  const char *fmt, ...)
+{
+  va_list ap;
+  unsigned char buf[4096];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  va_end(ap);
+
+  SILC_LOG_DEBUG(("Disconnecting remote host"));
+
+  /* Notify remote end that the conversation is over. The notify message
+     is tried to be sent immediately. */
+  silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,  
+                         buf, strlen(buf), TRUE);
+
+  /* Mark the connection to be disconnected */
+  SILC_SET_DISCONNECTED(sock);
+  silc_server_close_connection(server, sock);
+}
+
+/* Free's user_data pointer from socket connection object. As this 
+   pointer maybe anything we wil switch here to find the corrent
+   data type and free it the way it needs to be free'd. */
+
+void silc_server_free_sock_user_data(SilcServer server, 
+                                    SilcSocketConnection sock)
+{
+  SILC_LOG_DEBUG(("Start"));
+
+#define LCC(x) server->local_list->client_cache[(x) - 32]
+#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    {
+      SilcClientList *user_data = (SilcClientList *)sock->user_data;
+
+      /* Remove client from all channels */
+      silc_server_remove_from_channels(server, sock, user_data);
+
+      /* Clear ID cache */
+      if (user_data->nickname && user_data->id)
+       silc_idcache_del_by_id(LCC(user_data->nickname[0]),
+                              LCCC(user_data->nickname[0]),
+                              SILC_ID_CLIENT, user_data->id);
+
+      /* Free the client entry and everything in it */
+      /* XXX must take some info to history before freeing */
+      silc_idlist_del_client(&server->local_list->clients, user_data);
+      break;
+    }
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    {
+
+      break;
+    }
+    break;
+  default:
+    {
+      SilcIDListUnknown *user_data = (SilcIDListUnknown *)sock->user_data;
+
+      if (user_data->send_key)
+       silc_cipher_free(user_data->send_key);
+      if (user_data->receive_key)
+       silc_cipher_free(user_data->receive_key);
+      if (user_data->pkcs)
+       silc_pkcs_free(user_data->pkcs);
+      if (user_data->hmac) {
+       silc_hmac_free(user_data->hmac);
+       memset(user_data->hmac_key, 0, user_data->hmac_key_len);
+       silc_free(user_data->hmac_key);
+      }
+      silc_free(user_data);
+      break;
+    }
+  }
+
+  sock->user_data = NULL;
+#undef LCC
+#undef LCCC
+}
+
+/* Removes client from all channels it has joined. This is used when
+   client connection is disconnected. If the client on a channel
+   is last, the channel is removed as well. */
+
+void silc_server_remove_from_channels(SilcServer server, 
+                                     SilcSocketConnection sock,
+                                     SilcClientList *client)
+{
+  int i, k;
+  SilcChannelList *channel;
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+  /* Remove the client from all channels. The client is removed from
+     the channels' user list. */
+  for (i = 0; i < client->channel_count; i++) {
+    channel = client->channel[i];
+    if (!channel)
+      continue;
+
+    /* Remove from channel */
+    for (k = 0; k < channel->user_list_count; k++) {
+      if (channel->user_list[k].client == client) {
+
+       /* If this client is last one on the channel the channel
+          is removed all together. */
+       if (channel->user_list_count == 1) {
+         silc_idcache_del_by_id(LCC(channel->channel_name[0]),
+                                LCCC(channel->channel_name[0]),
+                                SILC_ID_CHANNEL, channel->id);
+         silc_idlist_del_channel(&server->local_list->channels, channel);
+         break;
+       }
+
+       channel->user_list[k].client = NULL;
+       channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+
+       /* XXX */
+       /* Send notify to channel about client leaving SILC and thus
+          the entire channel. */
+       silc_server_send_notify_to_channel(server, channel,
+                                          "%s has left channel %s",
+                                          client->nickname,
+                                          channel->channel_name);
+      }
+    }
+  }
+
+  if (client->channel_count)
+    silc_free(client->channel);
+  client->channel = NULL;
+#undef LCC
+#undef LCCC
+}
+
+/* Timeout callback. This is called if connection is idle or for some
+   other reason is not responding within some period of time. This 
+   disconnects the remote end. */
+
+SILC_TASK_CALLBACK(silc_server_timeout_remote)
+{
+  SilcServer server = (SilcServer)context;
+  SilcSocketConnection sock = server->sockets[fd];
+
+  silc_server_disconnect_remote(server, sock, 
+                               "Server closed connection: "
+                               "Connection timeout");
+}
+
+/* Internal routine used to send (relay, route) private messages to some
+   destination. This is used to by normal server to send the message to
+   its primary route and router uses this to send it to any route it
+   wants. If the private message key does not exist then the message
+   is re-encrypted, otherwise we just pass it along. */
+static void 
+silc_server_private_message_send_internal(SilcServer server,
+                                         SilcSocketConnection dst_sock,
+                                         SilcServerList *router,
+                                         SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+
+  /* Send and re-encrypt if private messge key does not exist */
+  if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+    unsigned char mac[32];
+    unsigned int mac_len = 0;
+    
+    if (router->hmac)
+      mac_len = router->hmac->hash->hash->hash_len;
+    
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    
+    /* Compute new HMAC */
+    if (router->hmac) {
+      mac_len = router->hmac->hash->hash->hash_len;
+      memset(mac, 0, sizeof(mac));
+      silc_hmac_make_with_key(router->hmac, 
+                             dst_sock->outbuf->data, 
+                             dst_sock->outbuf->len,
+                             router->hmac_key, 
+                             router->hmac_key_len, 
+                             mac);
+      silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
+      memset(mac, 0, sizeof(mac));
+    }
+    
+    silc_packet_encrypt(router->send_key, dst_sock->outbuf, buffer->len);
+    
+    if (router->hmac)
+      silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+    
+    /* Send the packet */
+    silc_server_packet_send_real(server, dst_sock, FALSE);
+
+  } else {
+    /* Key exist so just send it */
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    silc_server_packet_send_real(server, dst_sock, FALSE);
+  }
+}
+
+/* Internal routine to send the received private message packet to
+   our locally connected client. */
+static void
+silc_server_private_message_send_local(SilcServer server,
+                                      SilcSocketConnection dst_sock,
+                                      SilcClientList *client,
+                                      SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+
+  /* Re-encrypt packet if needed */
+  if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+    unsigned char mac[32];
+    unsigned int mac_len = 0;
+
+    if (client->hmac)
+      mac_len = client->hmac->hash->hash->hash_len;
+    
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    
+    /* Compute new HMAC */
+    if (client->hmac) {
+      memset(mac, 0, sizeof(mac));
+      silc_hmac_make_with_key(client->hmac, 
+                             dst_sock->outbuf->data, 
+                             dst_sock->outbuf->len,
+                             client->hmac_key, 
+                             client->hmac_key_len, 
+                             mac);
+      silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
+      memset(mac, 0, sizeof(mac));
+    }
+    
+    /* Encrypt */
+    if (client && client->send_key)
+      silc_packet_encrypt(client->send_key, dst_sock->outbuf, 
+                         buffer->len);
+    
+    if (client->hmac)
+      silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+    
+    /* Send the packet */
+    silc_server_packet_send_real(server, dst_sock, FALSE);
+  } else {
+    /* Key exist so just send it */
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+                    + packet->dst_id_len + packet->padlen);
+    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+    silc_server_packet_send_real(server, dst_sock, FALSE);
+  }
+}
+
+/* Received private message. This resolves the destination of the message 
+   and sends the packet. This is used by both server and router.  If the
+   destination is our locally connected client this sends the packet to
+   the client. This may also send the message for further routing if
+   the destination is not in our server (or router). */
+
+void silc_server_private_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientID *id;
+  SilcServerList *router;
+  SilcSocketConnection dst_sock;
+  SilcClientList *client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!packet->dst_id) {
+    SILC_LOG_DEBUG(("Bad Client ID in private message packet"));
+    goto err;
+  }
+
+  /* Decode destination Client ID */
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+  if (!id) {
+    SILC_LOG_DEBUG(("Could not decode destination Client ID"));
+    goto err;
+  }
+
+  /* If the destination belongs to our server we don't have to route
+     the message anywhere but to send it to the local destination. */
+  /* XXX: Should use local cache to search but the current idcache system
+     is so sucky that it cannot be used... it MUST be rewritten! Using
+     this search is probably faster than if we'd use here the current
+     idcache system. */
+  client =  silc_idlist_find_client_by_id(server->local_list->clients, id);
+  if (client) {
+    /* It exists, now deliver the message to the destination */
+    dst_sock = (SilcSocketConnection)client->connection;
+
+    /* If we are router and the client has router then the client is in
+       our cell but not directly connected to us. */
+    if (server->server_type == SILC_ROUTER && client->router) {
+      silc_server_private_message_send_internal(server, dst_sock,
+                                               client->router, packet);
+      goto out;
+    }
+
+    /* Seems that client really is directly connected to us */
+    silc_server_private_message_send_local(server, dst_sock, client, packet);
+    goto out;
+  }
+
+  /* Destination belongs to someone not in this server. If we are normal
+     server our action is to send the packet to our router. */
+  if (server->server_type == SILC_SERVER && !server->standalone) {
+    router = server->id_entry->router;
+    dst_sock = (SilcSocketConnection)router->connection;
+
+    /* Send to primary route */
+    silc_server_private_message_send_internal(server, dst_sock, router,
+                                             packet);
+    goto out;
+  }
+
+  /* We are router and we will perform route lookup for the destination 
+     and send the message to the correct route. */
+  if (server->server_type == SILC_ROUTER && !server->standalone) {
+
+    /* If we don't have specific route for the destination we will send
+       it to our primary route (default route). */
+    router = silc_server_route_check(id->ip.s_addr, server->id->port);
+    if (router) {
+      dst_sock = (SilcSocketConnection)router->connection;
+    } else {
+      router = server->id_entry->router;
+      dst_sock = (SilcSocketConnection)router->connection;
+    }
+
+    /* Send packet */
+    silc_server_private_message_send_internal(server, dst_sock, 
+                                             router, packet);
+    goto out;
+  }
+
+ err:
+  silc_server_send_error(server, sock, 
+                        "No such nickname: Private message not sent");
+ out:
+  silc_buffer_free(buffer);
+}
+
+SilcChannelList *silc_find_channel(SilcServer server, SilcChannelID *id)
+{
+  int i;
+  SilcIDCache *id_cache;
+
+#define LCC(x) server->local_list->channel_cache[(x)]
+#define LCCC(x) server->local_list->channel_cache_count[(x)]
+
+  for (i = 0; i < 96; i++) {
+    if (LCC(i) == NULL)
+      continue;
+    if (silc_idcache_find_by_id(LCC(i), LCCC(i), (void *)id, 
+                               SILC_ID_CHANNEL, &id_cache))
+      return (SilcChannelList *)id_cache->context;
+  }
+  
+  return NULL;
+#undef LCC
+#undef LCCC
+}
+
+/* Process received channel message. */
+
+void silc_server_channel_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcChannelList *channel = NULL;
+  SilcChannelID *id = NULL;
+  SilcClientID *sender;
+  SilcBuffer buffer = packet->buffer;
+
+  SILC_LOG_DEBUG(("Processing channel message"));
+  
+  /* Check MAC */
+  if (!silc_server_packet_check_mac(server, sock, buffer))
+    goto out;
+
+  /* Sanity checks */
+  if (packet->dst_id_type != SILC_ID_CHANNEL) {
+    SILC_LOG_ERROR(("Received bad message for channel, dropped"));
+    SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
+    goto out;
+  }
+
+  /* Send to local clients */
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+  channel = silc_find_channel(server, id);
+  if (!channel) {
+    SILC_LOG_DEBUG(("Could not find channel"));
+    goto out;
+  }
+
+  /* Distribute the packet to our local clients. This will send the
+     packet for further routing as well, if needed. */
+  sender = silc_id_str2id(packet->src_id, packet->src_id_type);
+  silc_server_packet_relay_to_channel(server, sock, channel, sender,
+                                     packet->src_id_type,
+                                     packet->buffer->data,
+                                     packet->buffer->len, FALSE);
+
+ out:
+  silc_buffer_free(buffer);
+}
+
+/* Received channel key packet. We distribute the key to all of our locally
+   connected clients on the channel. Router ignores the packet. */
+
+void silc_server_channel_key(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcChannelKeyPayload payload = NULL;
+  SilcChannelID *id = NULL;
+  SilcChannelList *channel;
+  SilcClientList *client;
+  unsigned char *key;
+  unsigned int key_len;
+  char *cipher;
+  int i;
+
+  if (server->server_type == SILC_ROUTER)
+    goto out;
+
+  if (packet->src_id_type != SILC_ID_SERVER &&
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
+    goto out;
+
+  /* Decode channel key payload */
+  payload = silc_channel_key_parse_payload(buffer);
+  if (!payload) {
+    SILC_LOG_ERROR(("Bad channel key payload, dropped"));
+    SILC_LOG_DEBUG(("Bad channel key payload, dropped"));
+  }
+
+  /* Get channel ID */
+  id = silc_id_str2id(silc_channel_key_get_id(payload, NULL), SILC_ID_CHANNEL);
+  if (!id)
+    goto out;
+
+  /* Get the channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
+  if (!channel) {
+    SILC_LOG_ERROR(("Received key for non-existent channel"));
+    SILC_LOG_DEBUG(("Received key for non-existent channel"));
+    goto out;
+  }
+
+  /* Save the key for us as well */
+  key = silc_channel_key_get_key(payload, &key_len);
+  if (!key)
+    goto out;
+  cipher = silc_channel_key_get_cipher(payload, NULL);;
+  if (!cipher)
+    goto out;
+  channel->key_len = key_len;
+  channel->key = silc_calloc(key_len, sizeof(unsigned char));
+  memcpy(channel->key, key, key_len);
+  silc_cipher_alloc(cipher, &channel->channel_key);
+  channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                       key, key_len);
+
+  /* Distribute the key to all clients on the channel */
+  for (i = 0; i < channel->user_list_count; i++) {
+    client = channel->user_list[i].client;
+
+    if (client)
+      silc_server_packet_send_dest(server, client->connection,
+                                  SILC_PACKET_CHANNEL_KEY, 0,
+                                  client->id, SILC_ID_CLIENT,
+                                  buffer->data, buffer->len, FALSE);
+  }
+
+ out:
+  if (id)
+    silc_free(id);
+  if (payload)
+    silc_channel_key_free_payload(payload);
+  silc_buffer_free(buffer);
+}
+
+/* Sends error message. Error messages may or may not have any 
+   implications. */
+
+void silc_server_send_error(SilcServer server,
+                           SilcSocketConnection sock,
+                           const char *fmt, ...)
+{
+  va_list ap;
+  unsigned char buf[4096];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  va_end(ap);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, 
+                         buf, strlen(buf), FALSE);
+}
+
+/* Sends notify message */
+
+void silc_server_send_notify(SilcServer server,
+                            SilcSocketConnection sock,
+                            const char *fmt, ...)
+{
+  va_list ap;
+  unsigned char buf[4096];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  va_end(ap);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
+                         buf, strlen(buf), FALSE);
+}
+
+/* Sends notify message to a channel. The notify message sent is 
+   distributed to all clients on the channel. */
+
+void silc_server_send_notify_to_channel(SilcServer server,
+                                       SilcChannelList *channel,
+                                       const char *fmt, ...)
+{
+  va_list ap;
+  unsigned char buf[4096];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  va_end(ap);
+
+  silc_server_packet_send_to_channel(server, channel, buf, 
+                                    strlen(buf), FALSE);
+}
+
+/* Sends New ID Payload to remote end. The packet is used to distribute
+   information about new registered clients, servers, channel etc. usually
+   to routers so that they can keep these information up to date. 
+   If the argument `broadcast' is TRUE then the packet is sent as
+   broadcast packet. */
+
+void silc_server_send_new_id(SilcServer server,
+                            SilcSocketConnection sock,
+                            int broadcast,
+                            void *id, SilcIdType id_type, 
+                            unsigned int id_len)
+{
+  SilcBuffer packet;
+  unsigned char *id_string;
+
+  id_string = silc_id_id2str(id, id_type);
+  if (!id_string)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + id_len);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(id_type),
+                    SILC_STR_UI_SHORT(id_len),
+                    SILC_STR_UI_XNSTRING(id_string, id_len),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+  silc_free(id_string);
+  silc_buffer_free(packet);
+}
+
+/* Sends Replace ID payload to remote end. This is used to replace old
+   ID with new ID sent in the packet.  This is called for example when
+   user changes nickname and we create new ID for the user.  If the 
+   argument `broadcast' is TRUE then the packet is sent as
+   broadcast packet. */
+/* XXX It would be expected that the new id is same type as the old
+   ID. :) */
+
+void silc_server_send_replace_id(SilcServer server,
+                                SilcSocketConnection sock,
+                                int broadcast,
+                                void *old_id, SilcIdType old_id_type,
+                                unsigned int old_id_len,
+                                void *new_id, SilcIdType new_id_type,
+                                unsigned int new_id_len)
+{
+  SilcBuffer packet;
+  unsigned char *oid;
+  unsigned char *nid;
+
+  oid = silc_id_id2str(old_id, old_id_type);
+  if (!oid)
+    return;
+
+  nid = silc_id_id2str(new_id, new_id_type);
+  if (!nid)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(old_id_type),
+                    SILC_STR_UI_SHORT(old_id_len),
+                    SILC_STR_UI_XNSTRING(oid, old_id_len),
+                    SILC_STR_UI_SHORT(new_id_type),
+                    SILC_STR_UI_SHORT(new_id_len),
+                    SILC_STR_UI_XNSTRING(nid, new_id_len),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+  silc_free(oid);
+  silc_free(nid);
+  silc_buffer_free(packet);
+}
+
+/* Creates new channel. */
+
+SilcChannelList *silc_server_new_channel(SilcServer server, 
+                                        SilcServerID *router_id,
+                                        char *cipher, char *channel_name)
+{
+  int i, channel_len;
+  SilcChannelID *channel_id;
+  SilcChannelList *entry;
+  SilcCipher key;
+  unsigned char channel_key[32], *id_string;
+  SilcBuffer packet;
+
+  SILC_LOG_DEBUG(("Creating new channel"));
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+  /* Create channel key */
+  for (i = 0; i < 32; i++)
+    channel_key[i] = silc_rng_get_byte(server->rng);
+
+  if (!cipher)
+    cipher = "twofish";
+
+  /* Allocate keys */
+  silc_cipher_alloc(cipher, &key);
+  key->cipher->set_key(key->context, channel_key, 16);
+
+  /* Create the channel */
+  silc_id_create_channel_id(router_id, server->rng, &channel_id);
+  silc_idlist_add_channel(&server->local_list->channels, channel_name, 
+                         SILC_CHANNEL_MODE_NONE, channel_id, NULL, /*XXX*/
+                         key, &entry);
+  LCCC(channel_name[0]) = silc_idcache_add(&LCC(channel_name[0]), 
+                                          LCCC(channel_name[0]),
+                                          channel_name, SILC_ID_CHANNEL, 
+                                          channel_id, (void *)entry);
+  entry->key = silc_calloc(16, sizeof(*entry->key));
+  entry->key_len = 16;
+  memcpy(entry->key, channel_key, 16);
+  memset(channel_key, 0, sizeof(channel_key));
+
+  /* Notify other routers about the new channel. We send the packet
+     to our primary route. */
+  if (server->standalone == FALSE) {
+    channel_len = strlen(channel_name);
+    id_string = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+    packet = silc_buffer_alloc(2 + SILC_ID_CHANNEL_LEN);
+
+    silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+    silc_buffer_format(packet,
+                      SILC_STR_UI_SHORT(channel_len),
+                      SILC_STR_UI_XNSTRING(channel_name, channel_len),
+                      SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+                      SILC_STR_UI_XNSTRING(id_string, SILC_ID_CHANNEL_LEN),
+                      SILC_STR_END);
+
+    /* Send the packet to our router. */
+    silc_server_packet_send(server, (SilcSocketConnection) 
+                           server->id_entry->router->connection,
+                           SILC_PACKET_NEW_CHANNEL_USER, 0, 
+                           packet->data, packet->len, TRUE);
+    
+    silc_free(id_string);
+    silc_buffer_free(packet);
+  }
+
+#undef LCC
+#undef LCCC
+  return entry;
+}
+
+/* Create new client. This processes incoming NEW_CLIENT packet and creates
+   Client ID for the client and adds it to lists and cache. */
+
+SilcClientList *silc_server_new_client(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientList *id_entry;
+  char *username = NULL, *realname = NULL, *id_string;
+  SilcBuffer reply;
+
+  SILC_LOG_DEBUG(("Creating new client"));
+
+  if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+    return NULL;
+
+#define LCC(x) server->local_list->client_cache[(x) - 32]
+#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_STRING_ALLOC(&username),
+                      SILC_STR_UI16_STRING_ALLOC(&realname),
+                      SILC_STR_END);
+
+  /* Set the pointers to the client list and create new client ID */
+  id_entry = (SilcClientList *)sock->user_data;
+  id_entry->nickname = strdup(username);
+  id_entry->username = username;
+  id_entry->userinfo = realname;
+  silc_id_create_client_id(server->id, server->rng, server->md5hash,
+                          username, &id_entry->id);
+
+  /* Add to client cache */
+  LCCC(username[0]) = silc_idcache_add(&LCC(username[0]), 
+                                      LCCC(username[0]),
+                                      username, SILC_ID_CLIENT, 
+                                      id_entry->id, (void *)id_entry);
+
+  /* Notify our router about new client on the SILC network */
+  if (!server->standalone)
+    silc_server_send_new_id(server, (SilcSocketConnection) 
+                           server->id_entry->router->connection, 
+                           server->server_type == SILC_SERVER ? TRUE : FALSE,
+                           id_entry->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+  
+  /* Send the new client ID to the client. */
+  id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
+  reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
+  silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
+  silc_buffer_format(reply,
+                    SILC_STR_UI_SHORT(SILC_ID_CLIENT),
+                    SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+                    SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+                    SILC_STR_END);
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0, 
+                         reply->data, reply->len, FALSE);
+  silc_free(id_string);
+  silc_buffer_free(reply);
+  
+  /* Send some nice info to the client */
+  silc_server_send_notify(server, sock, 
+                         "Welcome to the SILC Network %s@%s",
+                         username, 
+                         sock->hostname ? sock->hostname : sock->ip);
+  silc_server_send_notify(server, sock,
+                         "Your host is %s, running version %s",
+                         server->config->server_info->server_name,
+                         server_version);
+  silc_server_send_notify(server, sock, 
+                         "Your connection is secured with %s cipher, "
+                         "key length %d bits",
+                         id_entry->send_key->cipher->name,
+                         id_entry->send_key->cipher->key_len);
+  silc_server_send_notify(server, sock, 
+                         "Your current nickname is %s",
+                         id_entry->nickname);
+
+  /* XXX Send motd */
+
+#undef LCC
+#undef LCCC
+  return id_entry;
+}
+
+/* Create new server. This processes incoming NEW_SERVER packet and
+   saves the received Server ID. The server is our locally connected
+   server thus we save all the information and save it to local list. 
+   This funtion can be used by both normal server and router server.
+   If normal server uses this it means that its router has connected
+   to the server.  If router uses this it means that one of the cell's
+   servers is connected to the router. */
+
+SilcServerList *silc_server_new_server(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcServerList *id_entry;
+  unsigned char *server_name, *id_string;
+
+  SILC_LOG_DEBUG(("Creating new server"));
+
+  if (sock->type != SILC_SOCKET_TYPE_SERVER &&
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
+    return NULL;
+
+#define LSC(x) server->local_list->server_cache[(x) - 32]
+#define LSCC(x) server->local_list->server_cache_count[(x) - 32]
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_STRING_ALLOC(&id_string),
+                      SILC_STR_UI16_STRING_ALLOC(&server_name),
+                      SILC_STR_END);
+
+  /* Save ID and name */
+  id_entry = (SilcServerList *)sock->user_data;
+  id_entry->id = silc_id_str2id(id_string, SILC_ID_SERVER);
+  id_entry->server_name = server_name;
+  
+  /* Add to server cache */
+  LSCC(server_name[0]) = 
+    silc_idcache_add(&LSC(server_name[0]), 
+                    LSCC(server_name[0]),
+                    server_name, SILC_ID_SERVER, 
+                    id_entry->id, (void *)id_entry);
+
+  /* Distribute the information about new server in the SILC network
+     to our router. If we are normal server we won't send anything
+     since this connection must be our router connection. */
+  if (server->server_type == SILC_ROUTER && !server->standalone)
+    silc_server_send_new_id(server, server->id_entry->router->connection,
+                           TRUE, id_entry->id, SILC_ID_SERVER, 
+                           SILC_ID_SERVER_LEN);
+
+  silc_free(id_string);
+
+#undef LSC
+#undef LSCC
+  return id_entry;
+}
+
+/* Processes incoming New ID Payload. New ID Payload is used to distribute
+   information about newly registered clients, servers and created 
+   channels. */
+
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+                       SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcIdType id_type;
+  unsigned char *id_string;
+  void *id;
+
+  SILC_LOG_DEBUG(("Processing new ID"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      server->server_type == SILC_SERVER)
+    return;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&id_type),
+                      SILC_STR_UI16_STRING_ALLOC(&id_string),
+                      SILC_STR_END);
+
+  /* Normal server cannot have other normal server connections */
+  if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
+    goto out;
+
+  id = silc_id_str2id(id_string, id_type);
+  if (!id)
+    goto out;
+
+  /* XXX Do check whether the packet is coming outside the cell or
+     from someone inside the cell.  If outside use global lists otherwise
+     local lists. */
+  /* XXX If using local list set the idlist->connection to the sender's
+     socket connection as it is used in packet sending */
+
+  switch(id_type) {
+  case SILC_ID_CLIENT:
+    {
+      SilcClientList *idlist;
+
+      /* Add the client to our local list. We are router and we keep
+        cell specific local database of all clients in the cell. */
+      silc_idlist_add_client(&server->local_list->clients, NULL, NULL, NULL,
+                            id, sock->user_data, NULL, NULL, 
+                            NULL, NULL, &idlist);
+      idlist->connection = sock;
+    }
+    break;
+
+  case SILC_ID_SERVER:
+    {
+      SilcServerList *idlist;
+
+      /* Add the server to our local list. We are router and we keep
+        cell specific local database of all servers in the cell. */
+      silc_idlist_add_server(&server->local_list->servers, NULL, 0,
+                            id, server->id_entry, NULL, NULL, 
+                          NULL, NULL, &idlist);
+      idlist->connection = sock;
+    }
+    break;
+
+  case SILC_ID_CHANNEL:
+    /* Add the channel to our local list. We are router and we keep
+       cell specific local database of all channels in the cell. */
+    silc_idlist_add_channel(&server->local_list->channels, NULL, 0,
+                           id, server->id_entry, NULL, NULL);
+    break;
+
+  default:
+    goto out;
+    break;
+  }
+
+ out:
+  silc_free(id_string);
+}
diff --git a/apps/silcd/server.h b/apps/silcd/server.h
new file mode 100644 (file)
index 0000000..ebe661c
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+
+  server.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_H
+#define SERVER_H
+
+/* Forward declaration for SILC Server object. The actual object is
+   defined in internal header file for server routines. I want to keep
+   the object private hence this declaration. */
+typedef struct SilcServerObjectStruct *SilcServer;
+
+#define SILC_SERVER_MAX_CONNECTIONS 10000
+
+/* General definitions */
+
+#define SILC_SERVER 0
+#define SILC_ROUTER 1
+
+/* Prototypes */
+int silc_server_alloc(SilcServer *new_server);
+void silc_server_free(SilcServer server);
+int silc_server_init(SilcServer server);
+void silc_server_run(SilcServer server);
+void silc_server_stop(SilcServer server);
+void silc_server_packet_send(SilcServer server,
+                            SilcSocketConnection sock, 
+                            SilcPacketType type, 
+                            SilcPacketFlags flags,
+                            unsigned char *data, 
+                            unsigned int data_len,
+                            int force_send);
+void silc_server_packet_send_dest(SilcServer server,
+                                 SilcSocketConnection sock, 
+                                 SilcPacketType type, 
+                                 SilcPacketFlags flags,
+                                 void *dst_id,
+                                 SilcIdType dst_id_type,
+                                 unsigned char *data, 
+                                 unsigned int data_len,
+                                 int force_send);
+void silc_server_packet_forward(SilcServer server,
+                               SilcSocketConnection sock,
+                               unsigned char *data, unsigned int data_len,
+                               int force_send);
+void silc_server_packet_send_to_channel(SilcServer server,
+                                       SilcChannelList *channel,
+                                       unsigned char *data,
+                                       unsigned int data_len,
+                                       int force_send);
+void silc_server_packet_relay_to_channel(SilcServer server,
+                                        SilcSocketConnection sender_sock,
+                                        SilcChannelList *channel,
+                                        void *sender, 
+                                        SilcIdType sender_type,
+                                        unsigned char *data,
+                                        unsigned int data_len,
+                                        int force_send);
+void silc_server_packet_relay_command_reply(SilcServer server,
+                                           SilcSocketConnection sock,
+                                           SilcPacketContext *packet);
+void silc_server_close_connection(SilcServer server,
+                                 SilcSocketConnection sock);
+void silc_server_free_sock_user_data(SilcServer server, 
+                                    SilcSocketConnection sock);
+void silc_server_remove_from_channels(SilcServer server, 
+                                     SilcSocketConnection sock,
+                                     SilcClientList *client);
+void silc_server_disconnect_remote(SilcServer server,
+                                  SilcSocketConnection sock,
+                                  const char *fmt, ...);
+void silc_server_private_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet);
+void silc_server_channel_message(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet);
+void silc_server_channel_key(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet);
+void silc_server_send_error(SilcServer server,
+                           SilcSocketConnection sock,
+                           const char *fmt, ...);
+void silc_server_send_notify(SilcServer server,
+                            SilcSocketConnection sock,
+                            const char *fmt, ...);
+void silc_server_send_notify_to_channel(SilcServer server,
+                                       SilcChannelList *channel,
+                                       const char *fmt, ...);
+void silc_server_send_new_id(SilcServer server,
+                            SilcSocketConnection sock,
+                            int broadcast,
+                            void *id, SilcIdType id_type, 
+                            unsigned int id_len);
+void silc_server_send_replace_id(SilcServer server,
+                                SilcSocketConnection sock,
+                                int broadcast,
+                                void *old_id, SilcIdType old_id_type,
+                                unsigned int old_id_len,
+                                void *new_id, SilcIdType new_id_type,
+                                unsigned int new_id_len);
+SilcChannelList *silc_server_new_channel(SilcServer server, 
+                                        SilcServerID *router_id,
+                                        char *cipher, char *channel_name);
+SilcClientList *silc_server_new_client(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet);
+SilcServerList *silc_server_new_server(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet);
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+                       SilcPacketContext *packet);
+
+#endif
diff --git a/apps/silcd/server_internal.h b/apps/silcd/server_internal.h
new file mode 100644 (file)
index 0000000..3ed7cbe
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+
+  server_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERVER_INTERNAL_H
+#define SERVER_INTERNAL_H
+
+/* Server statistics structure. This holds various statistics about
+   various things. */
+/* XXX TODO */
+typedef struct {
+
+} SilcServerStatistics;
+
+/* 
+   SILC Server Object.
+
+*/
+typedef struct SilcServerObjectStruct {
+  char *server_name;
+  int server_type;
+  int sock;
+  int standalone;
+  int listenning;
+  SilcServerID *id;
+  SilcIdType id_type;
+  SilcServerList *id_entry;
+
+  /* SILC server task queues */
+  SilcTaskQueue io_queue;
+  SilcTaskQueue timeout_queue;
+  SilcTaskQueue generic_queue;
+
+  /* ID lists. */
+  SilcIDList local_list;
+  SilcIDList global_list;
+
+  /* Table of connected sockets */
+  SilcSocketConnection *sockets;
+
+  /* Server keys */
+  SilcCipher send_key;
+  SilcCipher receive_key;
+  SilcCipher none_cipher;
+
+  /* Server public key */
+  SilcPKCS public_key;
+
+  /* Hash objects for general hashing */
+  SilcHash md5hash;
+  SilcHash sha1hash;
+
+  /* HMAC objects for MAC's. */
+  SilcHmac md5hmac;
+  SilcHmac sha1hmac;
+
+  /* Configuration object */
+  SilcConfigServer config;
+
+  /* Random pool */
+  SilcRng rng;
+
+  /* Server statistics */
+  SilcServerStatistics stats;
+
+#ifdef SILC_SIM
+  /* SIM (SILC Module) table */
+  SilcSimContext **sim;
+  unsigned int sim_count;
+#endif
+} SilcServerObject;
+
+/* Macros */
+
+/* Registers generic task for file descriptor for reading from network and
+   writing to network. As being generic task the actual task is allocated 
+   only once and after that the same task applies to all registered fd's. */
+#define SILC_REGISTER_CONNECTION_FOR_IO(fd)                            \
+do {                                                                   \
+  SilcTask tmptask = silc_task_register(server->generic_queue, (fd),   \
+                                       silc_server_packet_process,     \
+                                       context, 0, 0,                  \
+                                       SILC_TASK_GENERIC,              \
+                                       SILC_TASK_PRI_NORMAL);          \
+  silc_task_set_iotype(tmptask, SILC_TASK_WRITE);                      \
+} while(0)
+
+#define SILC_SET_CONNECTION_FOR_INPUT(fd)                              \
+do {                                                                   \
+  silc_schedule_set_listen_fd((fd), (1L << SILC_TASK_READ));            \
+} while(0)
+     
+#define SILC_SET_CONNECTION_FOR_OUTPUT(fd)                             \
+do {                                                                   \
+  silc_schedule_set_listen_fd((fd), ((1L << SILC_TASK_READ) |           \
+                                    (1L << SILC_TASK_WRITE)));         \
+} while(0)
+
+/* Prototypes */
+
+#endif
diff --git a/apps/silcd/server_version.c b/apps/silcd/server_version.c
new file mode 100644 (file)
index 0000000..aa7099d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+
+  server_version.c
+  
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+
+const char server_version[] = "27062000";
diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c
new file mode 100644 (file)
index 0000000..326c133
--- /dev/null
@@ -0,0 +1,1446 @@
+/*
+
+  serverconfig.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/*  XXX
+   All possible configuration sections for SILC server. 
+
+   <Cipher>
+
+       Format:
+
+       +<Cipher name>:<SIM path>
+
+   <PKCS>
+
+       Format:
+
+       +<PKCS name>:<key length>
+
+   <HashFunction>
+
+       Format:
+
+       +<Hash function name>:<SIM path>
+
+   <ServerInfo>
+
+       This section is used to set the server informations.
+
+       Format:
+
+       +<Server DNS name>:<Server IP>:<Geographic location>:<Port>
+
+   <AdminInfo>
+
+       This section is used to set the server's administrative information.
+
+       Format:
+
+       +<Location>:<Server type>:<Admin's name>:<Admin's email address>
+
+   <ListenPort>
+
+       This section is used to set ports the server is listenning.
+
+       Format:
+
+       +<Local IP/UNIX socket path>:<Remote IP>:<Port>
+
+   <Logging>
+
+       This section is used to set various logging files, their paths
+       and maximum sizes. All the other directives except those defined
+       below are ignored in this section. Log files are purged after they
+       reach the maximum set byte size.
+
+       Format:
+
+       +infologfile:<path>:<max byte size>
+       +errorlogfile:<path>:<max byte size>
+
+   <ConnectionClass>
+
+       This section is used to define connection classes. These can be
+       used to optimize the server and the connections.
+
+       Format:
+
+       +<Class number>:<Ping freq>:<Connect freq>:<Max links>
+
+   <ClientAuth>
+
+       This section is used to define client authentications.
+
+       Format:
+
+       +<Remote address or name>:<auth method>:<password/cert/key/???>:<Port>:<Class>
+
+   <AdminAuth>
+
+       This section is used to define the server's administration 
+       authentications.
+
+       Format:
+
+       +<Hostname>:<auth method>:<password/cert/key/???>:<Nickname hash>:<Class>
+
+   <ServerConnection>
+
+       This section is used to define the server connections to this
+       server/router. Only routers can have normal server connections.
+       Normal servers leave this section epmty. The remote server cannot be
+       older than specified Version ID.
+
+       Format:
+
+       +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
+
+   <RouterConnection>
+
+       This section is used to define the router connections to this
+       server/router. Both normal server and router can have router
+       connections. Normal server usually has only one connection while
+       a router can have multiple. The remote server cannot be older than
+       specified Version ID.
+
+       Format:
+
+       +<Remote address or name>:<auth method>:<password/key/???>:<Port>:<Version ID>:<Class>
+
+   <DenyConnection>
+
+       This section is used to deny specific connections to your server. This
+       can be used to deny both clients and servers.
+
+       Format:
+
+       +<Remote address or name or nickname>:<Time interval>:<Comment>:<Port>
+
+   <RedirectClient>
+
+       This section is used to set the alternate servers that clients will be
+       redirected to when our server is full.
+
+       Format:
+
+       +<Remote address or name>:<Port>
+
+*/
+SilcConfigServerSection silc_config_server_sections[] = {
+  { "[Cipher]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER, 4 },
+  { "[PKCS]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_PKCS, 2 },
+  { "[HashFunction]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION, 4 },
+  { "[ServerInfo]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO, 4 },
+  { "[AdminInfo]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
+  { "[ListenPort]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
+  { "[Logging]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
+  { "[ConnectionClass]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS, 4 },
+  { "[ClientConnection]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION, 5 },
+  { "[ServerConnection]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION, 6 },
+  { "[RouterConnection]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION, 6 },
+  { "[AdminConnection]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, 5 },
+  { "[DenyConnection]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 },
+  { "[RedirectClient]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 },
+  
+  { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
+};
+
+/* Allocates a new configuration object, opens configuration file and
+   parses the file. The parsed data is returned to the newly allocated
+   configuration object. */
+
+SilcConfigServer silc_config_server_alloc(char *filename)
+{
+  SilcConfigServer new;
+  SilcBuffer buffer;
+  SilcConfigServerParse config_parse;
+
+  SILC_LOG_DEBUG(("Allocating new configuration object"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    fprintf(stderr, "Could not allocate new configuration object");
+    return NULL;
+  }
+
+  new->filename = filename;
+
+  /* Open configuration file and parse it */
+  config_parse = NULL;
+  buffer = NULL;
+  silc_config_open(filename, &buffer);
+  if (!buffer)
+    goto fail;
+  if ((silc_config_server_parse(new, buffer, &config_parse)) == FALSE)
+    goto fail;
+  if ((silc_config_server_parse_lines(new, config_parse)) == FALSE)
+    goto fail;
+
+  silc_free(buffer);
+
+  return new;
+
+ fail:
+  silc_free(new);
+  return NULL;
+}
+
+/* Free's a configuration object. */
+
+void silc_config_server_free(SilcConfigServer config)
+{
+  if (config) {
+    silc_free(config->filename);
+    silc_free(config->server_info);
+    silc_free(config->admin_info);
+    silc_free(config->listen_port);
+    silc_free(config->conn_class);
+    silc_free(config->clients);
+    silc_free(config->admins);
+    silc_free(config->servers);
+    silc_free(config->routers);
+    silc_free(config->denied);
+    silc_free(config->redirect);
+    silc_free(config);
+  }
+}
+
+/* Parses the the buffer and returns the parsed lines into return_config
+   argument. The return_config argument doesn't have to be initialized 
+   before calling this. It will be initialized during the parsing. The
+   buffer sent as argument can be safely free'd after this function has
+   succesfully returned. */
+
+int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer, 
+                            SilcConfigServerParse *return_config)
+{
+  int i, begin;
+  unsigned int linenum;
+  char line[1024], *cp;
+  SilcConfigServerSection *cptr = NULL;
+  SilcConfigServerParse parse = *return_config, first = NULL;
+
+  SILC_LOG_DEBUG(("Parsing configuration file"));
+
+  begin = 0;
+  linenum = 0;
+  while((begin = silc_gets(line, sizeof(line), 
+                          buffer->data, buffer->len, begin)) != EOF) {
+    cp = line;
+    linenum++;
+
+    /* Check for bad line */
+    if (silc_check_line(cp))
+      continue;
+
+    /* Remove tabs and whitespaces from the line */
+    if (strchr(cp, '\t')) {
+      i = 0;
+      while(strchr(cp + i, '\t')) {
+       *strchr(cp + i, '\t') = ' ';
+       i++;
+      }
+    }
+    for (i = 0; i < strlen(cp); i++) {
+      if (cp[i] != ' ') {
+       if (i)
+         cp++;
+       break;
+      }
+      cp++;
+    }
+
+    /* Parse line */
+    switch(cp[0]) {
+    case '[':
+      /*
+       * Start of a section
+       */
+
+      /* Remove new line sign */
+      if (strchr(cp, '\n'))
+       *strchr(cp, '\n') = '\0';
+      
+      /* Check for matching sections */
+      for (cptr = silc_config_server_sections; cptr->section; cptr++)
+       if (!strcmp(cp, cptr->section))
+         break;
+
+      if (!cptr->section) {
+       fprintf(stderr, "%s:%d: Unknown section `%s'\n", 
+                       config->filename, linenum, cp);
+       return FALSE;
+      }
+
+      break;
+    default:
+      /*
+       * Start of a configuration line
+       */
+
+      if (cptr->type != SILC_CONFIG_SERVER_SECTION_TYPE_NONE) {
+       
+       if (strchr(cp, '\n'))
+           *strchr(cp, '\n') = ':';
+
+       if (parse == NULL) {
+         parse = silc_calloc(1, sizeof(*parse));
+         parse->line = NULL;
+         parse->section = NULL;
+         parse->next = NULL;
+         parse->prev = NULL;
+       } else {
+         if (parse->next == NULL) {
+           parse->next = silc_calloc(1, sizeof(*parse->next));
+           parse->next->line = NULL;
+           parse->next->section = NULL;
+           parse->next->next = NULL;
+           parse->next->prev = parse;
+           parse = parse->next;
+         }
+       }
+       
+       if (first == NULL)
+         first = parse;
+
+       /* Add the line to parsing structure for further parsing. */
+       if (parse) {
+         parse->section = cptr;
+         parse->line = silc_buffer_alloc(strlen(cp) + 1);
+         parse->linenum = linenum;
+         silc_buffer_pull_tail(parse->line, strlen(cp));
+         silc_buffer_put(parse->line, cp, strlen(cp));
+       }
+      }
+      break;
+    }
+  }
+  
+  /* Set the return_config argument to its first value so that further
+     parsing can be started from the first line. */
+  *return_config = first;
+
+  return TRUE;
+}
+
+/* Parses the lines earlier read from configuration file. The config object
+   must not be initialized, it will be initialized in this function. The
+   parse_config argument is uninitialized automatically during this
+   function. */
+
+int silc_config_server_parse_lines(SilcConfigServer config, 
+                                  SilcConfigServerParse parse_config)
+{
+  int ret, check = FALSE;
+  unsigned int checkmask;
+  char *tmp;
+  SilcConfigServerParse pc = parse_config;
+  SilcBuffer line;
+
+  SILC_LOG_DEBUG(("Parsing configuration lines"));
+  
+  if (!config)
+    return FALSE;
+  
+  checkmask = 0;
+  while(pc) {
+    check = FALSE;
+    line = pc->line;
+
+    /* Get number of tokens in line */
+    ret = silc_config_check_num_token(line);
+    if (ret != pc->section->maxfields) {
+      /* Bad line */
+      fprintf(stderr, "%s:%d: Missing tokens, %d tokens (should be %d)\n",
+             config->filename, pc->linenum, ret, 
+             pc->section->maxfields);
+      break;
+    }
+
+    /* Parse the line */
+    switch(pc->section->type) {
+    case SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->cipher);
+
+      /* Get cipher name */
+      ret = silc_config_get_token(line, &config->cipher->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Cipher name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+
+      /* Get module name */
+      config->cipher->sim_name = NULL;
+      ret = silc_config_get_token(line, &config->cipher->sim_name);
+      if (ret < 0)
+       break;
+
+      /* Get block length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Cipher block length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->cipher->block_len = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get key length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Cipher key length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->cipher->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_PKCS:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->pkcs);
+
+      /* Get PKCS name */
+      ret = silc_config_get_token(line, &config->pkcs->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: PKCS name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+
+      /* Get key length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: PKCS key length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->pkcs->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->hash_func);
+
+      /* Get Hash function name */
+      ret = silc_config_get_token(line, &config->hash_func->alg_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      
+      /* Get Hash function module name */
+      config->hash_func->sim_name = NULL;
+      ret = silc_config_get_token(line, &config->hash_func->sim_name);
+      if (ret < 0)
+       break;
+
+      /* Get block length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function block length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->hash_func->block_len = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get hash length */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Hash function hash length not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+      config->hash_func->key_len = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO:
+
+      if (!config->server_info)
+       config->server_info = silc_calloc(1, sizeof(*config->server_info));
+
+      /* Get server name */
+      ret = silc_config_get_token(line, &config->server_info->server_name);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       /* Server name not defined */
+
+      }
+      
+      /* Get server IP */
+      ret = silc_config_get_token(line, &config->server_info->server_ip);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       /* Server IP not defined */
+
+      }
+
+      /* Get server location */
+      ret = silc_config_get_token(line, &config->server_info->location);
+      if (ret < 0)
+       break;
+
+      /* Get server port */
+      /* XXX: Need port here??? */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       /* Port not defined */
+
+      }
+      config->server_info->port = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO:
+
+      if (!config->admin_info)
+       config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
+
+      /* Get server type */
+      ret = silc_config_get_token(line, &config->admin_info->server_type);
+      if (ret < 0)
+       break;
+
+      /* Get admins name */
+      ret = silc_config_get_token(line, &config->admin_info->admin_name);
+      if (ret < 0)
+       break;
+
+      /* Get admins email address */
+      ret = silc_config_get_token(line, &config->admin_info->admin_email);
+      if (ret < 0)
+       break;
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
+
+      /* Get host */
+      ret = silc_config_get_token(line, &config->listen_port->host);
+      if (ret < 0)
+       break;
+
+      /* Get remote IP */
+      ret = silc_config_get_token(line, &config->listen_port->remote_ip);
+      if (ret < 0)
+       break;
+
+      /* Get port */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       /* Any port */
+       config->listen_port->port = 0;
+      } else {
+       config->listen_port->port = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
+
+      /* Get class number */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       /* Class number not defined */
+
+      }
+      config->conn_class->class = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get ping frequency */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      config->conn_class->ping_freq = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get connect frequency */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      config->conn_class->connect_freq = atoi(tmp);
+      silc_free(tmp);
+
+      /* Get max links */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      config->conn_class->max_links = atoi(tmp);
+      silc_free(tmp);
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->logging);
+
+      /* Get log section type and check it */
+      ret = silc_config_get_token(line, &config->logging->logtype);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Log file section not defined\n", 
+               config->filename, pc->linenum);
+       break;
+      }
+      if (strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_INFO)
+         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_WARNING)
+         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_ERROR)
+         && strcmp(config->logging->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
+       fprintf(stderr, "%s:%d: Unknown log file section '%s'\n",
+               config->filename, pc->linenum, config->logging->logtype);
+       break;
+      }
+
+      /* Get log filename */
+      ret = silc_config_get_token(line, &config->logging->filename);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       fprintf(stderr, "%s:%d: Log file name not defined\n",
+               config->filename, pc->linenum);
+       break;
+      }
+
+      /* Get max byte size */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->logging->maxsize = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->clients);
+
+      /* Get host */
+      ret = silc_config_get_token(line, &config->clients->host);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any host */
+       config->clients->host = strdup("*");
+
+      /* Get authentication method */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+         config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+         config->clients->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+       silc_free(tmp);
+      }
+
+      /* Get authentication data */
+      ret = silc_config_get_token(line, &config->clients->auth_data);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any host */
+       config->clients->host = strdup("*");
+
+      /* Get port */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret == 0) {
+       config->clients->port = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      /* Get class number */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->clients->class = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->servers);
+
+      /* Get host */
+      ret = silc_config_get_token(line, &config->servers->host);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any host */
+       config->servers->host = strdup("*");
+
+      /* Get authentication method */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+         config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+         config->servers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+       silc_free(tmp);
+      }
+
+      /* Get authentication data */
+      ret = silc_config_get_token(line, &config->servers->auth_data);
+      if (ret < 0)
+       break;
+
+      /* Get port */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->servers->port = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      /* Get version */
+      ret = silc_config_get_token(line, &config->servers->version);
+      if (ret < 0)
+       break;
+
+      /* Get class number */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->servers->class = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->routers);
+
+      /* Get host */
+      ret = silc_config_get_token(line, &config->routers->host);
+      if (ret < 0)
+       break;
+      //      if (ret == 0)
+      ///* Any host */
+      //       config->routers->host = strdup("*");
+
+      /* Get authentication method */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+         config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+         config->routers->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+       silc_free(tmp);
+      }
+
+      /* Get authentication data */
+      ret = silc_config_get_token(line, &config->routers->auth_data);
+      if (ret < 0)
+       break;
+
+      /* Get port */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->routers->port = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      /* Get version */
+      ret = silc_config_get_token(line, &config->routers->version);
+      if (ret < 0)
+       break;
+
+      /* Get class number */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->routers->class = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION:
+
+      SILC_SERVER_CONFIG_LIST_ALLOC(config->admins);
+
+      /* Get host */
+      ret = silc_config_get_token(line, &config->admins->host);
+      if (ret < 0)
+       break;
+      if (ret == 0)
+       /* Any host */
+       config->admins->host = strdup("*");
+
+      /* Get authentication method */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       if (strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD) &&
+           strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY)) {
+         fprintf(stderr, "%s:%d: Unknown authentication method '%s'\n",
+                 config->filename, pc->linenum, tmp);
+         break;
+       }
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PASSWD))
+         config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+
+       if (!strcmp(tmp, SILC_CONFIG_SERVER_AUTH_METH_PUBKEY))
+         config->admins->auth_meth = SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY;
+
+       silc_free(tmp);
+      }
+
+      /* Get authentication data */
+      ret = silc_config_get_token(line, &config->admins->auth_data);
+      if (ret < 0)
+       break;
+
+      /* Get nickname */
+      ret = silc_config_get_token(line, &config->admins->nickname);
+      if (ret < 0)
+       break;
+
+      /* Get class number */
+      ret = silc_config_get_token(line, &tmp);
+      if (ret < 0)
+       break;
+      if (ret) {
+       config->admins->class = atoi(tmp);
+       silc_free(tmp);
+      }
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION:
+      /* Not implemented yet */
+      check = TRUE;
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT:
+      /* Not implemented yet */
+      check = TRUE;
+      break;
+
+    case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
+    default:
+      /* Error */
+      break;
+    }
+
+    /* Check for error */
+    if (check == FALSE) {
+      /* Line could not be parsed */
+      fprintf(stderr, "%s:%d: Parse error\n", config->filename, pc->linenum);
+      break;
+    }
+
+    pc = pc->next;
+    /* XXXX */
+    //    silc_free(pc->prev);
+    //    pc->prev = NULL;
+  }
+
+  if (check == FALSE)
+    return FALSE;;
+
+  /* Check that all mandatory sections really were found. If not, the server
+     cannot function and we return error. */
+  ret = silc_config_server_check_sections(checkmask);
+  if (ret == FALSE) {
+    /* XXX */
+
+  }
+  
+  /* Before returning all the lists in the config object must be set
+     to their first values (the last value is first here). */
+  while (config->cipher && config->cipher->prev)
+    config->cipher = config->cipher->prev;
+  while (config->pkcs && config->pkcs->prev)
+    config->pkcs = config->pkcs->prev;
+  while (config->hash_func && config->hash_func->prev)
+    config->hash_func = config->hash_func->prev;
+  while (config->listen_port && config->listen_port->prev)
+    config->listen_port = config->listen_port->prev;
+  while (config->logging && config->logging->prev)
+    config->logging = config->logging->prev;
+  while (config->conn_class && config->conn_class->prev)
+    config->conn_class = config->conn_class->prev;
+  while (config->clients && config->clients->prev)
+    config->clients = config->clients->prev;
+  while (config->servers && config->servers->prev)
+    config->servers = config->servers->prev;
+  while (config->routers && config->routers->prev)
+    config->routers = config->routers->prev;
+  
+  SILC_LOG_DEBUG(("Done"));
+  
+  return TRUE;
+}
+
+/* This function checks that the mask sent as argument includes all the 
+   sections that are mandatory in SILC server. */
+
+int silc_config_server_check_sections(unsigned int checkmask)
+{
+  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO))) {
+    
+    return FALSE;
+  }
+  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO))) {
+    
+    return FALSE;
+  }
+  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT))) {
+    
+    return FALSE;
+  }
+  if (!(checkmask & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION))) {
+    
+    return FALSE;
+  }
+  if (!(checkmask 
+       & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION))) {
+    
+    return FALSE;
+  }
+  if (!(checkmask 
+       & (1L << SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION))) {
+    
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Sets log files where log messages is saved by the server. */
+
+void silc_config_server_setlogfiles(SilcConfigServer config)
+{
+  SilcConfigServerSectionLogging *log;
+  char *info, *warning, *error, *fatal;
+  unsigned int info_size, warning_size, error_size, fatal_size;
+
+  SILC_LOG_DEBUG(("Setting configured log file names"));
+
+  /* Set default files before checking configuration */
+  info = SILC_LOG_FILE_INFO;
+  warning = SILC_LOG_FILE_WARNING;
+  error = SILC_LOG_FILE_ERROR;
+  fatal = SILC_LOG_FILE_FATAL;
+  info_size = 0;
+  warning_size = 0;
+  error_size = 0;
+  fatal_size = 0;
+
+  log = config->logging;
+  while(log) {
+    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_INFO)) {
+      info = log->filename;
+      info_size = log->maxsize;
+    }
+    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_WARNING)) {
+      warning = log->filename;
+      warning_size = log->maxsize;
+    }
+    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_ERROR)) {
+      error = log->filename;
+      error_size = log->maxsize;
+    }
+    if (!strcmp(log->logtype, SILC_CONFIG_SERVER_LF_FATAL)) {
+      fatal = log->filename;
+      fatal_size = log->maxsize;
+    }
+
+    log = log->next;
+  }
+
+  silc_log_set_files(info, info_size, warning, warning_size,
+                    error, error_size, fatal, fatal_size);
+}
+
+/* Registers configured ciphers. These can then be allocated by the
+   server when needed. */
+
+void silc_config_server_register_ciphers(SilcConfigServer config)
+{
+  SilcConfigServerSectionAlg *alg;
+  SilcServer server = (SilcServer)config->server;
+
+  SILC_LOG_DEBUG(("Registering configured ciphers"));
+
+  alg = config->cipher;
+  while(alg) {
+
+    if (!alg->sim_name) {
+      /* Crypto module is supposed to be built in. Nothing to be done
+        here except to test that the cipher really is built in. */
+      SilcCipher tmp = NULL;
+
+      if (silc_cipher_alloc(alg->alg_name, &tmp) == FALSE) {
+       SILC_LOG_ERROR(("Unsupported cipher `%s'", alg->alg_name));
+       silc_server_stop(server);
+       exit(1);
+      }
+      silc_cipher_free(tmp);
+
+#ifdef SILC_SIM
+    } else {
+      /* Load (try at least) the crypto SIM module */
+      SilcCipherObject cipher;
+      SilcSimContext *sim;
+
+      memset(&cipher, 0, sizeof(cipher));
+      cipher.name = alg->alg_name;
+      cipher.block_len = alg->block_len;
+      cipher.key_len = alg->key_len * 8;
+
+      sim = silc_sim_alloc();
+      sim->type = SILC_SIM_CIPHER;
+      sim->libname = alg->sim_name;
+
+      if ((silc_sim_load(sim))) {
+       cipher.set_key = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+                                               SILC_CIPHER_SIM_SET_KEY));
+       SILC_LOG_DEBUG(("set_key=%p", cipher.set_key));
+       cipher.set_key_with_string = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+                                               SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
+       SILC_LOG_DEBUG(("set_key_with_string=%p", cipher.set_key_with_string));
+       cipher.encrypt = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_CIPHER_SIM_ENCRYPT_CBC));
+       SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher.encrypt));
+        cipher.decrypt = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_CIPHER_SIM_DECRYPT_CBC));
+       SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher.decrypt));
+        cipher.context_len = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_CIPHER_SIM_CONTEXT_LEN));
+       SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
+
+       /* Put the SIM to the table of all SIM's in server */
+       server->sim = silc_realloc(server->sim,
+                                  sizeof(*server->sim) * 
+                                  (server->sim_count + 1));
+       server->sim[server->sim_count] = sim;
+       server->sim_count++;
+      } else {
+       SILC_LOG_ERROR(("Error configuring ciphers"));
+       silc_server_stop(server);
+       exit(1);
+      }
+
+      /* Register the cipher */
+      silc_cipher_register(&cipher);
+#endif
+    }
+
+    alg = alg->next;
+  }
+}
+
+/* Registers configured PKCS's. */
+/* XXX: This really doesn't do anything now since we have statically
+   registered our PKCS's. This should be implemented when PKCS works
+   as SIM's. This checks now only that the PKCS user requested is 
+   really out there. */
+
+void silc_config_server_register_pkcs(SilcConfigServer config)
+{
+  SilcConfigServerSectionAlg *alg = config->pkcs;
+  SilcServer server = (SilcServer)config->server;
+  SilcPKCS tmp = NULL;
+
+  SILC_LOG_DEBUG(("Registering configured PKCS"));
+
+  while(alg) {
+
+    if (silc_pkcs_alloc(alg->alg_name, &tmp) == FALSE) {
+      SILC_LOG_ERROR(("Unsupported PKCS `%s'", alg->alg_name));
+      silc_server_stop(server);
+      exit(1);
+    }
+    silc_free(tmp);
+
+    alg = alg->next;
+  }
+}
+
+/* Registers configured hash functions. These can then be allocated by the
+   server when needed. */
+
+void silc_config_server_register_hashfuncs(SilcConfigServer config)
+{
+  SilcConfigServerSectionAlg *alg;
+  SilcServer server = (SilcServer)config->server;
+
+  SILC_LOG_DEBUG(("Registering configured hash functions"));
+
+  alg = config->hash_func;
+  while(alg) {
+
+    if (!alg->sim_name) {
+      /* Hash module is supposed to be built in. Nothing to be done
+        here except to test that the hash function really is built in. */
+      SilcHash tmp = NULL;
+
+      if (silc_hash_alloc(alg->alg_name, &tmp) == FALSE) {
+       SILC_LOG_ERROR(("Unsupported hash function `%s'", alg->alg_name));
+       silc_server_stop(server);
+       exit(1);
+      }
+      silc_free(tmp);
+
+#ifdef SILC_SIM
+    } else {
+      /* Load (try at least) the hash SIM module */
+      SilcHashObject hash;
+      SilcSimContext *sim;
+
+      memset(&hash, 0, sizeof(hash));
+      hash.name = alg->alg_name;
+      hash.block_len = alg->block_len;
+      hash.hash_len = alg->key_len;
+
+      sim = silc_sim_alloc();
+      sim->type = SILC_SIM_HASH;
+      sim->libname = alg->sim_name;
+
+      if ((silc_sim_load(sim))) {
+       hash.init = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name, 
+                                               SILC_HASH_SIM_INIT));
+       SILC_LOG_DEBUG(("init=%p", hash.init));
+       hash.update = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_HASH_SIM_UPDATE));
+       SILC_LOG_DEBUG(("update=%p", hash.update));
+        hash.final = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_HASH_SIM_FINAL));
+       SILC_LOG_DEBUG(("final=%p", hash.final));
+        hash.context_len = 
+         silc_sim_getsym(sim, silc_sim_symname(alg->alg_name,
+                                               SILC_HASH_SIM_CONTEXT_LEN));
+       SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
+
+       /* Put the SIM to the table of all SIM's in server */
+       server->sim = silc_realloc(server->sim,
+                                  sizeof(*server->sim) * 
+                                  (server->sim_count + 1));
+       server->sim[server->sim_count] = sim;
+       server->sim_count++;
+      } else {
+       SILC_LOG_ERROR(("Error configuring hash functions"));
+       silc_server_stop(server);
+       exit(1);
+      }
+
+      /* Register the cipher */
+      silc_hash_register(&hash);
+#endif
+    }
+
+    alg = alg->next;
+  }
+}
+
+/* Returns client authentication information from server configuration
+   by host (name or ip). */
+
+SilcConfigServerSectionClientConnection *
+silc_config_server_find_client_conn(SilcConfigServer config, 
+                                   char *host, int port)
+{
+  int i;
+  SilcConfigServerSectionClientConnection *client = NULL;
+
+  if (!host)
+    return NULL;
+
+  if (!config->clients)
+    return NULL;
+
+  client = config->clients;
+
+  for (i = 0; client; i++) {
+    if (silc_string_compare(client->host, host))
+      break;
+    client = client->next;
+  }
+
+  if (!client)
+    return NULL;
+
+  return client;
+}
+
+/* Returns server connection info from server configuartion by host 
+   (name or ip). */
+
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_server_conn(SilcConfigServer config, 
+                                   char *host, int port)
+{
+  int i;
+  SilcConfigServerSectionServerConnection *serv = NULL;
+
+  if (!host)
+    return NULL;
+
+  if (!config->servers)
+    return NULL;
+
+  serv = config->servers;
+  for (i = 0; serv; i++) {
+    if (silc_string_compare(serv->host, host))
+      break;
+    serv = serv->next;
+  }
+
+  if (!serv)
+    return NULL;
+
+  return serv;
+}
+
+/* Returns router connection info from server configuartion by
+   host (name or ip). */
+
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_router_conn(SilcConfigServer config, 
+                                   char *host, int port)
+{
+  int i;
+  SilcConfigServerSectionServerConnection *serv = NULL;
+
+  if (!host)
+    return NULL;
+
+  if (!config->routers)
+    return NULL;
+
+  serv = config->routers;
+  for (i = 0; serv; i++) {
+    if (silc_string_compare(serv->host, host))
+      break;
+    serv = serv->next;
+  }
+
+  if (!serv)
+    return NULL;
+
+  return serv;
+}
+
+/* Prints out example configuration file with default built in
+   configuration values. */
+
+void silc_config_server_print()
+{
+  char *buf;
+
+  buf = "\
+#\n\
+# Automatically generated example SILCd configuration file with default\n\
+# built in values. Use this as a guide to configure your SILCd configuration\n\
+# file for your system. For detailed description of different configuration\n\
+# sections refer to silcd(8) manual page.\n\
+#\n";
+  /*
+#<Cipher>
+#+blowfish
+#+twofish
+#+rc5
+#+rc6
+#+3des
+
+#<HashFunction>
+#+md5
+#+sha1
+
+<ServerInfo>
++lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+
+<AdminInfo>
++Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+<ListenPort>
++10.2.1.6:10.2.1.6:1333
+
+<Logging>
++infologfile:silcd.log:10000
+#+warninglogfile:/var/log/silcd_warning.log:10000
+#+errorlogfile:ERROR.log:10000
+#+fatallogfile:/var/log/silcd_error.log:
+
+<ConnectionClass>
+               +1:100:100:100
+                       +2:200:300:400
+
+<ClientAuth>
++10.2.1.199:priikone:333:1
+
+<AdminAuth>
++10.2.1.199:priikone:priikone:1
+
+<ServerConnection>
+
+<RouterConnection>
+
+<DenyConnection>
+<RedirectClient>
+  */
+
+  fprintf(stdout, "%s\n", buf);
+}
diff --git a/apps/silcd/serverconfig.h b/apps/silcd/serverconfig.h
new file mode 100644 (file)
index 0000000..56ed10e
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+
+  serverconfig.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERVERCONFIG_H
+#define SERVERCONFIG_H
+
+/* Holds information of configured algorithms */
+typedef struct SilcConfigServerSectionAlgStruct {
+  char *alg_name;
+  char *sim_name;
+  unsigned int block_len;
+  unsigned int key_len;
+  struct SilcConfigServerSectionAlgStruct *next;
+  struct SilcConfigServerSectionAlgStruct *prev;
+#define SILC_CONFIG_SERVER_MODNAME "builtin"
+} SilcConfigServerSectionAlg;
+
+/* Holds server information from config file */
+typedef struct {
+  char *server_name;
+  char *server_ip;
+  char *location;
+  unsigned short port;
+} SilcConfigServerSectionServerInfo;
+
+/* Holds server's administrative information from config file */
+typedef struct {
+  char *server_type;
+  char *admin_name;
+  char *admin_email;
+} SilcConfigServerSectionAdminInfo;
+
+/* Holds all the ports the server is listenning on */
+typedef struct SilcConfigServerSectionListenPortStruct {
+  char *host;
+  char *remote_ip;
+  unsigned short port;
+  struct SilcConfigServerSectionListenPortStruct *next;
+  struct SilcConfigServerSectionListenPortStruct *prev;
+} SilcConfigServerSectionListenPort;
+
+/* Holds all the configured log files. */
+typedef struct SilcConfigServerSectionLoggingStruct {
+  char *logtype;
+  char *filename;
+  unsigned int maxsize;
+  struct SilcConfigServerSectionLoggingStruct *next;
+  struct SilcConfigServerSectionLoggingStruct *prev;
+
+/* Allowed <Logging> section types */
+#define SILC_CONFIG_SERVER_LF_INFO "infologfile"
+#define SILC_CONFIG_SERVER_LF_WARNING "warninglogfile"
+#define SILC_CONFIG_SERVER_LF_ERROR "errorlogfile"
+#define SILC_CONFIG_SERVER_LF_FATAL "fatalogfile"
+} SilcConfigServerSectionLogging;
+
+/* Holds all configured connection classes */
+typedef struct SilcConfigServerSectionConnectionClassStruct {
+  unsigned int class;
+  unsigned int ping_freq;
+  unsigned int connect_freq;
+  unsigned int max_links;
+  struct SilcConfigServerSectionConnectionClassStruct *next;
+  struct SilcConfigServerSectionConnectionClassStruct *prev;
+} SilcConfigServerSectionConnectionClass;
+
+#define SILC_CONFIG_SERVER_AUTH_METH_PASSWD "passwd"
+#define SILC_CONFIG_SERVER_AUTH_METH_PUBKEY "pubkey"
+
+/* Holds all client authentication data from config file */
+typedef struct SilcConfigServerSectionClientConnectionStruct {
+  char *host;
+  int auth_meth;
+  char *auth_data;
+  unsigned short port;
+  unsigned int class;
+  struct SilcConfigServerSectionClientConnectionStruct *next;
+  struct SilcConfigServerSectionClientConnectionStruct *prev;
+} SilcConfigServerSectionClientConnection;
+
+/* Hols all server's administrators authentication data from config file */
+typedef struct SilcConfigServerSectionAdminConnectionStruct {
+  char *host;
+  int auth_meth;
+  char *auth_data;
+  char *nickname;
+  unsigned int class;
+  struct SilcConfigServerSectionAdminConnectionStruct *next;
+  struct SilcConfigServerSectionAdminConnectionStruct *prev;
+} SilcConfigServerSectionAdminConnection;
+
+/* Holds all configured server/router connections from config file */
+typedef struct SilcConfigServerSectionServerConnectionStruct {
+  char *host;
+  int auth_meth;
+  char *auth_data;
+  unsigned short port;
+  char *version;
+  unsigned int class;
+  struct SilcConfigServerSectionServerConnectionStruct *next;
+  struct SilcConfigServerSectionServerConnectionStruct *prev;
+} SilcConfigServerSectionServerConnection;
+
+/* Holds all configured denied connections from config file */
+typedef struct {
+  char *host;
+  char *time;
+  char *comment;
+  unsigned short port;
+} SilcConfigServerSectionDenyConnection;
+
+/* Holds all client redirections from config file */
+typedef struct {
+  char *host;
+  unsigned short port;
+} SilcConfigServerSectionRedirectClient;
+
+/* 
+   SILC Server Config object. 
+
+   This object holds all the data parsed from the SILC server configuration
+   file. This is mainly used at the initialization of the server.
+
+*/
+typedef struct {
+  /* Pointer back to the server */
+  void *server;
+
+  /* Filename of the configuration file */
+  char *filename;
+
+  /* Configuration sections */
+  SilcConfigServerSectionAlg *cipher;
+  SilcConfigServerSectionAlg *pkcs;
+  SilcConfigServerSectionAlg *hash_func;
+  SilcConfigServerSectionServerInfo *server_info;
+  SilcConfigServerSectionAdminInfo *admin_info;
+  SilcConfigServerSectionListenPort *listen_port;
+  SilcConfigServerSectionLogging *logging;
+  SilcConfigServerSectionConnectionClass *conn_class;
+  SilcConfigServerSectionClientConnection *clients;
+  SilcConfigServerSectionServerConnection *servers;
+  SilcConfigServerSectionServerConnection *routers;
+  SilcConfigServerSectionAdminConnection *admins;
+  SilcConfigServerSectionDenyConnection *denied;
+  SilcConfigServerSectionRedirectClient *redirect;
+} SilcConfigServerObject;
+
+typedef SilcConfigServerObject *SilcConfigServer;
+
+/* Configuration section type enumerations. */
+typedef enum {
+  SILC_CONFIG_SERVER_SECTION_TYPE_NONE = 0,
+  SILC_CONFIG_SERVER_SECTION_TYPE_CIPHER,
+  SILC_CONFIG_SERVER_SECTION_TYPE_PKCS,
+  SILC_CONFIG_SERVER_SECTION_TYPE_HASH_FUNCTION,
+  SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO,
+  SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO,
+  SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT,
+  SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING,
+  SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS,
+  SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION,
+  SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_CONNECTION,
+  SILC_CONFIG_SERVER_SECTION_TYPE_ROUTER_CONNECTION,
+  SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION,
+  SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION,
+  SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT,
+} SilcConfigServerSectionType;
+
+/* SILC Configuration Section structure. */
+typedef struct {
+  const char *section;
+  SilcConfigServerSectionType type;
+  unsigned int maxfields;
+} SilcConfigServerSection;
+
+/* LIst of all possible config sections in SILC server. */
+extern SilcConfigServerSection silc_config_server_sections[];
+
+/* Structure used in parsing the configuration lines. The line is read
+   from a file to this structure before parsing it further. */
+typedef struct SilcConfigServerParseStruct {
+  SilcBuffer line;
+  unsigned int linenum;
+  SilcConfigServerSection *section;
+  struct SilcConfigServerParseStruct *next;
+  struct SilcConfigServerParseStruct *prev;
+} *SilcConfigServerParse;
+
+/* Macros */
+
+/* Allocates list entries for configuration sections. Used by all
+   config sections as this is common. */
+#define SILC_SERVER_CONFIG_LIST_ALLOC(x)               \
+do {                                                   \
+  if (!(x)) {                                          \
+    (x) = silc_calloc(1, sizeof(*(x)));                        \
+    (x)->next = NULL;                                  \
+    (x)->prev = NULL;                                  \
+  } else {                                             \
+    if (!(x)->next) {                                  \
+      (x)->next = silc_calloc(1, sizeof(*(x)->next));  \
+      (x)->next->next = NULL;                          \
+      (x)->next->prev = (x);                           \
+      (x) = (x)->next;                                 \
+    }                                                  \
+  }                                                    \
+} while(0)
+
+/* Prototypes */
+SilcConfigServer silc_config_server_alloc(char *filename);
+void silc_config_server_free(SilcConfigServer config);
+int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
+                            SilcConfigServerParse *return_config);
+int silc_config_server_parse_lines(SilcConfigServer config, 
+                                  SilcConfigServerParse parse_config);
+int silc_config_server_check_sections(unsigned int checkmask);
+void silc_config_server_setlogfiles(SilcConfigServer config);
+void silc_config_server_register_ciphers(SilcConfigServer config);
+void silc_config_server_register_pkcs(SilcConfigServer config);
+void silc_config_server_register_hashfuncs(SilcConfigServer config);
+SilcConfigServerSectionClientConnection *
+silc_config_server_find_client_conn(SilcConfigServer config, 
+                                   char *host, int port);
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_server_conn(SilcConfigServer config, 
+                                   char *host, int port);
+SilcConfigServerSectionServerConnection *
+silc_config_server_find_router_conn(SilcConfigServer config, 
+                                   char *host, int port);
+void silc_config_server_print();
+
+#endif
diff --git a/apps/silcd/serverid.c b/apps/silcd/serverid.c
new file mode 100644 (file)
index 0000000..26f010c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+
+  id.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+
+/* Creates a Server ID. Newly created Server ID is returned to the
+   new_id argument. */
+
+void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id)
+{
+  struct sockaddr_in server;
+  int rval, len;
+
+  SILC_LOG_DEBUG(("Creating new Server ID"));
+
+  *new_id = silc_calloc(1, sizeof(**new_id));
+  if (*new_id == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new Server ID"));
+    return;
+  }
+
+  /* Get IP address */
+  len = sizeof(server);
+  rval = getsockname(sock, (struct sockaddr *)&server, &len);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Could not get IP address: %s", strerror(errno)));
+    silc_free(*new_id);
+    *new_id = NULL;
+    return;
+  }
+
+  /* Create the ID */
+  (*new_id)->ip = server.sin_addr;
+  (*new_id)->port = server.sin_port;
+  (*new_id)->rnd = silc_rng_get_rn16(rng);
+}
+
+/* Creates Client ID */
+
+void silc_id_create_client_id(SilcServerID *server_id, SilcRng rng,
+                             SilcHash md5hash, char *nickname, 
+                             SilcClientID **new_id)
+{
+  unsigned char hash[16];
+
+  SILC_LOG_DEBUG(("Creating new Client ID"));
+
+  *new_id = silc_calloc(1, sizeof(**new_id));
+  if (*new_id == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new Client ID"));
+    return;
+  }
+
+  /* Create hash of the nickanem */
+  silc_hash_make(md5hash, nickname, strlen(nickname), hash);
+
+  /* Create the ID */
+  (*new_id)->ip.s_addr = server_id->ip.s_addr;
+  (*new_id)->rnd = silc_rng_get_byte(rng);
+  memcpy((*new_id)->hash, hash, CLIENTID_HASH_LEN);
+}
+
+/* Creates Channel ID */
+
+void silc_id_create_channel_id(SilcServerID *router_id, SilcRng rng,
+                              SilcChannelID **new_id)
+{
+  SILC_LOG_DEBUG(("Creating new Channel ID"));
+
+  *new_id = silc_calloc(1, sizeof(**new_id));
+  if (*new_id == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new Channel ID"));
+    return;
+  }
+
+  /* Create the ID */
+  (*new_id)->ip.s_addr = router_id->ip.s_addr;
+  (*new_id)->port = router_id->port;
+  (*new_id)->rnd = silc_rng_get_rn16(rng);
+}
diff --git a/apps/silcd/serverid.h b/apps/silcd/serverid.h
new file mode 100644 (file)
index 0000000..2f5f858
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+
+  serverid.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERVERID_H
+#define SERVERID_H
+
+/* Prototypes */
+void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id);
+void silc_id_create_client_id(SilcServerID *server_id, SilcRng rng,
+                             SilcHash md5hash, char *nickname, 
+                             SilcClientID **new_id);
+void silc_id_create_channel_id(SilcServerID *router_id, SilcRng rng,
+                              SilcChannelID **new_id);
+
+#endif
diff --git a/apps/silcd/silc.conf b/apps/silcd/silc.conf
new file mode 100644 (file)
index 0000000..d7d4447
--- /dev/null
@@ -0,0 +1,44 @@
+[Cipher]
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ServerInfo]
+silc.pspt.fi:193.166.51.47:Kuopio, Finland:1333
+
+[ListenPort]
+193.166.51.47:193.166.51.47:1333
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+#errorlogfile:ERROR.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+:::1333:1
+
+[AdminConnection]
+
+[ServerConnection]
+
+[RouterConnection]
+
+[DenyConnection]
+[RedirectClient]
diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c
new file mode 100644 (file)
index 0000000..584141d
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+
+  silcd.c
+  
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* 
+ * Created: Wed Mar 19 00:17:12 1997
+ *
+ * This is the main program for the SILC daemon. This parses command
+ * line arguments and creates the server object.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+#include "version.h"
+
+/* Long command line options */
+static struct option long_opts[] = 
+{
+  { "config-file", 1, NULL, 'f' },
+  { "generate-config-file", 0, NULL, 'c' },
+  { "help", 0, NULL, 'h' },
+  { "version", 0, NULL,'V' },
+  { NULL, 0, NULL, 0 }
+};
+
+/* Prints out the usage of silc client */
+
+void silc_usage()
+{
+  printf("Usage: silcd [options]\n");
+  printf("Options:\n");
+  printf("  -f  --config-file=FILE        Alternate configuration file\n");
+  printf("  -c  --generate-config-file    Generate example configuration "
+        "file\n");
+  printf("  -h  --help                    Display this message\n");
+  printf("  -V  --version                 Display version\n");
+  exit(0);
+}
+
+int main(int argc, char **argv)
+{
+  int ret;
+  int opt, option_index;
+  char *config_file = NULL;
+  SilcServer silcd;
+
+  /* Parse command line arguments */
+  if (argc > 1) {
+    while ((opt = getopt_long(argc, argv, "cf:hV",
+                             long_opts, &option_index)) != EOF) {
+      switch(opt) 
+       {
+       case 'h':
+         silc_usage();
+         break;
+       case 'V':
+         printf("SILCd Secure Internet Live Conferencing daemon, "
+                "version %s\n", silc_version);
+         printf("(c) 1997 - 2000 Pekka Riikonen "
+                "<priikone@poseidon.pspt.fi>\n");
+         exit(0);
+         break;
+       case 'c':
+         /* Print out example configuration file */
+         silc_config_server_print();
+         exit(0);
+         break;
+       case 'f':
+         config_file = strdup(optarg);
+         break;
+       default:
+         silc_usage();
+         break;
+       }
+    }
+  }
+
+  /* Default configuration file */
+  if (!config_file)
+    config_file = strdup(SILC_SERVER_CONFIG_FILE);
+
+  /* Create SILC Server object */
+  ret = silc_server_alloc(&silcd);
+  if (ret == FALSE)
+    goto fail;
+
+  /* Read configuration files */
+  silcd->config = silc_config_server_alloc(config_file);
+  if (silcd->config == NULL)
+    goto fail;
+
+  /* Initialize the server */
+  ret = silc_server_init(silcd);
+  if (ret == FALSE)
+    goto fail;
+  
+  /* Run the server. When this returns the server has been stopped
+     and we will exit. */
+  silc_server_run(silcd);
+  
+  /* Stop the server. This probably has been done already but it
+     doesn't hurt to do it here again. */
+  silc_server_stop(silcd);
+  silc_server_free(silcd);
+  
+  exit(0);
+ fail:
+  exit(1);
+}
diff --git a/apps/silcd/silcd.h b/apps/silcd/silcd.h
new file mode 100644 (file)
index 0000000..1f33d12
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+  silcd.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCD_H
+#define SILCD_H
+
+/* Default server configuration file. This can be overridden at the
+   compilation time. Otherwise, use default. This can be overridden on
+   command line as well. */
+#ifndef SILC_SERVER_CONFIG_FILE
+#define SILC_SERVER_CONFIG_FILE "/etc/silc/silcd.conf\0"
+#endif
+
+void usage();
+
+char file_public_key[100];       /* server public key */
+char file_private_key[100];      /* server private key */
+
+#define PUBLICKEY_NAME "/silc_host_public"
+#define PRIVATEKEY_NAME "/silc_host_private"
+
+#define SERVER_KEY_EXPIRATION_DAYS 180
+int key_expires;
+
+#endif
diff --git a/apps/silcd/testi.conf b/apps/silcd/testi.conf
new file mode 100644 (file)
index 0000000..e5417e2
--- /dev/null
@@ -0,0 +1,45 @@
+[Cipher]
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ServerInfo]
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+
+[ListenPort]
+10.2.1.6:10.2.1.6:1333
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:silcd2_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+
+[ServerConnection]
+
+[RouterConnection]
+
+[DenyConnection]
+[RedirectClient]
diff --git a/apps/silcd/testi2.conf b/apps/silcd/testi2.conf
new file mode 100644 (file)
index 0000000..8d44456
--- /dev/null
@@ -0,0 +1,47 @@
+[Cipher]
+rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+[HashFunction]
+md5::64:16
+sha1::64:20
+
+#[PKCS]
+#rsa::1024
+#dss::1024
+
+[AdminInfo]
+Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+[ServerInfo]
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1334
+
+[ListenPort]
+10.2.1.6:10.2.1.6:1334
+
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+errorlogfile:silcd2_error.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+[ClientConnection]
+10.2.1.199:passwd:priikone:333:1
+:::1333:1
+
+[AdminConnection]
+10.2.1.199:passwd:priikone:priikone:1
+
+[ServerConnection]
+
+[RouterConnection]
+10.2.1.6:passwd:priikone:1333:1:1
+
+[DenyConnection]
+[RedirectClient]
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..1d27287
--- /dev/null
@@ -0,0 +1,997 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .globl main
+       .ent main
+main:
+       .frame \$30,0,\$26,0
+       .prologue 0
+       .long 0x47e03d80 # implver $0
+       lda \$2,259
+       .long 0x47e20c21 # amask $2,$1
+       srl \$1,8,\$2
+       sll \$2,2,\$2
+       sll \$0,3,\$0
+       addl \$1,\$0,\$0
+       addl \$2,\$0,\$0
+       ret \$31,(\$26),1
+       .end main
+EOF
+       ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               ./$dummy
+               case "$?" in
+                       7)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       15)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       14)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       10)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       16)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-cbm-sysv4
+       exit 0;;
+    amiga:NetBSD:*:*)
+      echo m68k-cbm-netbsd${UNAME_RELEASE}
+      exit 0 ;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    arm32:NetBSD:*:*)
+       echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    SR2?01:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:NetBSD:*:*)
+       echo m68k-atari-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3*:NetBSD:*:*)
+       echo m68k-sun-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:NetBSD:*:*)
+       echo m68k-apple-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:NetBSD:*:*)
+        echo powerpc-apple-netbsd${UNAME_RELEASE}
+        exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       ${CC-cc} $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+        if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+       if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+            -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+       else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+       fi
+        else echo i586-dg-dgux${UNAME_RELEASE}
+        fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:4)
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=4.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/6?? | 9000/7?? | 9000/80[024] | 9000/8?[136790] | 9000/892 )
+              sed 's/^              //' << EOF >$dummy.c
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (${CC-cc} $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       rm -f $dummy.c $dummy
+       esac
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE*:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    *9??*:MPE*:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i?86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo t3e-cray-unicosmk${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F300:UNIX_System_V:*:*)
+        FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    F301:UNIX_System_V:*:*)
+       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+       exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+       echo m68k-hp-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       if test -x /usr/bin/objformat; then
+           if test "elf" = "`/usr/bin/objformat`"; then
+               echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
+               exit 0
+           fi
+       fi
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:NetBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    *:Linux:*:*)
+#      # uname on the ARM produces all sorts of strangeness, and we need to
+#      # filter it out.
+#      case "$UNAME_MACHINE" in
+#        armv*)                      UNAME_MACHINE=$UNAME_MACHINE ;;
+#        arm* | sa110*)              UNAME_MACHINE="arm" ;;
+#      esac
+
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us.
+       ld_help_string=`ld --help 2>&1`
+       ld_supported_emulations=`echo $ld_help_string \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         i?86linux)  echo "${UNAME_MACHINE}-pc-linux-gnuaout"      ; exit 0 ;;
+         i?86coff)   echo "${UNAME_MACHINE}-pc-linux-gnucoff"      ; exit 0 ;;
+         sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+         armlinux)   echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+         m68klinux)  echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+         elf32arm)   echo "${UNAME_MACHINE}-unknown-linux-gnu"     ; exit 0 ;;
+         elf32ppc)   echo "powerpc-unknown-linux-gnu"              ; exit 0 ;;
+       esac
+
+       if test "${UNAME_MACHINE}" = "alpha" ; then
+               sed 's/^        //'  <<EOF >$dummy.s
+               .globl main
+               .ent main
+       main:
+               .frame \$30,0,\$26,0
+               .prologue 0
+               .long 0x47e03d80 # implver $0
+               lda \$2,259
+               .long 0x47e20c21 # amask $2,$1
+               srl \$1,8,\$2
+               sll \$2,2,\$2
+               sll \$0,3,\$0
+               addl \$1,\$0,\$0
+               addl \$2,\$0,\$0
+               ret \$31,(\$26),1
+               .end main
+EOF
+               LIBC=""
+               ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       ./$dummy
+                       case "$?" in
+                       7)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       15)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       14)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       10)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       16)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       esac
+
+                       objdump --private-headers $dummy | \
+                         grep ld.so.1 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi
+               rm -f $dummy.s $dummy
+               echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+       elif test "${UNAME_MACHINE}" = "mips" ; then
+         cat >$dummy.c <<EOF
+#ifdef __cplusplus
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       else
+         # Either a pre-BFD a.out linker (linux-gnuoldld)
+         # or one that does not give us useful --help.
+         # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+         # If ld does not provide *any* "supported emulations:"
+         # that means it is gnuoldld.
+         echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+         test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+         case "${UNAME_MACHINE}" in
+         i?86)
+           VENDOR=pc;
+           ;;
+         *)
+           VENDOR=unknown;
+           ;;
+         esac
+         # Determine whether the default compiler is a.out or elf
+         cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i?86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i?86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i?86:UnixWare:*:*)
+       if /bin/uname -X 2>/dev/null >/dev/null ; then
+         (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+           && UNAME_MACHINE=i586
+       fi
+       echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION}
+       exit 0 ;;
+    pc:*:*:*)
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:*:6*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..ecf770c
--- /dev/null
@@ -0,0 +1,979 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+       echo Configuration name missing. 1>&2
+       echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+       echo "or     $0 ALIAS" 1>&2
+       echo where ALIAS is a recognized configuration type. 1>&2
+       exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+       *local*)
+               echo $1
+               exit 0
+               ;;
+       *)
+       ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  linux-gnu*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple)
+               os=
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+               | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
+               | hppa2.0w \
+               | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
+               | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+               | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+               | mipstx39 | mipstx39el | armv[34][lb] \
+               | sparc | sparclet | sparclite | sparc64 | v850)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i[34567]86)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+             | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
+             | hppa2.0w-* \
+             | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
+             | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+             | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+             | sparc64-* | mips64-* | mipsel-* | armv[34][lb]-*\
+             | mips64el-* | mips64orion-* | mips64orionel-*  \
+             | mipstx39-* | mipstx39el-* \
+             | f301-* | armv*-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-cbm
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-cbm
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-cbm
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [ctj]90-cray)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               os=-mpeix
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               os=-mpeix
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i[34567]86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i[34567]86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i[34567]86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i[34567]86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netwinder)
+               basic_machine=armv4l-corel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | nexen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | k6 | 6x86)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | nexen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | k6-* | 6x86-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=rs6000-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sparc)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -rhapsody* \
+             | -openstep* | -mpeix* | -oskit*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-corel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f301-fujitsu)
+               os=-uxpv
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..a138211
--- /dev/null
@@ -0,0 +1,147 @@
+#
+#  configure.in
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AC_INIT(includes/version.h)
+
+# Compiler settings
+CFLAGS="-Wall $CFLAGS"
+
+#
+# Put here any platform specific stuff
+#
+AC_CANONICAL_SYSTEM
+case "$target" in
+  *-*-linux*|*-*-mklinux*)
+    CFLAGS="-D_GNU_SOURCE $CFLAGS"
+    ;;
+  *)
+    ;;
+esac
+
+AM_INIT_AUTOMAKE(silc, 28062000)
+AC_PREREQ(2.3)
+AM_CONFIG_HEADER(includes/silcdefs.h)
+
+AC_PROG_CC
+AC_C_INLINE
+AC_C_CONST
+AC_ARG_PROGRAM
+
+AC_PROG_LN_S
+AC_SUBST(LN_S)
+
+# XXX
+# Compiler flags
+if test "$GCC"; then
+  CFLAGS="-finline-functions $CFLAGS"
+else
+  # Currently GCC is only supported compiler
+  AC_MSG_ERROR(GCC is only supported compiler currently)
+fi
+
+# Program checking
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PROG_MAKE_SET
+
+# Header checking
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_HEADER_STAT
+
+# More header checking
+AC_CHECK_HEADERS(unistd.h string.h getopt.h errno.h fcntl.h assert.h)
+AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/time.h)
+AC_CHECK_HEADERS(netinet/in.h netinet/tcp.h netdb.h)
+AC_CHECK_HEADERS(pwd.h grp.h termcap.h)
+AC_CHECK_HEADERS(ncurses.h signal.h ctype.h)
+AC_CHECK_HEADERS(arpa/inet.h sys/mman.h)
+
+# Data type checking
+AC_TYPE_SIGNAL
+AC_TYPE_SIZE_T
+AC_TYPE_MODE_T
+AC_TYPE_UID_T
+AC_TYPE_PID_T
+
+# Function checking
+AC_CHECK_FUNCS(chmod stat fstat getenv putenv strerror ctime gettimeofday)
+AC_CHECK_FUNCS(getpid getgid getsid getpgid getpgrp getuid)
+AC_CHECK_FUNCS(strchr strstr strcpy strncpy memcpy memset memmove)
+AC_CHECK_FUNCS(gethostname gethostbyname gethostbyaddr)
+AC_CHECK_FUNCS(select socket listen bind shutdown close connect)
+AC_CHECK_FUNCS(fcntl setsockopt)
+AC_CHECK_FUNCS(getservbyname getservbyport)
+AC_CHECK_FUNCS(getopt_long time)
+AC_CHECK_FUNCS(mlock munlock)
+
+# SIM support checking
+# XXX These needs to be changed as more supported platforms appear.
+# XXX This probably needs to be made platform dependant check.
+AC_CHECKING(for SIM support)
+AC_CHECK_HEADERS(dlfcn.h, 
+  AC_CHECK_LIB(dl, dlopen, 
+    AC_DEFINE(SILC_SIM) 
+    AC_MSG_RESULT(enabled SIM support)
+    LIBS="$LIBS -ldl",
+    AC_MSG_RESULT(no SIM support found)),
+  AC_MSG_RESULT(no SIM support found))
+
+# Debug checking
+AC_MSG_CHECKING(for enabled debugging)
+AC_ARG_ENABLE(debug,
+[  --enable-debug          Enable debugging (warning: it is heavy!)],
+[ case "${enableval}" in
+  yes) 
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(SILC_DEBUG)
+    CFLAGS="-O -g $CFLAGS"
+    ;;
+  *)
+    AC_MSG_RESULT(no)
+    CFLAGS="-O2 $CFLAGS"
+    ;;
+esac ], CFLAGS="-O2 $CFLAGS"
+        AC_MSG_RESULT(no))
+
+# XXX
+#LIBS="$LIBS -lefence"
+
+AC_ARG_WITH(silcd-config-file,
+[  --with-silcd-config-file[=PATH]
+                          Use PATH as default configuration file in SILC
+                          server.],
+[ AC_DEFINE_UNQUOTED(SILC_SERVER_CONFIG_FILE, "$withval") ])
+
+# Other configure scripts
+#AC_CONFIG_SUBDIRS(lib/zlib)
+AC_CONFIG_SUBDIRS(lib/silcmath/gmp-3.0.1)
+
+AC_OUTPUT( \
+Makefile
+doc/Makefile
+includes/Makefile
+lib/Makefile
+lib/silccore/Makefile
+lib/silccrypt/Makefile
+lib/silcmath/Makefile
+lib/silcsim/Makefile
+lib/silcsim/modules/Makefile
+lib/silcske/Makefile
+silc/Makefile
+silcd/Makefile)
diff --git a/doc/CodingStyle b/doc/CodingStyle
new file mode 100644 (file)
index 0000000..0393f34
--- /dev/null
@@ -0,0 +1,575 @@
+Coding Style in SILC source tree
+================================
+
+This documents describes the coding style and coding conventions used
+in the SILC source tree.  The purpose of the document is to describe the
+common way to program for SILC and thus should be learned when programming
+new code.  The document describes various conventions regarding variable
+naming, function naming, indentation, overall appearance of a piece of
+code and how some of the technical issues has been done in the SILC and
+should be done in the future.
+
+
+Naming
+======
+
+Generic naming
+
+All identifiers, whether they defines, functions or something else, with
+execption of variables, has a common naming convention.  Usually all 
+identifiers use `silc' prefix to indicate that the identifier is part of
+SILC distribution.  For example, silc_server_init(), SILC_PACKET_TYPE_ERROR, 
+etc.  As mentioned however, variables, local or global, does not use this
+naming convention.
+
+Lower lever routines, usually some library routines, may use their
+own naming convention if generic API is defined over them.  The API uses
+the common naming convention while the lower level routines uses what
+ever they want.  For example, ciphers are implemented currently in this
+way.  They define common SILC Cipher API but the actual implementation
+of algorithms uses their own naming convention.  Another example is
+the GMP math library that uses its own function naming but we have our
+own SILC MP API over it that has been defined using common SILC naming
+convention.
+
+
+Variables
+
+Variable names are always in lowercase and any mixed-case or totally
+uppercase variable names should be avoided.  Variable names may include
+underscore if it is necessary.  For example, `unsigned char *id_string;'.
+
+The same name convention is used in structure field names.  All fields
+in structures should be in lowercase.  Global variables should have some
+sort of prefix to indicate that the variable is global.  Although, global
+variables should be avoided if possible.
+
+Local variable names should be as short as possible without losing
+meaning of the name.  For example there is no reason to call loop
+counter as `loop_counter' when `i' is commonly used instead.  Using
+variable name `tmp' is also ok and should be used when some temporary
+value is used.
+
+
+#define's and Macros
+
+All #define's should always be in uppercase to indicate that it is
+a define, for example, `#define SILC_PACKET_TYPE_NONE 0'.  As mentioned
+previously #define's and macros always use the `SILC' prefix.  The
+names also uses always underscores.
+
+Names of #define's and macros should be self explanatory.  This may
+lead to long names but it is better than having some `#define SILC_KE1_SX'
+which does not tell you anything.
+
+
+Type definitions
+
+Type definitions (typedefs) uses some what different naming convention
+from variables and macros.  Typedefs has mixed-case names and they
+never use underscores.  For example, `SilcSomeStruct', `SilcServerObject'.
+Like in any other case the names should be self explanatory which may
+lead to long names but that is not a problem.
+
+The names should tell what the typedef is about.  If it is a typedef
+of a structure it should tell what the structure is for in the first
+place.  For example `SilcClientStruct', `SilcCipherObject', 
+`SilcConfigSection´, etc.
+
+
+Structures
+
+Same naming convention used in typedefs applies to names of structures as
+well.  Same as with typedef, structure names should be self explanatory
+and should tell what the structure is made for.
+
+Structures are used a lot in SILC.  They are used as simple structures
+and as objects as well.  When normal structures are needed they are
+defined as follows,
+
+       struct SilcDummyStruct {
+         unsigned char *dummy;
+       };
+
+And used as `struct SilcDummyStruct *dummy'.  However, this is quite
+rarely used in the SILC, instead structures are typedef'd as following
+later.  When structure is used as object they are defined as follows,
+
+       typedef struct SilcDummyStruct {
+         unsigned char *dummy;
+         unsigned int flags;
+         void (*callback)(void *, unsigned int);
+       } SilcDummyObject;
+
+If the SilcDummyStruct is not needed it may be omitted (which is very
+common in SILC code), leaving,
+
+       typedef struct {
+         unsigned char *dummy;
+         unsigned int flags;
+         void (*callback)(void *, unsigned int);
+       } SilcDummyObject;
+
+Finally, it is common that structures are typedef'd pointers as they
+are very flexible to use,
+
+       typedef SilcDummyObject *SilcDummy;
+
+It is common in SILC to typedef structures instead of defining name
+for the structure.  In this case the structure may be used without
+defining `struct' to the code, For example,
+
+       SilcDummyObject dummy_obj;
+       SilcDummyObject *dummy;
+
+If the structure has a pointer typedef then they are defined as normal
+variables but for real they are pointers, For example,
+
+       SilcDummy dummy;
+       dummy = silc_calloc(1, sizeof(*dummy));
+       dummy->flags = 0;
+
+This convention is very common in SILC code and has been used consistently
+throughout the code.  The pattern here is that all structures are named
+as `SilcXxxStruct', all objects are named as `SilcXxxObject' and when
+they are typedef'd pointers they are named as `SilcXxx'.
+
+
+Functions
+
+Function naming uses the common naming convention used in the SILC.  All
+functions are always lowercase and they use underscores.  The name of
+the function always starts with prefix `silc_'.  The name of the function
+should be self explanatory which may lead to long names.  The name of
+a function is constructed from following parts,
+
+       silc_<application>_<module>_<function>
+
+The <application> is for example <client> or <server>, however, it is
+always omitted (and must be omitted) when programming library code.
+
+The <module> is the module you are programming currently.  You should
+have a pretty good idea what you are programming and what the module
+does.  For example, <cipher>, <config>, <command>, <packet>, etc.
+
+The <function> is the describtion of the functionality of the function
+you are writing.  Naturally it should be self explanatory and weird
+short names should be avoided.  It is better to have long function
+names than some odd name that does not tell what it is about.  Function
+naming could be for example, <read>, <new_id>, <register>, <find_by_name>,
+etc.
+
+So, it is common in SILC to have function names, such as,
+
+       silc_server_packet_send
+       silc_server_packet_send_to_channel
+       silc_client_packet_process
+       silc_idcache_del_by_id
+       silc_task_unregister_by_fd
+       silc_protocol_excute_final
+       silc_buffer_alloc
+
+When function registers something the name of the function should
+generally be `silc_function_register' and unregistering should happen
+with `silc_function_unregister'.  When function allocates something it
+should be called `silc_function_alloc' and when freeing it should be
+called `silc_function_free'.  Respectively, with init/uninit functions.
+
+When this naming convention is used consistently it is easy to remember
+what the name of the function is.  For example, if you need buffer it
+is easy to figure out that the routines are most likely called 
+`silc_buffer_*',  and if you need to allocate buffer it is most likely 
+called `silc_buffer_alloc'.  This sort of naming makes the programming,
+in the long run, much cleaner, simpler and faster.
+
+
+Inline functions
+
+SILC uses quite a bit inline functions to optimize the code.  The
+naming of inline functions must follow same convention as any normal
+function.  All inline functions in SILC are defined and written into
+header files.  Inline functions must be defined in following manner
+in the header file,
+
+extern inline void silc_dummy_inline(unsigned int flags)
+{
+  doing_little_dummy_things;
+}
+
+Because the function is defined as extern they can be included into
+public header files.  Do not forget to define inline function as extern.
+There are no any explicit prototype definitions for inline functions.
+
+
+Indentation
+===========
+
+SILC has been coded with Emacs so standard indentation of Emacs is used
+in the SILC code.  The indentation is always 2 characters, not a 
+tabulator.  If you use Emacs then this should not be a problem.  So,
+if you code for SILC be sure to format the code to the standard way
+used in the SILC before submitting the code.
+
+A tip for those who think that these long function names etc are just
+too long to type, consider using dynamic abbreviation found in Emacs.
+With this cool feature you only have type some part of the string and
+then use the dabbrev to find the rest of the string.  I guess, by 
+default it is M-/ in Emacs but I have binded it into Shift-TAB so it
+is fast to use when typing.
+
+
+Placing Braces
+==============
+
+The common fight about how the braces should be placed in the C code
+is probably going on in the SILC code as well.  However, SILC code
+is consistent about this.  The placing uses K&R style thus the opening
+of the brace is put to the last on the line and the closing brace is
+on first on its own line,
+
+       if (condition) {
+         silc_something();
+         silc_something_more();
+       }
+
+The function's braces are as follows,
+
+       int silc_client_function()
+       {
+         return 0;
+       }
+
+More examples,
+
+       if (condition) {
+         something;
+         silc_something_more();
+       } else {
+         something_else;
+       }
+
+       if (condition) {
+         something;
+         silc_something_more();
+       } else if (other_condition) {
+         something;
+         silc_something_more();
+       } else {
+         something_else;
+       }
+
+
+Commenting
+==========
+
+SILC code is usually pretty well commented and this should be the way
+in the future as well.  However, the comments should not tell how the
+code works, it should be apparent by looking at the code.  Instead the
+commenting should tell what the function does.  All functions should
+be commented.  If nothing more a line of comment telling what the function
+is about helps a lot when you go back to it after six months.  Static
+functions should be commented as well.
+
+The commenting of functions in SILC has been made into the source files,
+and not in the header files where the function prototypes reside.  Header
+files usually includes structure comments, macro comments and perhaps
+some other relevant commenting but usually not function comments.
+It is also Ok to comment the code inside function when it is needed.
+
+Comments should use normal C-language comments /* */ and not C++ comments.
+
+
+General Appearance
+==================
+
+The code should be clean and good to eye, although the function of it
+must always superseed the appearance.  However, it is nice to read code
+that looks good.  Here are some issues on general appearance.
+
+       o Use empty lines when appropriate but not too much.  There
+         should not be excess empty lines at the end of file.  However,
+          using some empty lines in the code makes the code better 
+          looking.
+
+       o The line is 79 characters long and not one character longer.
+         Longer lines must be cut in two, or three, or ...
+
+       o Use spaces very much.  Do not write things like `if(!k)',
+         instead write `if (!k)'.  Same with `for', `while', etc.
+         Spaces should be put around all binary operators like `*', 
+         `==', `+', etc.  Also, when setting a value to variable be
+         sure to set spaces around `='.  When writing argument list 
+         to a function, space should follow each of the comma in the
+         list.  However, do not use spaces with parenthesis, for 
+         example, `if ( !k )' is not accepted.
+
+       o If you are not sure about how something should be done or
+         the code you've done is not finished, it should be commented
+         with XXX plus explanation what is going on.
+
+
+Source Files
+
+All source files starts with header that includes the name of the author,
+copyright notice and the copyright policy, usually part of GNU GPL licence.
+Now, if this really isn't that important but some sort of header should
+be in all source files.
+
+In the start of the source files should include the #include's that are
+needed.  All library source files must include `silcincludes.h', this is
+a must.  Client source file must include at least `clientincludes.h' and
+server source file must include `serverincludes.h'.  Additional include's
+may be added as well, however, system specific includes should not be
+added directly (unless it is really a special case).  Go see any source
+file as an example.
+
+
+Header Files
+
+As with source files, header files should include same file header at
+the start of the file.
+
+Header files are usually divided in three parts in SILC.  At the start
+of header files should include all definitions, typedefs, structure
+definitions etc.  After definitions should include macros and inline
+functions if any of those exist.  After macros should include the
+public prototypes of the functions.  Go see any header file as an example.
+
+
+Debug Messages
+==============
+
+When writing new code it is recommended that the code produces some sort
+of debug messages.  SILC has own debug logging system that must be used
+in the generic SILC code.  Few macros exist,
+
+       SILC_LOG_DEBUG
+       SILC_LOG_HEXDUMP
+       SILC_LOG_INFO
+       SILC_LOG_WARNING
+       SILC_LOG_ERROR
+       SILC_LOG_FATAL
+
+When doing debugging the most used macros are SILC_LOG_DEBUG and 
+SILC_LOG_HEXDUMP.  With first macro you can print out any sort of debug
+messages with variable argument list, for example,
+
+       SILC_LOG_DEBUG(("Start"));
+       SILC_LOG_DEBUG(("Packet length %d", packet_len));
+
+Note the extra parenthesis that are required for the macro so that the
+variable argument list formatting would work correctly.
+
+When you need to dump some data into screen you should use SILC_LOG_HEXDUMP
+macro.  For example,
+
+       SILC_LOG_HEXDUMP(("Packet"), packet->data, packet->len);
+       SILC_LOG_HEXDUMP(("Packet, size %d", size), packet->data, packet->len);
+
+In SILC_LOG_HEXDUMP the data to be dumped are set between the second last
+and last parenthesis in order that the data is first and the length of the
+data is next.  If arguments are used they are used the same way as in
+SILC_LOG_DEBUG and the data to be dumped are set after the argument list
+is closed with the parenthesis.
+
+
+Memory Allocation
+=================
+
+Naturally, memory allocation is a big part of SILC.  However, there are
+few things that must be noted on the issue.  SILC has defined its own
+memory allocation functions that must be used.  System specific functions
+must not be used directly.  There are functions like,
+
+       silc_malloc
+       silc_calloc
+       silc_realloc
+       silc_free
+
+You should always use silc_calloc instead of silc_malloc because
+silc_calloc automatically zeroes the allocated memory area.  This is
+imporant especially with structures because generally we want that all
+fields, by default, are zero.
+
+So, instead of doing
+
+       SilcStruct *ptr;
+
+       ptr = silc_malloc(sizeof(*ptr));
+
+You should do
+
+       SilcStruct *ptr
+
+       ptr = silc_calloc(1, sizeof(*ptr));
+
+
+When freeing memory it should be zero'ed when appropriate.  All memory
+allocations that handle sensitive data such as keys should be zero'ed
+by memset() before freeing the memory.  Common way to do is,
+
+       memset(ptr, 'F', sizeof(*ptr));
+       silc_free(ptr);
+
+Where 'F' indicates free'd memory if you ever check it with debugger.
+Other choice is to use 0 instead of 'F'.  The pointer after freeing 
+should be set to NULL if appropriate, ptr = NULL.
+
+Note that some functions in the SILC library handles the zeroing of
+the memory area automatically, like for example, silc_buffer_free.
+
+
+Callback Programming
+====================
+
+SILC uses pretty much programming convention called callback programming.
+This is a programming style that extensively uses function pointers
+which are usually called inside some other function.
+
+Typical scenario is this;  You are performing some task that most likely
+is asynchronous.  You need to be able get some structure context when
+the operation finishes.  Most common way in this case is to pass the
+structure context to the operation function with a callback function
+that is called when the operation has finished.  Following code explains
+probaly better.
+
+
+/* Prototypes */
+static silc_callback(void *context);
+void silc_start();
+void silc_async_operation_register(int fd, SilcAsyncCb callback, 
+                                   void *context);
+void silc_async_operation(int fd, SilcAsyncCb callback, void *context);
+
+/* Type definition of the callback function */
+typedef (*SilcAsyncCb)(void *context);
+
+/* Registers async operation and passes callback function and context
+   to it as arguments. */
+
+void silc_start()
+{
+  SilcDummyStruct *ctx;
+
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->fd = 30;
+
+  silc_async_operation_register(30, silc_callback, (void *)ctx);
+}
+
+/* The callblack function that is called from the operation function */
+
+static void silc_callback(void *context)
+{
+  SilcDummyStruct *ctx = (SilcDummyStruct *)context;
+
+  ctx->fd = 10;
+}
+
+/* Register async operation */
+
+void silc_async_operation_register(int fd, SilcAsyncCb callback, 
+                                   void *context)
+{
+  /* Register and return immediately */
+  silc_register_async_operation_internal(fd, callback, context);
+}
+
+/* Operation function that will call the callback function after it
+   has finished. */
+
+void silc_async_operation(int fd, SilcAsyncCb callback, void *context)
+{
+  here_this_function_does_what_ever_it_wants;
+
+  here_something_more;
+
+  /* We are finished, call the callback */
+  if (callback)
+    (*callback)(context);
+}
+       
+
+Now, after the registeration of the async operation in this dumb example
+the silc_start returns immediately.  Lets say, 10 seconds later the
+async operation is executed (it would have been better to call it just
+timeout) by calling silc_async_operation which on the other hand will
+call the callback function after it has finished.  The context that
+was passed to the registeration function is now passed back to the
+callback function.  Thus, you will get the context you wanted.  This is
+the typical scenario where callback functions come in very handy.  This 
+is also the best way to pass context's that are needed later without
+making them global context's.  And as long as the context's are defined
+as void * they can be what ever contexts making the functions, that
+takes in the context, generic.  Like in above example, you could pass
+what ever context to the registeration function if you'd want to.
+
+Callback programming is also used when making generic API's of some
+operation.  For example, if you want generic hooks to the API so that
+something could be done while doing the operation (maybe to collect
+statistics or something else) just get the functions accept a callback
+function and context and call them when appropriate, then continue
+as normally.
+
+Callback functions has been used a lot in SILC code.  The scheduler
+and task system implemented in core library uses extensively callback
+functions.  Timeout's uses callbacks as well.  SILC Key Exchange protocol
+uses callback functions too.  The callback function in SKE provides
+packet sending without defining into the SKE code how the packets
+should be sent thus making it generic for both client and server 
+(and actually to any application for that matter).
+
+There are some technical issues on callback programming that are
+common in SILC code.
+
+       o Callback functions are usually defined as void functions
+         as the routine that calls them usually don't care about
+         what the callback function does.  Many times it doesn't
+         actually know what it does nor would it be interested to
+         know that.  It doesn't care about return values.
+
+       o Many times the callback functions are static functions
+         because they are not wanted to be called in anyway else
+         than as callback functions.
+
+       o Callback function names usually have the `_cb' or `_callback'
+         at the end of function name, eg. silc_client_cb.
+
+       o Type of callback functions should be typedef'd instead of
+         defining them directly to the function.  See above example.
+         This makes the code much cleaner.
+
+       o Callback function types has usually the suffix `Cb' or
+         ´Callback' in the type name, eg. SilcAsyncCallback.
+
+       o You must explicitly cast the void * context's to correct
+         type in the callback function.  Of course you must be careful
+         to cast them to the correct type as they are void * they 
+         could be anything.  Many times this causes problems when you
+         forget what was the type you passed to it.  Callback 
+         programming may get very complex.
+
+       o You cannot use inline functions as callback functions,
+         naturally.
+
+Callback programming may be hard to understand from first standing if
+you haven't done these before, and debugging them may be pain in the
+ass sometimes.  But after the grand idea behind callback functions 
+becomes clear they are a wonderful tool.
+
+
+Copyrights of the Code
+======================
+
+The original code in SILC is GPL licensed.  GMP is GPL licensed as well
+and zlib is with free license as well.  New code will be accepted to
+the official SILC source tree if it is coded in GPL or similiar free
+license as GPL is, and of course if it is public domain.  Code with
+restricting licenses will not be accepted to the SILC source tree.
+SILC is free software, open source, what ever, project and will remain
+as such.
+
+Also, about authoring; If you write code to SILC don't forget to add
+yourself as author at the start of the file.  The reason for this is
+of course that everybody should get the credits they deserve but also 
+if problems occur we know who to blame. :)
diff --git a/doc/FAQ b/doc/FAQ
new file mode 100644 (file)
index 0000000..b6da030
--- /dev/null
+++ b/doc/FAQ
@@ -0,0 +1,90 @@
+Frequently Asked Questions
+
+
+Q: What is SILC?
+A: SILC (Secure Internet Live Conferencing) is a protocol which provides
+   secure conferencing services in the Internet over insecure channel.
+   SILC is IRC like although internally they are very different.  Biggest
+   similiarity between SILC and IRC is that they both provide conferencing
+   services and that SILC has almost same commands as IRC.  Other than
+   that they are nothing alike.
+
+   Biggest differences are that SILC is secure what IRC is not in any
+   way.  The network model is also entirely different compared to IRC.
+
+
+Q: Can I use SILC with IRC client?  What about can I use IRC with SILC
+   client?
+A: Answer for both question is no.  IRC client is in no way compatible
+   with SILC server.  SILC client cannot currenly use IRC but this may
+   change in the future if IRC support is added to the SILC client.  
+   After that one could use both SILC and IRC with the same client.
+   Although, even then one cannot talk from SILC network to IRC network.
+   That just is not possible.
+
+
+Q: How secure SILC really is?
+A: A good question which I don't have a answer.  SILC has been tried to
+   make as secure as possible.  However, there is no security protocol
+   or security software that has not been vulnerable to some sort of
+   attacks.  SILC is in no means different from this.  So, it is suspected 
+   that there are security holes in the SILC.  These holes just needs to 
+   be found so that they can be fixed.
+
+   But to give you some parameters of security SILC uses the most secure
+   crytographic algorithms such as Blowfish, RC5, Twofish, etc.  SILC
+   does not have DES or 3DES as DES is insecure and 3DES is just too
+   slow.  SILC also uses cryptographically strong random number generator
+   when it needs random numbers.  Public key cryptography uses RSA
+   and Diffie Hellman algorithms.  Key lengths for ciphers are initially
+   set to 128 bits but many algorithm supports longer keys.  For public
+   key algorithms the starting key length is 1024 bits.
+
+   But the best answer for this question is that SILC is as secure as
+   its weakest link.  SILC is open and the protocol is open and in public
+   thus open for security analyzes.
+
+   To give a list of attacks that are ineffective against SILC:
+
+      o Man-in-the-middle attacks are ineffective if proper public key
+        infrastructure is used.  SILC is vulnerable to this attack if
+        the public keys used in the SILC are not verified to be trusted.
+
+      o IP spoofing is ineffective (because of encryption and trusted 
+        server keys).
+
+      o Attacks that change the contents of the data or add extra
+        data to the packets are ineffective (because of encryption and
+        integrity checks).
+
+      o Passive attacks (listenning network traffic) are ineffective
+        (because of encryption).  Everything is encrypted including
+        authentication data such as passwords when they are needed.
+
+      o Any sort of cryptanalytic attacks are tried to make ineffective
+        by using the best cryptographic algorithms out there.
+
+
+Q: Why SILC? Why not IRC3?
+A: Question that is justified no doubt of that.  I didn't start doing SILC
+   to be replacement for IRC.  SILC was something that didn't exist in
+   1996 or even today except that SILC is now released.  However, I did
+   check out the IRC3 project in 1997 when I started coding and planning
+   the SILC protocol.
+
+   But, IRC3 is problematic. Why? Because it still doesn't exist.  The
+   project is at the same spot where it was in 1997 when I checked it out.
+   And it was old project back then as well.  Couple of months ago I 
+   checked it again and nothing were happening.  That's the problem of IRC3
+   project.  The same almost to happened to SILC as well as I wasn't making
+   real progress over the years.  I talked to the original author of IRC,
+   Jarkko Oikarinen, in 1997 and he directed me to the IRC3 project, 
+   although he said that IRC3 is a lot of talking and not that much of 
+   anything else.  I am not trying to put down the IRC3 project but its
+   problem is that no one in the project is able to make a decision what
+   is the best way to go about making the IRC3 and I wasn't going to be
+   part of that.  The fact is that if I would've gone to IRC3 project,
+   nor IRC3 or SILC would exist today.  I think IRC3 could be something
+   really great if they just would get their act together and start
+   coding the thing.  I hope that the release of SILC gives a boost to
+   the IRC3 project as well.
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..7f6fea8
--- /dev/null
@@ -0,0 +1,40 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+all:
+       touch draft-riikonen-silc-spec-00.txt
+       touch draft-riikonen-silc-pp-00.txt
+       touch draft-riikonen-silc-ke-auth-00.txt
+       -cd ..
+
+dist-hook:
+       -rm -f draft-riikonen*.txt
+       ./makerfc draft-riikonen-silc-spec-00.nroff \
+               draft-riikonen-silc-spec-00.txt
+       ./makerfc draft-riikonen-silc-pp-00.nroff \
+               draft-riikonen-silc-pp-00.txt
+       ./makerfc draft-riikonen-silc-ke-auth-00.nroff \
+               draft-riikonen-silc-ke-auth-00.txt
+
+EXTRA_DIST = \
+       CodingStyle \
+       example_silcd.conf \
+       example_silc.conf \
+       draft-riikonen*.txt
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..ed43946
--- /dev/null
@@ -0,0 +1,203 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+EXTRA_DIST = \
+       CodingStyle \
+       example_silcd.conf \
+       example_silc.conf \
+       draft-riikonen*.txt
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../includes/silcdefs.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+       $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+all:
+       touch draft-riikonen-silc-spec-00.txt
+       touch draft-riikonen-silc-pp-00.txt
+       touch draft-riikonen-silc-ke-auth-00.txt
+       -cd ..
+
+dist-hook:
+       -rm -f draft-riikonen*.txt
+       ./makerfc draft-riikonen-silc-spec-00.nroff \
+               draft-riikonen-silc-spec-00.txt
+       ./makerfc draft-riikonen-silc-pp-00.nroff \
+               draft-riikonen-silc-pp-00.txt
+       ./makerfc draft-riikonen-silc-ke-auth-00.nroff \
+               draft-riikonen-silc-ke-auth-00.txt
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/draft-riikonen-silc-ke-auth-00.nroff b/doc/draft-riikonen-silc-ke-auth-00.nroff
new file mode 100644 (file)
index 0000000..e4be714
--- /dev/null
@@ -0,0 +1,1038 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2000
+.ds CH Key Exchange and Authentication
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                      P. Riikonen
+Internet-Draft
+draft-riikonen-silc-ke-auth-00.txt                        27 June 2000
+Expires: 27 Jan 2001
+
+.in 3
+
+.ce
+SILC Key Exchange and Authentication Protocols
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft.  Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups.  Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other 
+documents at any time. It is inappropriate to use Internet-Drafts  
+as reference material or to cite them other than as 
+``work in progress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification internet-draft [SILC1].  The
+SILC Key Exchange (SKE) protocol provides secure key exchange between
+two parties resulting into shared secret key material.  The protocol
+is based on Diffie Hellman key exchange algorithm and its functionality
+is derived from several key exchange protocols.  SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol [OAKLEY].
+
+The SILC Connection Authentication protocol provides user level
+authentication used when creating connections in SILC network.  The
+protocol is transparent to the authentication data which means that it
+can be used to authenticate the user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+2 SILC Key Exchange Protocol ....................................  3
+  2.1 Key Exchange Payloads .....................................  3
+      2.1.1 Key Exchange Start Payload ..........................  4
+      2.1.2 Key Exchange 1 Payload ..............................  7
+      2.1.3 Key Exchange 2 Payload ..............................  9
+  2.2 Key Exchange Procedure .................................... 10
+  2.3 Processing the Key Material ............................... 12
+  2.4 SILC Key Exchange Groups .................................. 13
+      2.4.1 diffie-hellman-group1 ............................... 13
+      2.4.2 diffie-hellman-group2 ............................... 14
+  2.5 Key Exchange Status Types ................................. 14
+3 SILC Connection Authentication Protocol ....................... 16
+  3.1 Connection Auth Payload ................................... 17
+  3.2 Connection Authentication Types ........................... 18
+      3.2.1 Passphrase Authentication ........................... 18
+      3.2.2 Public Key Authentication ........................... 18
+  3.3 Connection Authentication Status Types .................... 19
+4 Security Considerations ....................................... 19
+5 References .................................................... 19
+6 Author's Address .............................................. 20
+
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:  Key Exchange Start Payload
+Figure 2:  Key Exchange 1 Payload
+Figure 3:  Key Exchange 2 Payload
+Figure 4:  Connection Auth Payload
+
+
+.ti 0
+1 Introduction
+
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification internet-draft [SILC1].  The
+SILC Key Exchange (SKE) protocol provides secure key exchange between
+two parties resulting into shared secret key material.  The protocol
+is based on Diffie Hellman key exchange algorithm and its functionality
+is derived from several key exchange protocols.  SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol.
+
+The SILC Connection Authentication protocol provides user level
+authentication used when creating connections in SILC network.  The
+protocol is transparent to the authentication data which means that it
+can be used to authenticate the user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+
+The basis of secure SILC session requires strong and secure key exchange
+protocol and authentication.  The authentication protocol is entirely
+secured and no authentication data is ever sent in the network without
+encrypting and authenticating it first.  Thus, authentication protocol
+may be used only after the key exchange protocol has been successfully
+completed.
+
+This document refers constantly to other SILC protocol specification
+Internet Drafts that are a must read for those who wants to understand
+the function of these protocols.  The most important references are
+the Secure Internet Live Conferencing, Protocol Specification [SILC1]
+and SILC Packet Protocol [SILC2] Internet Drafts.
+
+The protocol is intended to be used with the SILC protocol thus it
+does not define own framework that could be used.  The framework is
+provided by the SILC protocol.
+
+
+.ti 0
+2 SILC Key Exchange Protocol
+
+SILC Key Exchange Protocol (SKE) is used to exchange shared secret
+between connecting entities.  The result of this protocol is a key
+material used to secure the communication channel.  The protocol uses
+Diffie-Hellman key exchange algorithm and its functionality is derived
+from several key exchange protocols.  SKE uses best parts of the SSH2
+Key Exchange protocol, Station-To-Station (STS) protocol and the OAKLEY
+Key Determination protocol.  The protocol does not claim any conformance
+to any of these protocols, they were merely used as a reference when
+designing this protocol.
+
+The purpose of SILC Key Exchange protocol is to create session keys to
+be used in current SILC session.  The keys are valid only for some period
+of time (usually an hour) or at most until the session ends.  These keys
+are used to protect packets like commands, command replies and other
+communication between two entities.  If connection is server to server
+connection, the keys are used to protect all traffic between those
+servers.  In client connections usually all the packets are protected
+with this key except channel messages; channels has their own keys and 
+they are not exchanged with this protocol.
+
+
+.ti 0
+2.1 Key Exchange Payloads
+
+During the key exchange procedure public data is sent between initiator
+and responder.  This data is later used in the key exchange procedure.
+There are several payloads used in the key exchange.  As for all SILC
+packets, SILC Packet Header, described in [SILC2], is at the start of all
+packets, the same is done with these payloads as well.  All fields in
+all payloads are always in MSB (most significant byte first) order.
+Following descriptions of these payloads.
+
+
+.ti 0
+2.1.1 Key Exchange Start Payload
+
+Key exchange between two entities always begins with a
+SILC_PACKET_KEY_EXCHANGE packet containing Key Exchange Start Payload.
+When performing key exchange between client and server, the client sends
+Key Exchange Start Payload to server filled with all security properties
+that the client supports.  Server then checks if it supports the security
+properties.
+
+It then sends a Key Exchange Start Payload to client filled with security
+properties it selected from the payload client originally sent.  The
+payload sent by server must include only one chosen property per list.
+
+When performing key exchange between server and server, the server who
+is contacting sends the Key Exchange Start Payload with security property
+list it supports to the other server.  The contacted party then chooses
+the preferred properties same way as previously described.  It then
+replies with the properties it wanted same way as previously described.
+
+The Key Exchange Start Payload is used to tell connecting entities what
+security properties and algorithms should be used in the communication.
+If perfect forward secrecy (PFS) is not desired (PFS is undefined by
+default) Key Exchange Start Payload is sent only once per session, thus,
+for example, re-keying will not cause sending of a new payload.  If PFS
+is desired, re-keying will always cause new key exchange thus causes
+sending of a new Key Exchange Start Payload.
+
+When performing first key exchange this payload is never encrypted, as
+there are no existing keys to encrypt it with.  If performing re-keying
+(PFS was selected) this payload is encrypted with the existing key and
+encryption algorithm.
+
+Cookie is also send in this payload.  Cookie is used to uniform the
+payload so that none of the key exchange parties cannot determine this
+payload before hand.  The cookie must be returned to the original sender
+by the responder.
+
+Following diagram represents the Key Exchange Start Payload.  The lists
+mentioned below are always comma (`,') separated and the list must
+not include spaces (` ').
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   RESERVED    |     Flags     |         Payload Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
++                                                               +  
+|                                                               |
++                            Cookie                             +
+|                                                               |
++                                                               +
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Key Exchange Grp Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Key Exchange Groups                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        PKCS Alg Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         PKCS Algorithms                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Encryption Alg Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Encryption Algorithms                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Hash Alg Length         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Hash Algorithms                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|    Compression Alg Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                     Compression Algorithms                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 1:  Key Exchange Start Payload
+
+
+
+.in 6
+o RESERVED (1 byte) - Reserved field.  Sender fills this with
+  zeroes (0).
+
+o Flags (1 byte) - Indicates flags to be used in the key
+  exchange.  Several flags can be set at once by ORing the
+  flags together.  Following flags are reserved for this field.
+
+     No flags              0x00
+
+       In this case the field is ignored.
+
+     No Reply              0x01
+
+       If set the receiver of the payload does not reply to 
+       the packet.
+
+     PFS                   0x02
+
+       Perfect Forward Secrecy (PFS) to be used in the
+       key exchange protocol.  If not set, re-keying
+       is performed using the old key.  When PFS is used, 
+       re-keying and creating new keys for any particular 
+       purpose will cause new key exchange.
+
+       Rest of the flags are reserved for the future and
+       must not be set.
+
+o Payload Length (2 bytes) - Length of the entire Key Exchange
+  Start payload.
+
+o Cookie (16 bytes) - Cookie that uniforms this payload so
+  that each of the party cannot determine the payload before
+  hand.
+
+o Key Exchange Grp Length (2 bytes) - The length of the
+  key exchange group list, including this field as well.
+
+o Key Exchange Group (variable length) - The list of
+  key exchange groups.  See the section 2.1.2 SILC Key Exchange
+  Groups for definitions of these groups.
+
+o PKCS Alg Length (2 bytes) - The length of the PKCS algorithms
+  list, including this field as well.
+
+o PKCS Algorithms (variable length) - The list of PKCS 
+  algorithms.
+
+o Encryption Alg Length (2 bytes) - The length of the encryption
+  algorithms list, including this field as well.
+
+o Encryption Algorithms (variable length) - The list of
+  encryption algorithms.
+
+o Hash Alg Length (2 bytes) - The length of the Hash algorithms
+  list, including this field as well.
+
+o Hash Algorithms (variable length) - The list of Hash algorithms.
+
+o Compression Alg Length (2 bytes) - The length of the
+  compression algorithms list, including this field as well.
+
+o Compression Algorithms (variable length) - The list of 
+  compression algorithms.
+.in 3
+
+
+.ti 0
+2.1.2 Key Exchange 1 Payload
+
+Key Exchange 1 Payload is used to deliver computed public data from 
+initiator to responder.  This data is used to compute the shared secret,
+later by all parties.  Key Exchange 1 Payload is only sent after the 
+SILC_PACKET_KEY_EXCHANGE packet and the Key Exchange Start Payload has
+been processed by all the parties.
+
+This payload sends the initiator's public key to the responder.  Responder
+may need the public key in which case it should be checked to be trusted
+by the responder.
+The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_1 packet.
+It must not be sent in any other packet type.  Following diagram 
+represent the Key Exchange 1 Payload.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Key Length       |        Public Key Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~            Public Key of the Host (or certificate)            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Public Data Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                 Public Data (e = g ^ x mod p)                 ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2:  Key Exchange 1 Payload
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the public key
+  (or certificate), including this field and public key type
+  field as well.
+
+o Public Key Type (2 bytes) - The public key (or certificate) 
+  type.  This field indicates the type of the public key in 
+  the packet.  Following types are defined:
+
+     1    SILC style public key (mandatory)
+     2    SSH2 style public key (optional)
+     3    X.509 Version 3 certificate (optional)
+     4    OpenPGP certificate (optional)
+     5    SPKI certificate (optional)
+
+  The only required type to support is type number 1.  See 
+  [SILC1] for the SILC public key specification.  See
+  SSH public key specification in [SSH-TRANS].  See X.509v3
+  certificate specification in [PKIX-Part1].  See OpenPGP
+  certificate specification in [PGP].  See SPKI certificate
+  specification in [SPKI].  If this field includes zero (0)
+  or unsupported type number the protocol must be aborted
+  sending SILC_PACKET_FAILURE message.
+
+o Public Data Length (2 bytes) - The length of the public
+  data computed by the responder, including this field
+  as well.
+
+o Public Data (variable length) - The public data to be
+  sent to the responder.  See section 2.2 Key Exchange 
+  Procedure for detailed description how this field is
+  computed.  This value is binary encoded.
+.in 3
+
+
+.ti 0
+2.1.3 Key Exchange 2 Payload
+
+Key Exchange 2 Payload is used to deliver public key, computed public
+data and signature from responder to initiator.  Initiator uses these
+public parts of the key exchange protocol to compute the shared secret.
+
+The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_2 packet.
+It must not be sent in any other packet type.  Following diagram 
+represent the Key Exchange 2 Payload.
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Key Length       |        Public Key Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~            Public Key of the Host (or certificate)            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Data Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                 Public Data (f = g ^ y mod p)                 ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Signature Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Signature Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3:  Key Exchange 2 Payload
+
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the public key
+  (or certificate), including this field and public key type
+  field as well.
+
+o Public Key Type (2 bytes) - The public key (or certificate) 
+  type.  This field indicates the type of the public key in 
+  the packet.  See previous sections for defined public key
+  types.
+
+o Public Key of the host (variable length) - The public
+  key of the sender (or its certificate).  This is verified
+  by the receiver of the packet.  The type of this field
+  is indicated by previous Public Key Type field.
+
+o Public Data Length (2 bytes) - The length of the public
+  data computed by the responder, including this field
+  as well.
+
+o Public Data (variable length) - The public data computed
+  by the responder.  See section 2.2 Key Exchange Procedure
+  for detailed description how this field is computed.  This
+  value is binary encoded.
+
+o Signature Length (2 bytes) - The length of the signature,
+  including the length of this field as well.
+
+o Signature Data (variable length) - The signature signed
+  by the responder.  The receiver of this signature must
+  verify it.  The verification is done using the public
+  key received in this same payload.  See section 2.2
+  Key Exchange Procedure for detailed description how
+  to produce the signature.
+
+
+.ti 0
+2.2 Key Exchange Procedure
+
+The key exchange begins by sending SILC_PACKET_KEY_EXCHANGE packet with
+Key Exchange Start Payload to select the security properties to be used
+in the key exchange and later in the  communication.
+
+After Key Exchange Start Payload has been processed by both of the
+parties the protocol proceeds as follows:
+
+
+Setup:  p is a large and public safe prime.  This is one of the
+        Diffie Hellman groups.  q is order of subgroup (largest
+        prime factor of p).  g is a generator and is defined
+        along with the Diffie Hellman group.
+
+    1.  Initiator generates a random number x, where 1 < x < q, 
+        and computes e = g ^ x mod p.  The result e is then 
+        encoded into Key Exchange 1 Payload and sent
+        to the responder.
+
+
+    2.  Responder generates a random number y, where 1 < y < q,
+        and computes f = g ^ y mod p.  It then computes the
+        shared secret KEY = e ^ y mod p, and, a hash value 
+        HASH = hash(Key Exchange Start Payload data | Host public 
+        key (or certificate) | e | f | KEY).  It then signs
+        the HASH value with its private key resulting a signature
+        SIGN.  
+
+        It then encodes its public key (or certificate), f and 
+        SIGN into Key Exchange 2 Payload and sends it to the 
+        initiator.
+
+
+    3.  Initiator verifies that the public key provided in
+        the payload is authentic, or if certificates are used
+        it verifies the certificate.  Initiator may accept
+        the public key without verifying it, however, doing
+        so may result to insecure key exchange (accepting the
+        public key without verifying may be desirable for 
+        practical reasons on many environments.  For long term
+        use this is never desirable, in which case certificates
+        would be the preferred method to use).
+
+        Initiator then computes the shared secret KEY = 
+        f ^ x mod p, and, a hash value HASH in the same way as
+        responder did in phase 2.  It then verifies the 
+        signature SIGN from the payload with the hash value
+        HASH using the received public key.
+
+
+If any of these phases is to fail SILC_PACKET_FAILURE is sent to
+indicate that the key exchange protocol failed.  Any other packets must
+not be sent or accepted during the key exchange except the
+SILC_PACKET_KEY_EXCHANGE_*, SILC_PACKET_DISCONNECT, SILC_PACKET_FAILURE
+and/or SILC_PACKET_SUCCESS packets.
+
+The result of this protocol is a shared secret key material KEY and
+a hash value HASH.  The key material itself is not fit to be used as 
+a key, it needs to be processed further to derive the actual keys to be
+used.  The key material is also used to produce other security parameters
+later used in the communication.  See section 2.3 Processing the Key
+Material for detailed description how to process the key material.
+
+After the keys are processed the protocol is ended by sending the
+SILC_PACKET_SUCCESS packet.  Both entities send this packet to 
+each other.  After this both parties will start using the new keys.
+
+
+
+.ti 0
+2.3 Processing the Key Material
+
+Key Exchange protocol produces secret shared key material KEY.  This
+key material is used to derive the actual keys used in the encryption
+of the communication channel.  The key material is also used to derive
+other security parameters used in the communication.  Key Exchange
+protocol produces a hash value HASH as well.  This is used in the key
+deriving process as a session identifier.
+
+Keys are derived from the key material as follows:
+
+.in 6
+Sending Initial Vector (IV)     = hash(0 | KEY | HASH)
+Receiving Initial Vector (IV)   = hash(1 | KEY | HASH)
+Sending Encryption Key          = hash(2 | KEY | HASH)
+Receiving Encryption Key        = hash(3 | KEY | HASH)
+HMAC Key                        = hash(4 | KEY | HASH)
+.in 3
+
+
+The Initial Vector (IV) is used in the encryption when doing for
+example CBC mode.  As many bytes as needed are taken from the start of
+the hash output for IV.  Sending IV is for sending key and receiving IV
+is for receiving key.  For receiving party, the receiving IV is actually
+sender's sending IV, and, the sending IV is actually sender's receiving
+IV.  Initiator uses IV's as they are (sending IV for sending and
+receiving IV for receiving).
+
+The Encryption Keys are derived as well from the hash().  If the hash()
+output is too short for the encryption algorithm more key material is
+produced in following manner:
+
+.in 6
+K1 = hash(2 | KEY | HASH)
+K2 = hash(KEY | K1)
+K3 = hash(KEY | K1 | K2)  ...
+
+Sending Encryption Key = K1 | K2 | K3 ...
+
+
+K1 = hash(3 | KEY | HASH)
+K2 = hash(KEY | K1)
+K3 = hash(KEY | K1 | K2)  ...
+
+Receiving Encryption Key = K1 | K2 | K3 ...
+.in 3
+
+
+The key is distributed by hashing the previous hash with the original
+key material.  The final key is a concatenation of the hash values.
+For Receiving Encryption Key the procedure is equivalent.  Sending key
+is used only for encrypting data to be sent.  The receiving key is used
+only to decrypt received data.  For receiving party, the receive key is
+actually sender's sending key, and, the sending key is actually sender's
+receiving key.  Initiator uses generated keys as they are (sending key
+for sending and receiving key for sending).
+
+The HMAC key is used to create MAC values to packets in the communication
+channel.  As many bytes as needed are taken from the start of the hash
+output.
+
+These procedures are performed by all parties of the key exchange
+protocol.  This must be done before the protocol has been ended by
+sending the SILC_PACKET_SUCCESS packet.
+
+
+.ti 0
+2.4 SILC Key Exchange Groups
+
+Following groups may be used in the SILC Key Exchange protocol.  The 
+first group diffie-hellman-group1 is mandatory, other groups maybe 
+negotiated to be used in the connection with Key Exchange Start Payload
+and SILC_PACKET_KEY_EXCHANGE packet.  However, the first group must be
+proposed in the Key Exchange Start Payload regardless of any other
+requested group (however, it doesn't have to be the first on the list).
+
+
+.ti 0
+2.4.1 diffie-hellman-group1
+
+The length of this group is 1024 bits.  This is mandatory group.
+The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+
+Its decimal value is
+
+.in 6
+179769313486231590770839156793787453197860296048756011706444
+423684197180216158519368947833795864925541502180565485980503
+646440548199239100050792877003355816639229553136239076508735
+759914822574862575007425302077447712589550957937778424442426
+617334727629299387668709205606050270810842907692932019128194
+467627007
+.in 3
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
+FFFFFFFF FFFFFFFF
+.in 3
+
+
+The generator used with this prime is g = 2. The group order q is
+(p - 1) / 2.
+
+This group was taken from the OAKLEY specification.
+
+
+.ti 0
+2.4.2 diffie-hellman-group2
+
+The length of this group is 1536 bits.  This is optional group.
+The prime is 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }.
+
+Its decimal value is
+
+.in 6
+241031242692103258855207602219756607485695054850245994265411
+694195810883168261222889009385826134161467322714147790401219
+650364895705058263194273070680500922306273474534107340669624
+601458936165977404102716924945320037872943417032584377865919
+814376319377685986952408894019557734611984354530154704374720
+774996976375008430892633929555996888245787241299381012913029
+459299994792636526405928464720973038494721168143446471443848
+8520940127459844288859336526896320919633919
+.in 3
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
+.in 3
+
+The generator used with this prime is g = 2. The group order q is
+(p - 1) / 2.
+
+This group was taken from the OAKLEY specification.
+
+
+.ti 0
+2.5 Key Exchange Status Types
+
+This section defines all key exchange protocol status types that may be
+returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets to
+indicate the status of the protocol.  Implementations may map the
+status types to human readable error message.  All types except the
+SILC_SKE_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
+Following status types are defined:
+
+.in 6
+0   SILC_SKE_STATUS_OK
+
+    Protocol were exeucted succesfully.
+
+
+1   SILC_SKE_STATUS_ERROR
+
+    Unknown error occured.  No specific error type is defined.
+
+
+2   SILC_SKE_STATUS_BAD_PAYLOAD
+
+    Provided KE payload were malformed or included bad fields.
+
+
+3   SILC_SKE_STATUS_UNSUPPORTED_GROUP
+
+    None of the provided groups were supported.
+
+
+4   SILC_SKE_STATUS_UNSUPPORTED_CIPHER
+
+    None of the provided ciphers were supported.
+
+
+5   SILC_SKE_STATUS_UNSUPPORTED_PKCS
+
+    None of the provided public key algorithms were supported.
+
+
+6   SILC_SKE_STATUS_UNSUPPORTED_HASH_FUNCTION
+
+    None of the provided hash functions were supported.
+
+
+7   SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY
+
+    Provided public key type is not supported.
+
+
+8   SILC_SKE_STATUS_INCORRECT_SIGNATURE
+
+    Provided signature was incorrect.
+.in 3
+
+
+
+
+
+.ti 0
+3 SILC Connection Authentication Protocol
+
+Purpose of Connection Authentication protocol is to authenticate the
+connecting party with server.  Usually connecting party is client but
+server may connect to server as well.  Its other purpose is to provide
+information for the server about which type of connection this is.
+The type defines whether this is client, server or router connection.
+Server uses this information to create the ID for the connection.  After
+the authentication protocol has been successfully completed 
+SILC_PACKET_NEW_ID must be sent to the connecting party by the server.
+See section New ID Payload in [SILC2] for detailed description for this
+packet's payload.
+
+Server must verify the authentication data received and if it is to fail
+the authentication must be failed by sending SILC_PACKET_FAILURE packet.
+If everything checks out fine the protocol is ended by server by sending
+SILC_PACKET_SUCCESS packet.
+
+The protocol is executed after the SILC Key Exchange protocol.  It must
+not be executed in any other time.  As it is performed after key exchange
+protocol all traffic in the connection authentication protocol is
+encrypted with the exchanged keys.
+
+The protocol is started by the connecting party by sending
+SILC_PACKET_CONNECTION_AUTH packet with Connection Auth Payload,
+described in the next section.  This payload must include the
+authentication data.  Authentication data is set according
+authentication method that must be known by both parties. If connecting
+party does not know what is the mandatory authentication method it must
+request it from the server by sending SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet.  This packet is not part of this protocol and is described in
+section Connection Auth Request Payload in [SILC2].  However, if
+connecting party already knows the mandatory authentication method
+sending the request is not necessary.
+
+See [SILC1] and section Connection Auth Request Payload in [SILC2] also
+for the list of different authentication methods.  Authentication method
+may also be NONE, in which case the server does not require
+authentication at all.  However, in this case the protocol still must be
+executed; the authentication data just is empty indicating no
+authentication is required.
+
+If authentication method is passphrase the authentication data is
+plaintext passphrase.  As the payload is entirely encrypted it is safe
+to have plaintext passphrase.  3.2.1 Passphrase Authentication for
+more information.
+
+
+If authentication method is public key authentication the authentication
+data is signature of the hash value HASH plus Key Exchange Start Payload,
+established by the SILC Key Exchange protocol.  This signature must then
+be verified by the server.  See section 3.2.2 Public Key Authentication
+for more information.
+
+The connecting party of this protocol must wait after successful execution
+of this protocol for the SILC_PACKET_NEW_ID packet where it will receive
+the ID it will be using in the SILC network.  Connecting party cannot
+start normal SILC session (sending messages or commands) until it has
+received its ID.  The ID's are always created by the server except
+for server to server connection where servers create their own ID's.
+
+
+
+.ti 0
+3.1 Connection Auth Payload
+
+Client sends this payload to authenticate itself to the server.  Server
+connecting to another server also sends this payload.  Server receiving
+this payload must verify all the data in it and if something is to fail
+the authentication must be failed by sending SILC_PACKET_FAILURE packet.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH packet.
+It must not be sent in any other packet type.  Following diagram 
+represent the Connection Auth Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Payload Length         |        Connection Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                     Authentication Data                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+.ce
+Figure 4:  Connection Auth Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the entire Connection 
+  Auth Payload.
+
+o Connection Type (2 bytes) - Indicates the type of the 
+  connection.  See section Connection Auth Request Payload
+  in [SILC2] for the list of connection types.  This field must 
+  include valid connection type or the packet must be discarded 
+  and authentication must be failed. 
+
+o Authentication Data (variable length) - The actual 
+  authentication data.  Contents of this depends on the 
+  authentication method known by both parties.  If no
+  authentication is required this field does not exist.
+.in 3
+
+
+.ti 0
+3.2 Connection Authentication Types
+
+SILC supports two authentication types to be used in the connection
+authentication protocol; passphrase or public key based authentication.
+Following sections defines the authentication methods.  See [SILC2]
+for defined numerical authentication method types.
+
+
+.ti 0
+3.2.1 Passphrase Authentication
+
+Passphrase authentication or pre-shared-key base authentication is 
+simply an authentication where the party that wants to authenticate 
+itself to the other end sends the passphrase that is required by
+the other end, for example server.
+
+If the passphrase matches with the one in the server's end the
+authentication is successful.  Otherwise SILC_PACKET_FAILURE must be
+sent to the sender and the protocol execution fails.
+
+This is required authentication method to be supported by all SILC
+implementations.
+
+
+.ti 0
+3.2.2 Public Key Authentication
+
+Public key authentication may be used if passphrase based authentication
+is not desired.  The public key authentication works by sending a
+signature as authentication data to the other end, say, server.  The
+server must then verify the signature by the public key of the sender,
+which the server has received earlier in SKE protocol.
+
+The signature is computed using the private key of the sender by signing
+the HASH value provided by the SKE protocol previously, and the Key
+Exchange Start Payload from SKE protocol that was sent to the server.
+The server must verify the data, thus it must keep the HASH and the
+Key Exchange Start Payload saved during SKE and authentication protocols.
+
+If the verified signature matches the sent signature, the authentication
+were successful and SILC_PACKET_SUCCESS is sent.  If it failed the protocol
+execution is stopped and SILC_PACKET_FAILURE is sent.
+
+This is required authentication method to be supported by all SILC
+implementations.
+
+
+.ti 0
+3.3 Connection Authentication Status Types
+
+This section defines all connection authentication status types that
+may be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
+to indicate the status of the protocol.  Implementations may map the
+status types to human readable error message.  All types except the
+SILC_AUTH_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
+Following status types are defined:
+
+0   SILC_AUTH_OK
+
+    Protocol was executed succesfully.
+
+
+1   SILC_AUTH_FAILED
+
+    Authentication failed.
+
+
+.ti 0
+4 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+5 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, June 2000.
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             June 2000.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol", 
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key 
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exhange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+
+.ti 0
+6 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
diff --git a/doc/draft-riikonen-silc-pp-00.nroff b/doc/draft-riikonen-silc-pp-00.nroff
new file mode 100644 (file)
index 0000000..7f90743
--- /dev/null
@@ -0,0 +1,2317 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2000
+.ds CH SILC Packet Protocol
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                      P. Riikonen
+Internet-Draft
+draft-riikonen-silc-pp-00.txt                             27 June 2000
+Expires: 27 Jan 2001
+
+.in 3
+
+.ce
+SILC Packet Protocol
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft.  Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups.  Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other 
+documents at any time. It is inappropriate to use Internet-Drafts  
+as reference material or to cite them other than as 
+``work in progress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Packet Protocol used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification Internet Draft [SILC1].  This
+protocol describes the packet types and packet payloads which defines
+the contents of the packets.  The protocol provides secure binary packet
+protocol that assures that the contents of the packets are secured and
+authenticated.
+
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  3
+2 SILC Packet Protocol ..........................................  4
+  2.1 SILC Packet ...............................................  4
+  2.2 SILC Packet Header ........................................  5
+  2.3 SILC Packet Types .........................................  7
+      2.3.1 SILC Packet Payloads ................................ 15
+      2.3.2 Disconnect Payload .................................. 15
+      2.3.3 Success Payload ..................................... 16
+      2.3.4 Failure Payload ..................................... 16
+      2.3.5 Reject Payload ...................................... 17
+      2.3.6 Notify Payload ...................................... 17
+      2.3.7 Error Payload ....................................... 18
+      2.3.8 Channel Message Payload ............................. 19
+      2.3.9 Channel Key Payload ................................. 20
+      2.3.10 Private Message Payload ............................ 23
+      2.3.11 Private Message Key Payload ........................ 24
+      2.3.12 Command Payload .................................... 25
+             2.3.12.1 Command Argument Payload .................. 25
+      2.3.13 Command Reply Payload .............................. 26
+      2.3.14 Connection Auth Request Payload .................... 27
+      2.3.15 New ID Payload ..................................... 28
+      2.3.16 New ID List Payload ................................ 29
+      2.3.17 New Client Payload ................................. 29
+      2.3.18 New Server Payload ................................. 31
+      2.3.19 New Channel Payload ................................ 31
+      2.3.20 New Channel User Payload ........................... 32
+      2.3.21 New Channel List Payload ........................... 33
+      2.3.22 New Channel User List Payload ...................... 34
+      2.3.23 Replace ID Payload ................................. 34
+      2.3.24 Remove ID Payload .................................. 35
+  2.4 SILC ID Types ............................................. 36
+  2.5 Packet Encryption And Decryption .......................... 37
+      2.5.1 Normal Packet Encryption And Decryption ............. 37
+      2.5.2 Channel Message Encryption And Decryption ........... 37
+      2.5.3 Private Message Encryption And Decryption ........... 38
+  2.6 Packet MAC Generation ..................................... 39
+  2.7 Packet Padding Generation ................................. 39
+  2.8 Packet Compression ........................................ 40
+  2.9 Packet Sending ............................................ 40
+  2.10 Packet Reception ......................................... 41
+  2.11 Packet Broadcasting ...................................... 41
+  2.12 Packet Routing ........................................... 42
+  2.13 Packet Tunneling ......................................... 42
+3 Security Considerations ....................................... 43
+4 References .................................................... 43
+5 Author's Address .............................................. 44
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:   Typical SILC Packet
+Figure 2:   SILC Packet Header
+Figure 3:   Disconnect Payload
+Figure 4:   Success Payload
+Figure 5:   Failure Payload
+Figure 6:   Reject Payload
+Figure 7:   Notify Payload
+Figure 8:   Error Payload
+Figure 9:   Channel Message Payload
+Figure 10:  Channel Key Payload
+Figure 11:  Private Message Payload
+Figure 12:  Private Message Key Payload
+Figure 13:  Command Payload
+Figure 14:  Command Argument Payload
+Figure 15:  Connection Auth Request Payload
+Figure 16:  New ID Payload
+Figure 17:  New Client Payload
+Figure 18:  New Server Payload
+Figure 19:  New Channel Payload
+Figure 20:  New Channel User Payload
+Figure 21:  Replace ID Payload
+Figure 22:  Remove ID Payload
+
+
+.ti 0
+1. Introduction
+
+This document describes a Packet Protocol used in the Secure Internet
+Live Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification Internet Draft [SILC1].  This
+protocol describes the packet types and packet payloads which defines
+the contents of the packets.  The protocol provides secure binary packet
+protocol that assures that the contents of the packets are secured and
+authenticated.
+
+The basis of SILC protocol relies in the SILC packets and it is with
+out a doubt the most important part of the protocol.  It is also probably
+the most complicated part of the protocol.  Packets are used all the
+time in the SILC network to send messages, commands and other information.
+All packets in SILC network are always encrypted and their integrity
+is assured by computed MACs.  The protocol defines several packet types
+and packet payloads.  Each packet type usually has a specific packet
+payload that actually defines the contents of the packet.  Each packet
+also includes a default SILC Packet Header that provides sufficient
+information about the origin of the packet and destination of the
+packet.
+
+
+.ti 0
+2 SILC Packet Protocol
+
+.ti 0
+2.1 SILC Packet
+
+SILC packets deliver messages from sender to receiver securely by
+encrypting important fields of the packet.  The packet consists of
+default SILC Packet Header, Padding, Packet Payload data, and, packet 
+MAC.
+
+The following diagram illustrates typical SILC packet.
+
+
+.in 5
+.nf
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+|   n bytes   | 1 - n bytes |      n bytes       |  n bytes       
+| SILC Header |   Padding   |    Data Payload    |    MAC    
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.in 3
+
+.ce
+Figure 1:  Typical SILC Packet
+
+
+SILC Header is always the first part of the packet and its purpose
+is to provide information about the packet.  It provides for example
+the packet type, origin of the packet and the destination of the packet.
+The header is variable in length and first two (2) bytes of the
+header (thus first two bytes of the packet) are not encrypted.  The
+first two (2) bytes are the length of the packet which is not encrypted.
+See following section for description of SILC Packet header.  Packets
+without SILC header or with malformed SILC header must be dropped.
+
+Padding follows the packet header.  The purpose of the padding is to
+make the packet multiple by eight (8) or by the block size of the
+cipher used in the encryption, which ever is larger.  The maximum
+length of padding is currently 16 bytes.  The padding is always
+encrypted.
+
+Data payload area follows padding and it is the actual data of the
+packet.  The packet data is the packet payloads defined in this
+protocol.  The data payload area is always encrypted.
+
+The last part of SILC packet is the packet MAC that assures the
+integrity of the packet.  The MAC is always computed from the packet
+before the encryption is applied to the packet.  If compression is used
+in the packet the MAC is computed after the compression has been
+applied.  The compression, on the other hand, is always applied before
+encryption.
+
+All fields in all packet payloads are always in MSB (most significant
+byte first) order.
+
+
+.ti 0
+2.2 SILC Packet Header
+
+The default SILC packet header is applied to all SILC packets and it is
+variable in length.  The purpose of SILC Packet header is to provide
+detailed information about the packet.  The receiver of the packet uses
+the packet header to parse the packet and gain other relevant parameters
+of the packet.
+
+Following diagram represents the default SILC header format.
+(*) indicates that this field is never encrypted.  Other fields are
+always encrypted.
+
+
+.in 5
+.nf
+                      1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Payload Length *       |     Flags     |  Packet Type  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Source ID Length       |     Destination ID Length     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Src ID Type  |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                           Source ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Dst ID Type  |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                         Destination ID                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2:  SILC Packet Header
+
+
+.in 6
+o Payload Length (2 bytes) - Is the length of the packet
+  not including the padding of the packet.  This field must
+  not be encrypted but must always be authenticated.
+
+o Flags (1 byte) - Indicates flags to be used in packet
+  processing.  Several flags may be set by ORing the flags
+  together.
+
+  Following flags are reserved for this field:
+
+
+
+
+     No flags                  0x00
+
+       In this case the field is ignored.
+
+
+     Private Message Key       0x01
+
+       Indicates that the packet must include private
+       message that is encrypted using private key set by
+       client.  Servers does not know anything about this
+       key and this causes that the private message is
+       not handled by the server at all, it is just
+       passed along.  See section 2.5.3 Private Message
+       Encryption And Decryption for more information.
+
+
+     Broadcast                 0x02
+
+       Marks the packet to be broadcasted.  Client cannot
+       send broadcast packet and normal server cannot send
+       broadcast packet.  Only router server may send broadcast
+       packet.  The router receiving of packet with this flag 
+       set must send (broadcast) the packet to its primary
+       route.  If router has several router connections the
+       packet may be sent only to the primary route.  See
+       section 2.11 Packet Broadcasting for description of 
+       packet broadcasting.
+
+
+     Tunneled                  0x04
+
+       Marks that the packet is tunneled.  Tunneling means
+       that extra SILC Packet Header has been applied to the
+       original packet.  The outer header has this flag
+       set.  See section 2.13 Packet Tunneling for more
+       information.
+.in 3
+
+
+
+o Packet Type (1 byte) - Is the type of the packet. Receiver 
+  uses this field to parse the packet.  See section 2.3
+  SILC Packets for list of defined packet types.
+
+o Source ID Length (2 bytes) - Indicates the length of the
+  Source ID field in the header, not including this or any
+  other fields.
+
+
+
+o Destination ID Length (2 bytes) - Indicates the length of the
+  Destination ID field in the header, not including this or
+  any other fields.
+
+o Src ID Type (1 byte) - Indicates the type of ID in the
+  Source ID field.  See section 2.4 SILC ID Types for
+  defined ID types.
+
+o Source ID (variable length) - The actual source ID that
+  indicates who is the original sender of the packet.
+
+o Dst ID Type (1 byte) - Indicates the type of ID in the
+  Destination ID field.  See section 2.4 SILC ID Types for
+  defined ID types.
+
+o Destination ID (variable length) - The actual source ID that
+  indicates who is the end receiver of the packet.
+
+
+.ti 0
+2.3 SILC Packet Types
+
+SILC packet types defines the contents of the packet and it is used by
+the receiver to parse the packet.  The packet type is 8 bits, as a one
+byte, in length.  The range for the packet types are from 0 - 255,
+where 0 is never sent and 255 is currently reserved for future
+extensions and must not be defined to any other purpose.  Every SILC
+specification compliant implementation should support all of these packet
+types.
+
+The below list of the SILC Packet types includes reference to the packet
+payload as well.  Packet payloads are the actual packet, that is, the data
+that the packet consists of.  Each packet type defines packet payload 
+which usually may only be sent with the specific packet type.
+
+Most of the packets are packets that must be destined directly to entity
+that is connected to the sender.  It is not allowed, for example, for
+router to send disconnect packet to client that is not directly connected
+to the router.  However, there are some special packet types that may
+be destined to some entity that the sender has not direct connection
+with.  These packets are for example private message packets, channel
+message packets, command packets and some other packets that may be
+broadcasted in the SILC network.  If the packet is allowed to be sent to
+indirectly connected entity it is mentioned separately in the packet
+description (unless it is obvious as in private and channel message
+packets).  Other packets must not be sent or accepted, if sent, to
+indirectly connected entities.
+
+List of SILC Packet types are defined as follows.
+
+.in 1
+     0    SILC_PACKET_NONE
+
+          This type is reserved and it is never sent.         
+
+
+     1    SILC_PACKET_DISCONNECT
+
+          This packet is sent to disconnect the remote end.  Reason of
+          the disconnection is sent inside the packet payload.  Client
+          usually does not send this packet.
+
+          Payload of the packet:  See section 2.3.2 Disconnect Payload
+
+
+     2    SILC_PACKET_SUCCESS
+
+          This packet is sent upon successful execution of some protocol.
+          The status of the success is sent in the packet.
+
+          Payload of the packet:  See section 2.3.3 Success Payload
+
+
+     3    SILC_PACKET_FAILURE
+
+          This packet is sent upon failure of some protocol.  The status
+          of the failure is sent in the packet.
+
+          Payload of the packet:  See section 2.3.4 Failure Payload
+
+
+     4    SILC_PACKET_REJECT
+
+          This packet may be sent upon rejection of some protocol.
+          The status of the rejection is sent in the packet.
+
+          Payload of the packet:  See section 2.3.5 Reject Payload
+
+
+     5    SILC_PACKET_NOTIFY
+
+          This packet is used to send notify message, usually from
+          server to client, although it may be sent from server to another
+          server as well.  Client never sends this packet.  Server may
+          send this packet to channel as well when the packet is 
+          distributed to all clients on the channel.  Receiver of this 
+          packet may ignore the packet if it chooses so.  However, it 
+          should not be ignored.
+
+          Payload of the packet:  See section 2.3.6 Notify Payload.
+
+
+     6    SILC_PACKET_ERROR
+
+          This packet is sent when an error occurs.  Server may
+          send this packet.  Client never sends this packet.  The
+          client may entirely ignore the packet, however, server is
+          most likely to take action anyway.
+
+          Payload of the packet:  See section 2.3.7 Error Payload.
+
+
+     7    SILC_PACKET_CHANNEL_MESSAGE
+
+          This packet is used to send messages to channels.  The packet
+          includes Channel ID of the channel and the actual message to
+          the channel.  Messages sent to the channel are always protected
+          by channel specific keys.  Channel Keys are distributed by
+          SILC_PACKET_CHANNEL_KEY packet.
+
+          When client sends this packet the destination ID in the SILC 
+          header must be the Channel ID of the channel the message is 
+          destined to.  If server sends this packet to a client the 
+          destination ID in the SILC header must be the Client ID of 
+          the client receiving the packet.
+
+          If server sends this packet to router or if router sends this
+          packet to server or another router the destination ID in the
+          SILC header must be the Channel ID of the channel.  Server
+          (including router) distributes this packet only to its local
+          clients who are joined to the channel.  Servers and routers
+          also determines who are on the channel and when this packet
+          needs to be sent, as described in section Client To Client
+          in [SILC1].
+
+          Payload of the packet:  See section 2.3.8 Channel Message 
+                                  Payload
+
+
+     8    SILC_PACKET_CHANNEL_KEY
+
+          This packet is used to distribute new key for particular
+          channel.  Each channel has their own independent keys that
+          is used to protect the traffic on the channel.  Only server
+          may send this packet.  This packet may be sent to entity
+          that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.9 Channel Key Payload
+
+
+     9    SILC_PACKET_PRIVATE_MESSAGE
+
+          This packet is used to send private messages from client
+          to another client.  By default, private messages are protected
+          by session keys established by normal key exchange protocol.
+          However, it is possible to use specific key to protect private
+          messages.  SILC_PACKET_PRIVATE_MESSAGE_KEY packet is used to 
+          agree the key with the remote client.  Pre-shared key may be 
+          used as well if both of the client knows it, however, it needs 
+          to be agreed outside SILC.  See more of this in [SILC1].
+
+          Payload of the packet:  See section 2.3.10 Private Message
+                                  Payload
+
+
+     10   SILC_PACKET_PRIVATE_MESSAGE_KEY
+
+          This packet is used to agree about a key to be used to protect
+          the private messages between two clients.  If this is not sent
+          the normal session key is used to protect the private messages
+          inside SILC network.  Agreeing to use specific key to protect
+          private messages adds security, as no server between the two
+          clients will be able to decrypt the private message.  However,
+          servers inside SILC network are considered to be trusted, thus
+          using normal session key to protect private messages does not
+          degree security.  Whether to agree to use specific keys by
+          default or to use normal session keys by default, is 
+          implementation specific issue.  See more of this in [SILC1].
+
+          Payload of the packet:  See section 2.3.11 Private Message
+                                  Key Payload
+
+
+     11   SILC_PACKET_COMMAND
+
+          This packet is used to send commands from client to server.
+          Server may send this packet to other servers as well.  All
+          commands are listed in their own section SILC Command Types
+          in [SILC1].  The contents of this packet is command specific.
+          This packet may be sent to entity that is indirectly connected
+          to the sender.
+
+          Payload of the packet:  See section 2.3.12 Command Payload
+
+
+     12   SILC_PACKET_COMMAND_REPLY
+
+          This packet is send as reply to the SILC_PACKET_COMMAND packet.
+          The contents of this packet is command specific.  This packet
+          maybe sent to entity that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.13 Command Reply 
+                                  Payload and section 2.3.12 Command
+                                  Payload
+
+
+     13   SILC_PACKET_KEY_EXCHANGE
+
+          This packet is used to start SILC Key Exchange Protocol, 
+          described in detail in [SILC3].
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     14   SILC_PACKET_KEY_EXCHANGE_1
+
+          This packet is used as part of the SILC Key Exchange Protocol.
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     15   SILC_PACKET_KEY_EXCHANGE_2
+
+          This packet is used as part of the SILC Key Exchange Protocol.
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     16   SILC_PACKET_CONNECTION_AUTH_REQUEST
+
+          This packet is used to request the authentication method to
+          be used in the SILC Connection Authentication Protocol.  If 
+          initiator of the protocol does not know the mandatory 
+          authentication method this packet is used to determine it.
+
+          The party receiving this payload must respond with the same
+          packet including the mandatory authentication method.
+
+          Payload of the packet:  See section 2.3.14 Connection Auth
+                                  Request Payload
+
+
+     17   SILC_PACKET_CONNECTION_AUTH
+
+          This packet is used to start and perform the SILC Connection
+          Authentication Protocol.  This protocol is used to authenticate
+          the connecting party.  The protocol is described in detail in
+          [SILC3].
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Authentication
+                                  Protocol and it sub sections in [SILC].
+
+
+     18   SILC_PACKET_NEW_ID
+
+          This packet is used to distribute new ID's from server to
+          router and from router to all routers in the SILC network.
+          This is used when for example new client is registered to
+          SILC network.  The newly created ID's of these operations are
+          distributed by this packet.  Only server may send this packet,
+          however, client must be able to receive this packet.
+
+          Payload of the packet:  See section 2.3.15 New ID Payload
+
+
+     19   SILC_PACKET_NEW_ID_LIST
+
+          This packet is used to distribute list of new ID's from
+          server to routers.  This is equivalent to previous packet
+          type except that it may include several ID's.  Client must
+          not send this packet.
+
+          Payload of the packet:  See section 2.3.16 New ID List 
+                                  Payload
+
+
+     20   SILC_PACKET_NEW_CLIENT
+
+          This packet is used by client to register itself to the
+          SILC network.  This is sent after key exchange and 
+          authentication protocols has been completed.  Client sends
+          various information about itself in this packet.
+
+          Payload of the packet:  See section 2.3.17 New Client Payload
+
+
+     21   SILC_PACKET_NEW_SERVER
+
+          This packet is used by server to register itself to the
+          SILC network.  This is sent after key exchange and 
+          authentication protocols has been completed.  Server sends
+          this to the router it connected to, or, if router was
+          connecting, to the connected router.  Server sends
+          its Server ID and other information in this packet.
+          Client must not send or receive this packet.
+
+          Payload of the packet:  See section 2.3.18 New Server Payload
+
+
+     22   SILC_PACKET_NEW_CHANNEL
+
+          This packet is used to notify routers about newly created
+          channel.  Channels are always created by the router and it must
+          notify other routers about the created channel.  Router sends
+          this packet to its primary route.  Client must not send this
+          packet.  This packet maybe sent to entity that is indirectly
+          connected to the sender.
+
+          Payload of the packet:  See section 2.3.19 New Channel Payload
+
+
+     23   SILC_PACKET_NEW_CHANNEL_USER
+
+          This packet is used to notify routers about new user on channel.
+          The packet is sent after user has joined to the channel.  Server
+          may send this packet to its router and router may send this to
+          its primary router.  Client must not send this packet.  This
+          packet maybe sent to entity that is indirectly connected to the
+          sender.
+
+          Payload of the packet:  See section 2.3.20 New Channel User
+                                  Payload
+
+
+     24   SILC_PACKET_NEW_CHANNEL_LIST
+
+          This packet is used to distribute list of created channels
+          from server to routers.  This is equivalent to the packet
+          SILC_PACKET_NEW_CHANNEL except that it may include several
+          payloads. Client must not send this packet.
+
+          Payload of the packet:  See section 2.3.21 New Channel List
+                                  Payload
+
+
+     25   SILC_PACKET_NEW_CHANNEL_USER_LIST
+
+          This packet is used to distribute list of users on specific
+          channel from server to routers.  This is equivalent to the
+          packet SILC_PACKET_NEW_CHANNEL_USER except that it may
+          include several payloads.  Client must not send this packet.
+
+          Payload of the packet:  See section 2.3.22 New Channel User
+                                  List Payload
+
+
+     26   SILC_PACKET_REPLACE_ID
+
+          This packet is used to replace old ID with new ID sent in
+          the packet payload.  For example, when client changes its
+          nickname new ID is created and this packet can be used to
+          distribute the new ID and the old ID is removed when it is
+          send in the packet.  Client cannot send or receive this
+          packet.  This packet maybe sent to entity that is indirectly
+          connected to the sender.
+
+          Payload of the packet:  See section 2.3.23 Replace ID Payload
+
+
+     27   SILC_PACKET_REMOVE_ID
+
+          This packet is used to removed ID.  For example, when client
+          exits SILC network its ID is removed.  Client must not send
+          this packet.  This packet maybe sent to entity that is
+          indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.24 Remove ID Payload
+
+
+     28   SILC_PACKET_REKEY
+
+          This packet is used to indicate that re-key must be performed
+          for session keys.  See section Session Key Regeneration in
+          [SILC1] for more information.  This packet does not have
+          a payload.
+
+
+
+
+     29   SILC_PACKET_REKEY_DONE
+
+          This packet is used to indicate that re-key is performed and
+          new keys must be used hereafter.  This is sent only if re-key
+          was done without PFS option.  If PFS is set, this is not sent
+          as SILC Key Exchange protocol is executed.  This packet does
+          not have a payload.
+
+
+     30 - 254
+
+         Currently undefined commands.
+
+
+     255 SILC_PACKET_MAX
+
+         This type is reserved for future extensions and currently it 
+         is not sent.
+.in 3
+
+
+.ti 0
+2.3.1 SILC Packet Payloads
+
+All payloads resides in the main data area of the SILC packet.  However
+all payloads must be at the start of the data area after the default
+SILC packet header and padding.  All fields in the packet payload are
+always encrypted, as, they reside in the data area of the packet which
+is always encrypted.
+
+Payloads described in this section are common payloads that must be
+accepted anytime during SILC session.  Most of the payloads may only
+be sent with specific packet type which is defined in the description
+of the payload.
+
+There are a lot of other payloads in the SILC as well.  However, they
+are not common in the sense that they could be sent at any time. 
+These payloads are not described in this section.  These are payloads
+such as SILC Key Exchange payloads and so on.  These are described
+in [SILC1] and [SILC3].
+
+
+.ti 0
+2.3.2 Disconnect Payload
+
+Disconnect payload is sent upon disconnection.  The payload is simple;
+reason of disconnection is sent to the disconnected party.
+
+The payload may only be sent with SILC_PACKET_DISCONNECT packet.  It
+must not be sent in any other packet type.  Following diagram represents
+the Disconnect Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Disconnect Message                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3:  Disconnect Payload
+
+
+
+
+.in 6
+o Disconnect Message (variable length) - Human readable
+  reason of the disconnection.
+.in 3
+
+
+.ti 0
+2.3.3 Success Payload
+
+Success payload is sent when some protocol execution is successfully
+completed.  The payload is simple; indication of the success is sent.
+This maybe any data, including binary or human readable data.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Success Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4:  Success Payload
+
+
+.in 6
+o Success Indication (variable length) - Indication of
+  the success.  This maybe for example some flag that
+  indicates the protocol and the success status or human
+  readable success message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.4 Failure Payload
+
+This is opposite of Success Payload.  Indication of failure of
+some protocol is sent in the payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Failure Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  Failure Payload
+
+
+.in 6
+o Failure Indication (variable length) - Indication of
+  the failure.  This maybe for example some flag that
+  indicates the protocol and the failure status or human
+  readable failure message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.5 Reject Payload
+
+This payload is sent when some protocol is rejected to be executed.
+Other operations may send this as well that was rejected.  The
+indication of the rejection is sent in the payload.  The indication
+may be binary or human readable data.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Reject Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  Reject Payload
+
+
+.in 6
+o Reject Indication (variable length) - Indication of
+  the rejection.  This maybe for example some flag that
+  indicates the protocol and the rejection status or human
+  readable rejection message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.6 Notify Payload
+
+Notify payload is used to send notify messages.  The payload is usually
+sent from server to client, however, server may send it to another
+server as well.  Client must not send this payload.  The receiver of
+this payload may totally ignore the contents of the payload, however,
+notify message should be noted and possibly logged.
+
+The payload may only be sent with SILC_PACKET_NOTIFY packet.  It must
+not be sent in any other packet type.  Following diagram represents the
+Notify Payload.
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                        Notify Message                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 7:  Notify Payload
+
+
+.in 6
+o Notify Message (variable length) - Human readable notify
+  message.
+.in 3
+
+
+.ti 0
+2.3.7 Error Payload
+
+Error payload is sent upon error.  Error may occur in various
+conditions when server sends this packet.  Client may not send this
+payload but must be able to accept it.  However, client may
+totally ignore the contents of the packet as server is going to
+take action on the error anyway.  However, it is recommended
+that the client takes error packet seriously.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Error Message                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 8:  Error Payload
+
+
+.in 6
+o Error Message (variable length) - Human readable error
+  message.
+.in 3
+
+
+.ti 0
+2.3.8 Channel Message Payload
+
+Channel messages are the most common messages sent in the SILC.
+Channel Message Payload is used to send message to channels.  These
+messages can only be sent if client has joined to some channel.
+Even though this packet is the most common in SILC it is still
+special packet.  Some special handling on sending and reception
+of channel message is required.
+
+Padding must be applied into this payload since the payload is
+encrypted separately from other parts of the packet with the
+channel specific key.  Hence the requirement of the padding.  
+The padding should be random data.  The packet must be made
+multiple by eight (8) or by the block size of the cipher, which
+ever is larger.
+
+The SILC header in this packet is encrypted with the session key
+of the next receiver of the packet.  Nothing else is encrypted
+with that key.  Hence, the actual packet and padding to be
+encrypted with the session key is SILC Header plus padding to it
+to make it multiple by eight (8) or multiple by the block size
+of the cipher, which ever is larger.
+
+Receiver of the the channel message packet is able to determine
+the channel the message is destined to by checking the destination
+ID from the SILC Packet header which tells the destination channel.
+The original sender of the packet is also determined by checking
+the source ID from the header which tells the who client sent
+the message.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_MESSAGE packet.
+It  must not be sent in any other packet type.  Following diagram 
+represents the Notify Payload.
+
+(*) indicates that the field is not encrypted.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Nickname Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Nickname                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Message Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Message Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Padding Length         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                            Padding                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Initial Vector *                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 9:  Channel Message Payload
+
+
+.in 6
+o Nickname Length (2 bytes) - Indicates the length of the
+  Nickname field, not including any other field.
+
+o Nickname (variable length) - Nickname of the sender of the 
+  channel message.  This should not be trusted as a definite 
+  sender of the channel message.  The SILC Packet Header in 
+  the packet indicates the true sender of the packet and 
+  client should verify that the nickname sent here belongs 
+  to the Client ID in the SILC Packet Header.  This nickname 
+  is merely provided to be displayed by the client.
+
+  If server is sending this packet this field is not included
+  and zero (0) length must be set to the Nickname Length field.
+
+o Message Length (2 bytes) - Indicates the length of the
+  the Message Data field in the payload, not including any 
+  other field.
+
+
+o Message Data (variable length) - The actual message to
+  the channel.
+
+o Padding Length (2 bytes) - Indicates the length of the
+  Padding field in the payload, not including any other
+  field.
+
+o Padding (variable length) - The padding that must be
+  applied because this payload is encrypted separately from
+  other parts of the packet.
+
+o Initial Vector (variable length) - The initial vector
+  that has been used in packet encryption.  It needs to be
+  used in the packet decryption as well.  What this field
+  includes is implementation issue.  However, it is 
+  recommended that it would be random data or, perhaps,
+  a timestamp.  It is not recommended to use zero (0) as
+  initial vector.  This field is not encrypted.  This field
+  is not included into the padding calculation.  Length
+  of this field equals the cipher's block size.  This field
+  is, however, authenticated.
+.in 3
+
+
+.ti 0
+2.3.9 Channel Key Payload
+
+All traffic in channels are protected by channel specific keys.
+Channel Key Payload is used to distribute channel keys to all
+clients on the particular channel.  Channel keys are sent when
+the channel is created, when new user joins to the channel and
+whenever a user leaves a channel.  Server creates the new
+channel key and distributes it to the clients by encrypting this
+payload with the session key shared between the server and
+the client.  After that, client starts using the key received
+in this payload to protect the traffic on the channel.
+
+Channel keys are cell specific thus every router in cell have
+to create a channel key and distribute it if any client in the
+cell has joined to a channel.  Channel traffic between cell's
+are not encrypted using channel keys, they are encrypted using
+normal session keys between two routers.  Inside a cell, all
+channel traffic is encrypted with the specified channel key.
+Channel key should expire peridiocally, say, in one hour, in
+which case new channel key is created and distributed.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_KEY packet.
+It must not be sent in any other packet type.  Following diagram 
+represents the Channel Key Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Cipher Name Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Cipher Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel Key Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Channel Key                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 10:  Channel Key Payload
+
+
+
+.in 6
+o Channel ID Length (2 bytes) - Indicates the length of the
+  Channel ID field in the payload, not including any other
+  field.
+
+o Channel ID (variable length) - The Channel ID of the
+  channel this key is meant for.
+
+o Cipher Name Length (2 bytes) - Indicates the length of the
+  Cipher name field in the payload, not including any other
+  field.
+
+o Cipher Name (variable length) - Name of the cipher used
+  in the protection of channel traffic.  This name is
+  initially decided by the creator of the channel but it
+  may change during the life time of the channel as well.
+
+o Channel Key Length (2 bytes) - Indicates the length of the
+  Channel Key field in the payload, not including any other
+  field.
+
+o Channel Key (variable length) - The actual channel key
+  material.  This key is used as such as key material for
+  encryption function.
+.in 3
+
+
+.ti 0
+2.3.10 Private Message Payload
+
+Private Message Payload is used to send private message between
+two clients (or users for that matter).  The messages are sent only
+to the specified user and no other user inside SILC network is
+able to see the message.  The message is protected by the session 
+key established by the SILC Key Exchange Protocol.  However,
+it is also possible to agree to use specific keys to protect
+just the private messages.  See section 2.3.11 Private Message
+Key Payload for detailed description of how to agree to use
+specific key.
+
+If normal session key is used to protect the message, every
+server between the sender client and the receiving client needs
+to decrypt the packet and always re-encrypt it with the session
+key of the next receiver of the packet.  See section Client
+To Client in [SILC1].
+
+When specific key is used to protect the message, servers between 
+the sender and the receiver needs not to decrypt/re-encrypt the 
+packet.  Section 4.8.2 Client To Client in [SILC1] gives example of
+this scheme as well.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE 
+packet.  It must not be sent in any other packet type.  Following 
+diagram represents the Private Message Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Nickname Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                            Nickname                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                          Message Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 11:  Private Message Payload
+
+
+.in 6
+o Nickname Length (2 bytes) - Indicates the length of the
+  Nickname field, not including any other field.
+
+o Nickname (variable length) - Nickname of the sender of the 
+  private message.  This should not be trusted as a definite 
+  sender of the private message.  The SILC Packet Header in 
+  the packet indicates the true sender of the packet and 
+  client should verify that the nickname sent here belongs 
+  to the Client ID in the SILC Packet Header.  This nickname 
+  is merely provided to be displayed by the client.
+
+o Message Data (variable length) - The actual message to
+  the client.  Rest of the packet is reserved for the message
+  data.
+.in 3
+
+
+.ti 0
+2.3.11 Private Message Key Payload
+
+This payload is used to send key from client to another client that
+is going to be used to protect the private messages between these
+two clients.  If this payload is not sent normal session key 
+established by the SILC Key Exchange Protocol is used to protect
+the private messages.
+
+This payload may only be sent by client to another client.  Server
+must not send this payload at any time.  After sending this payload
+the sender of private messages must set the Private Message Key
+flag into SILC Packet Header.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE_KEY 
+packet.  It must not be sent in any other packet type.  Following 
+diagram represents the Private Message Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Private Message Key Length   |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Private Message Key                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 12:  Private Message Key Payload
+
+
+
+
+.in 6
+o Private Message Key Length (2 bytes) - Indicates the length 
+  of the Private Message Key field in the payload, not including 
+  any other field.
+
+o Private Message Key (variable length) - The actual private
+  message key material.  This key is used as such as key material 
+  for encryption function.
+.in 3
+
+
+.ti 0
+2.3.12 Command Payload
+
+Command Payload is used to send SILC commands from client to server.  
+Following diagram represents the Command Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| SILC Command  | Arguments Num |         Payload Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 13:  Command Payload
+
+
+.in 6
+o SILC Command (1 byte) - SILC Command identifier.  This must 
+  be set to non-zero value.  If zero (0) value is found in this 
+  field the packet must be discarded.
+
+o Arguments Num (1 byte) - Indicates the number of arguments
+  associated with the command.  If there are no arguments this
+  field is set to zero (0).  The arguments must follow the 
+  command payload.
+
+o Payload Length (2 bytes) - Length of the entire command 
+  payload including any command argument payloads associated 
+  with this payload.
+.in 3
+
+See [SILC1] for detailed description of different SILC commands,
+their arguments and their reply messages.
+
+
+.ti 0
+2.3.12.1 Command Argument Payload
+
+Command Argument Payload is used to set arguments for SILC commands.
+Number of arguments associated with a command are indicated by the
+Command Payload in the Arguments Num field.  Command argument 
+payloads may only be used with a command payload and they must 
+always reside right after the command payload.  Incorrect amount of
+argument payloads must cause rejection of the packet.  Following 
+diagram represents the Command Argument Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Argument Num | Argument Type |         Payload Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                        Argument Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 14:  Command Argument Payload
+
+
+.in 6
+o Argument Num (1 byte) - Indicates the number of this argument.
+  For first argument this is set to 1, for second argument this
+  is set to 2, and so forth.  If incorrect value is found 
+  in this field the packet must be discarded.  Value is 
+  incorrect if it is zero (0) or, for example, a third argument
+  does not include value 3.
+
+o Argument Type (1 byte) - Indicates the type of the argument.  
+  Every command specify a number for each argument that maybe 
+  associated with the command.  By using this number the receiver 
+  of the packet knows what type of argument this is.  The numbers 
+  are command specific and has been defined in section SILC
+  Commands in [SILC1].  This field makes it possible to send
+  arguments in free order as this field is used to identify
+  the specific type of the argument.
+
+o Payload Length (2 bytes) - Length of the argument payload data 
+  area not including the length of any other fields in the 
+  payload.
+
+o Argument Data (variable length) - Argument data.
+.in 3
+
+
+.ti 0
+2.3.13 Command Reply Payload
+
+Command Reply Payload is used to send replies to the commands sent
+by the client.  The Command Reply Payload is identical to the
+Command Payload hence see the upper sections for Command Payload
+and for Command Argument Payload specifications.  Command Reply
+message uses the Command Argument Payload as well.
+
+See SILC Commands in [SILC1] for detailed description of different
+SILC commands, their arguments and their reply messages.
+
+
+.ti 0
+2.3.14 Connection Auth Request Payload
+
+Client may send this payload to server to request the authentication
+method that must be used in authentication protocol.  If client knows 
+this information beforehand this payload is not necessary to be sent.
+Server performing authentication with another server may also send
+this payload to request the authentication method.  If the connecting
+server already knows this information this payload is not necessary
+to be sent.
+
+Server receiving this request must reply with same payload sending
+the mandatory authentication method.  Algorithms that may be required
+to be used by the authentication method are the ones already 
+established by the SILC Key Exchange protocol.  See section Key
+Exchange Start Payload in [SILC3] for detailed information.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet.  It must not be sent in any other packet type.  Following 
+diagram represents the Connection Auth Request Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Connection Type        |     Authentication Method     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 15:  Connection Auth Request Payload
+
+
+.in 6
+o Connection Type (2 bytes) - Indicates the type of the ID.
+  Following connection types are defined:
+
+     1    Client connection
+     2    Server connection
+     3    Router connection
+
+  If any other type is found in this field the packet must be
+  discarded and the authentication must be failed.
+
+o Authentication Method (2 bytes) - Indicates the authentication
+  method to be used in the authentication protocol.  Following
+  authentication methods are defined:
+
+
+
+     0    NONE        (mandatory)
+     1    password    (mandatory)
+     2    public key  (mandatory)
+
+  If any other type is found in this field the packet must be
+  discarded and the authentication must be failed.  If this
+  payload is sent as request to receive the mandatory 
+  authentication method this field must be set to zero (0),
+  indicating that receiver should send the mandatory 
+  authentication method.  The receiver sending this payload
+  to the requesting party, may also set this field to zero (0) 
+  to indicate that authentication is not required.  In this
+  case authentication protocol still must be started but
+  server is most likely to respond with SILC_PACKET_SUCCESS
+  immediately.
+.in 3
+
+
+.ti 0
+2.3.15 New ID Payload
+
+New ID Payload is a multipurpose payload.  It is used to send newly 
+created ID's from clients and servers.  When client connects to server
+and registers itself to the server by sending SILC_PACKET_NEW_CLIENT
+packet, server replies with this packet by sending the created ID for
+the client.  Server always creates the ID for the client.
+
+This payload is also used when server tells its router that new client
+has registered to the SILC network.  In this case the server sends
+the Client ID of the client to the router.  Similiary when router
+distributes information to other routers about the client in the SILC
+network this payload is used.  
+
+Also, when server connects to router, router uses this payload to inform
+other routers about new server in the SILC network.  However, every 
+server (or router) creates their own ID's thus the ID distributed by 
+this payload is not created by the distributor in this case.  Servers
+create their own ID's.  Server registers itself to the network by sending
+SILC_PACKET_NEW_SERVER to the router it connected to.  The case is same
+when router connects to another router.
+
+Hence, this payload is very important and used every time when some
+new entity is registered to the SILC network.  Client never sends this
+payload.  Both client and server (and router) may receive this payload.
+
+The payload may only be sent with SILC_PACKET_NEW_ID packet.  It must
+not be sent in any other packet type.  Following diagram represents the
+New ID Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|             ID Type           |           ID Length           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                           ID Data                             ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 16:  New ID Payload
+
+
+.in 6
+o ID Type (2 bytes) - Indicates the type of the ID.  See 
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o ID Length (2 bytes) - Length of the ID Data area not 
+  including the length of any other fields in the payload.
+
+o ID Data (variable length) - The actual ID data.
+.in 3
+
+
+
+.ti 0
+2.3.16 New ID List Payload
+
+New ID List Payload is used to distribute list of ID's usually from 
+server to router but also from router to other routers in the network.
+This payload is used, for example, when server is connected to router
+and the server wants to distribute all of its locally connected clients
+and locally created channels to the router.  It is convenient in this
+case to use this payload instead of sending all the information one
+by one using New ID Payload.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in previous section.  To form a list
+several payloads is put in the packet each after each.  The payload
+is variable in length but can be calculated by calculating the ID
+Type field, Length field and the ID Data fields together.  This forms
+one New ID Payload in the list.
+
+The list of payloads may only be sent with SILC_PACKET_NEW_ID_LIST
+packet.  They must not be sent in any other packet type.
+
+
+.ti 0
+2.3.17 New Client Payload
+
+When client is connected to the server, keys has been exchanged and
+connection has been authenticated client must register itself to the 
+server.  Clients first packet after key exchange and authentication 
+protocols must be SILC_PACKET_NEW_CLIENT.  This payload tells server all
+the relevant information about the connected user.  Server creates a new
+client ID for the client when received this payload and sends it to the
+client in New ID Payload.
+
+This payload sends username and real name of the user on the remote host
+which is connected to the SILC server with SILC client.  The server 
+creates the client ID according the information sent in this payload.
+The nickname of the user becomes the username sent in this payload.
+However, client should call NICK command after sending this payload to
+set the real nickname of the user which is then used to create new 
+client ID.
+
+The payload may only be sent with SILC_PACKET_NEW_CLIENT packet.  It
+must not be sent in any other packet type.  Following diagram represents
+the New Client Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Username Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Username                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Real Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Real Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 17:  New Client Payload
+
+
+.in 6
+o Username Length (2 bytes) - Length of the username.
+
+o Username (variable length) - The username of the user on
+  the host where connecting to the SILC server.
+
+o Real Name Length (2 bytes) - Length of the Real Name.
+
+o Real Name (variable length) - The real name of the user
+  on the host where connecting to the SILC server.
+.in 3
+
+
+.ti 0
+2.3.18 New Server Payload
+
+This payload is sent by server when it has completed successfully both
+key exchange and connection authentication protocols.  The server
+uses this payload to register itself to the SILC network.  The
+first packet after these key exchange and authentication protocols
+is SILC_PACKET_NEW_SERVER packet.  The payload includes the Server ID
+of the server that it has created by itself.  It also includes a
+name of the server that is associated to the Server ID.
+
+The payload may only be sent with SILC_PACKET_NEW_SERVER packet.  It
+must not be sent in any other packet type.  Following diagram represents
+the New Server Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Server ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Server ID Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Server Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Server Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 18:  New Server Payload
+
+
+.in 6
+o Server ID Length (2 bytes) - Length of the ID Data area not 
+  including the length of any other fields in the payload.
+
+o Server ID Data (variable length) - The actual Server ID
+   data.
+
+o Server Name Length (2 bytes) - Length of the server name.
+
+o Server Name (variable length) - The server name.
+.in 3
+
+
+.ti 0
+2.3.19 New Channel Payload
+
+Information about newly created channel is broadcasted to all routers
+in the SILC network by sending this packet payload.  Channels are
+created by router of the cell.  Server never creates channels unless
+it is a standalone server and it does not have router connection,
+in this case server acts as router.  Normal server sends JOIN command
+to the router (after it has received JOIN command from client) which
+then processes the command and creates the channel.  Client never sends
+this packet.
+
+The payload may only be sent with SILC_PACKET_NEW_CHANNEL packet.
+It must not be sent in any other packet type.  Following diagram
+represents the New Channel Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel Name Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Channel Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 19:  New Channel Payload
+
+
+
+.in 6
+o Channel Name Length (2 bytes) - Length of the channel name.
+
+o Channel Name (variable length) - The name of the created
+  channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID.
+
+o Channel ID (variable length) - The created Channel ID.
+.in 3
+
+
+.ti 0
+2.3.20 New Channel User Payload
+
+When client (user) joins to a channel, server must notify routers
+about the new user on the channel.  Normal server sends this packet
+payload to its router which then broadcasts the packet further.
+Router sends this packet always to its primary router.  Client must
+not send this packet payload.  The mode of the user is NONE after 
+user has joined to the channel.
+
+The payload may only be sent with SILC_PACKET_NEW_CHANNEL_USER 
+packet.  It must not be sent in any other packet type.  Following 
+diagram represents the New Channel User Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Client ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Client ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 20:  New Channel User Payload
+
+
+.in 6
+o Channel ID Length (2 bytes) - Length of the Channel ID.
+
+o Channel ID (variable length) - The Channel ID of the channel
+  to which the client has joined.
+
+o Client ID Length (2 bytes) - Length of the Client ID.
+
+o Client ID (variable length) - The Client ID of the client
+  who has joined the channel.
+.in 3
+
+
+.ti 0
+2.3.21 New Channel List Payload
+
+This payload is used to distribute list of new channels from server
+to routers.  It might convenient to send list of new channels when
+existing server connects to router, instead of sending them one
+by one.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in 2.3.19 New Channel Payload.  To form
+a list several payloads is put in the packet each after each.  The
+payload is variable in length but can be calculated by calculating
+the length of the fields together.  This forms one New Channel Payload
+in the list.
+
+The list of payloads may only be sent with SILC_PACKET_NEW_CHANNEL_LIST
+packet.  They must not be sent in any other packet type.
+
+
+.ti 0
+2.3.22 New Channel User List Payload
+
+This payload is used to distribute list of channel users on specific
+channel from server to routers.  It might convenient to send list of
+channel users when existing server connects to router, instead of
+sending them one by one.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in 2.3.20 New Channel User Payload.
+To form a list several payloads is put in the packet each after each.
+The payload is variable in length but can be calculated by calculating
+the length of the fields together.  This forms one New Channel User
+Payload in the list.
+
+The list of payloads may only be sent with packet
+SILC_PACKET_NEW_CHANNEL_USER_LIST. They must not be sent in any other
+packet type.
+
+
+.ti 0
+2.3.23 Replace ID Payload
+
+This payload is used to replace old ID with new ID sent in the payload.
+When ID changes for some entity and the new ID is wanted to replace the
+old one this payload must be used.  Client cannot send or receive this
+payload.  Normal server and router server may send and receive this
+payload.  After this packet has been sent the old ID must not be used
+anymore.
+
+The payload may only be sent with SILC_PACKET_REPLACE_ID packet.  It must
+not be sent in any other packet type.  Following diagram represents the 
+Replace Payload Payload.
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          Old ID Type          |         Old ID Length         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Old ID Data                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          New ID Type          |         New ID Length         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         New ID Data                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 21:  Replace ID Payload
+
+
+.in 6
+o Old ID Type (2 bytes) - Indicates the type of the old ID.  See 
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o Old ID Length (2 bytes) - Length of the old ID Data area not 
+  including the length of any other fields in the payload.
+
+o Old ID Data (variable length) - The actual old ID data.
+
+o New ID Type (2 bytes) - Indicates the type of the new ID.  See 
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o New ID Length (2 bytes) - Length of the new ID Data area not 
+  including the length of any other fields in the payload.
+
+o New ID Data (variable length) - The actual new ID data.
+.in 3
+
+
+.ti 0
+2.3.24 Remove ID Payload
+
+Remove ID payload is used to remove ID from SILC network.  This is used
+for example when client exits SILC network.  The server must in this
+case send this payload to notify that this ID is not valid anymore.
+After this has been send the old ID must not be used anymore.  Client
+must not send this payload.
+
+The payload may only be sent with SILC_PACKET_REMOVE_ID packet.  It must
+not be sent in any other packet type.  Following diagram represents the 
+Remove Payload Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|            ID Type            |           ID Length           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                            ID Data                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 22:  Remove ID Payload
+
+
+.in 6
+o ID Type (2 bytes) - Indicates the type of the ID to be
+  removed.  See section 2.4 SILC ID Types for list of defined
+  ID types.
+
+o ID Length (2 bytes) - Length of the D Data area not including
+  the length of any other fields in the payload.
+
+o ID Data (variable length) - The actual ID data to be removed.
+.in 3
+
+
+.ti 0
+2.4 SILC ID Types
+
+ID's are extensively used in the SILC network to associate different
+entities.  Following ID's has been defined to be used in the SILC
+network.
+
+.in 6
+0    No ID
+
+   When ever specific ID cannot be used this is used.
+
+1    Server ID
+
+   Server ID to associate servers.  See the format of
+   this ID in [SILC1].
+
+2    Client ID
+
+   Client ID to associate clients.  See the format of
+   this ID in [SILC1].
+
+3    Channel ID
+
+   Channel ID to associate channels.  See the format of
+   this ID in [SILC1].
+.in 3
+
+
+.ti 0
+2.5 Packet Encryption And Decryption
+
+SILC packets are encrypted almost entirely.  Only small part of SILC
+header is not encrypted as described in section 5.2 SILC Packet Header.
+The SILC Packet header is the first part of a packet to be encrypted
+and it is always encrypted with the key of the next receiver of the
+packet.  The data payload area of the packet is always entirely 
+encrypted and it is usually encrypted with the next receiver's key.
+However, there are some special packet types and packet payloads
+that require special encryption process.  These special cases are
+described in the next sections.  First is described the normal packet
+encryption process.
+
+
+.ti 0
+2.5.1 Normal Packet Encryption And Decryption
+
+Normal SILC packets are encrypted with the session key of the next
+receiver of the packet.  The entire SILC Packet header and the packet
+data payload is is also encrypted with the same key.  Padding of the
+packet is also encrypted always with the session key, also in special
+cases.  Computed MAC of the packet must not be encrypted.
+
+Decryption process in these cases are straightforward.  The receiver
+of the packet must first decrypt the SILC Packet header, or some parts
+of it, usually first 16 bytes of it.  Then the receiver checks the
+packet type from the decrypted part of the header and can determine
+how the rest of the packet must be decrypted.  If the packet type is
+any of the special cases described in following sections the packet
+decryption is special.  If the packet type is not among those special
+packet types rest of the packet may be decrypted with the same key.
+
+Also, note that two bytes of the SILC Packet header are not encrypted
+thus it must be noticed in the decryption process by starting the
+decryption from the second byte of the header.  This sets some rules
+to padding generation as well, see the section 2.7 Packet Padding
+Generation.
+
+With out a doubt, this sort of decryption processing causes some
+overhead to packet decryption, but never the less, is required.
+
+
+.ti 0
+2.5.2 Channel Message Encryption And Decryption
+
+Channel Messages (Channel Message Payload) are always encrypted with
+the channel specific key.  However, the SILC Packet header is not 
+encrypted with that key.  As in normal case, the header is encrypted
+with the key of the next receiver of the packet, who ever that might
+be.  Note that in this case the encrypted data area is not touched
+at all; it must not be re-encrypted with the session key.
+
+Receiver of a channel message, who ever that is, is required to decrypt
+the SILC Packet header to be able to even recognize the packet to be as
+channel message.  This is same procedure as for normal SILC packets.
+As the receiver founds the packet to be channel message, rest of the
+packet processing is special.  Rest of the SILC Packet header is
+decrypted with the same session key along with the padding of the
+packet.  After that the packet is protected with the channel specific
+key and hence can be decrypted only if the receiver is the client on
+the channel.  See section 2.7 Packet Padding Generation for more
+information about padding on special packets.
+
+If the receiver of the channel message is router who is routing the
+message to another router then it must decrypt the Channel Message
+payload.  Between routers (that is, between cells) channel messages
+are protected with session keys shared between the routers.  This
+causes another special packet processing for channel messages.  If
+the channel message is received from another router then the entire
+packet, including Channel Message payload, is encrypted with the
+session key shared between the routers.  In this case the packet
+decryption process is as with normal SILC packets.  Hence, if the
+router is sending channel message to another router the Channel
+Message payload must have been decrypted and must be re-encrypted
+with the session key shared between the another router.  In this
+case the packet encryption is as with any normal SILC packet.
+
+It must be noted that this is only when the channel messages are sent
+from router to another router.  In all other cases the channel
+message encryption and decryption is as described above.  This
+different processing of channel messages with router to router
+connection is because channel keys are cell specific.  All cells has
+their own channel keys thus the channel message traveling from one
+cell to another must be protected as it would be any normal SILC
+packet.
+
+
+.ti 0
+2.5.3 Private Message Encryption And Decryption
+
+By default, private message in SILC are protected by session keys.
+In this case the private message encryption and decryption process is
+equivalent to normal packet encryption and decryption.
+
+However, private messages can be protected with private message key
+which causes the packet to be special packet.  The procedure in this
+case is very much alike to channel packets.  The actual private message
+is encrypted with the private message key and other parts of the
+packet is encrypted with the session key.  See 2.7 Packet Padding
+Generation for more information about padding on special packets.
+
+The difference from channel message processing is that server or router
+en route never decrypts the actual private message, as it does not
+have the key to do that.  Thus, when sending packets between router
+the processing is same as in any other case as well; the packet's header
+and padding is protected by the session key and the data area is not
+touched.
+
+The true receiver of the private message, client, that is, is able
+to decrypt the private message as it shares the key with the sender
+of the message.
+
+
+.ti 0
+2.6 Packet MAC Generation
+
+Data integrity of a packet is protected by including a message
+authentication code (MAC) at the end of the packet.  The MAC is computed
+from shared secret MAC key, that is established by the SILC Key Exchange
+protocol, and from the original contents of the packet.  The MAC is
+always computed before the packet is encrypted, although after it is
+compressed if compression is used.
+
+The MAC is computed from entire packet.  Every bit of data in the packet,
+including SILC Packet Header is used in the MAC computing.  This way
+the entire packet becomes authenticated.
+
+If the packet is special packet MAC is computed from the entire packet
+but part of the packet may be encrypted before the MAC is computed.
+This is case, for example, with channel messages where the message data
+is encrypted with key that server may not now.  In this case the MAC
+has been computed from the encrypted data.
+
+See [SILC1] for defined and allowed MAC algorithms.
+
+
+.ti 0
+2.7 Packet Padding Generation
+
+Padding is needed in the packet because the packet is encrypted.  It
+must always be multiple by eight (8) or multiple by the size of the
+cipher's block size, which ever is larger.  The padding is always
+encrypted.
+
+For normal packets the padding is added after the SILC Packet Header
+and between the Data Payload area.  The padding for normal packets
+are calculated as follows:
+
+.in 6
+padding length = 16 - ((packet length - 2) % 16)
+.in 3
+
+The 16 is the maximum padding allowed in SILC packet.  Two (2) is 
+subtracted from the true length of the packet because two (2) bytes
+is not encrypted in SILC Packet Header, see section 2.2 SILC Packet
+Header.  Those two bytes that are not encrypted must not be calculated
+to the padding length.
+
+For special packets the padding calculation may be different as special
+packets may be encrypted differently.  In these cases the encrypted
+data area must already be multiple by the block size thus in this case
+the padding is calculated only for SILC Packet Header, not for any
+other area of the packet.  The same algorithm works in this case as
+well, except that the `packet length' is now the SILC Packet Header
+length.  In this case, as well, two (2) is subtracted from the
+length.
+
+The padding must be random data, preferably, generated by 
+cryptographically strong random number generator.
+
+
+.ti 0
+2.8 Packet Compression
+
+SILC Packets may be compressed.  In this case the data payload area
+is compressed and all other areas of the packet must remain as they
+are.  After compression is performed for the data area, the length
+field of Packet Header must be set to the compressed length of the
+data.
+
+The compression must always be applied before encryption.  When
+the packet is received and decrypted the data area must be decompressed.
+Note that the true sender of the packet must apply the compression and
+the true receiver of the packet must apply the decompression.  Any
+server or router en route must not decompress the packet.
+
+
+.ti 0
+2.9 Packet Sending
+
+The sender of the packet must assemble the SILC Packet Header with
+correct values.  It must set the Source ID of the header as its own
+ID.  It must also set the Destination ID of the header to the true
+destination.  If the destination is client it will be Client ID, if
+it is server it will be Server ID and if it is channel it will be
+Channel ID.
+
+If the sender wants to compress the packet it must apply the
+compression now.  Sender must also compute the padding as described
+in above sections.  Then sender must compute the MAC of the packet.
+
+Then sender encrypts the packet as has been described in above
+sections according whether the packet is normal packet or special
+packet.  The computed MAC must not be encrypted.
+
+
+.ti 0
+2.10 Packet Reception
+
+On packet reception the receiver must check that all fields in the
+SILC Packet Header are valid sain.  It must check the flags of the
+header and act accordingly.  It must also check the MAC of the packet
+and if it is to be failed the packet must be discarded.  Also if the
+header of the packet includes any bad fields the packet must be
+discarded.
+
+See above sections on the decryption process of the received packet.
+The receiver must also check that the ID's in the header are valid
+ID's.  Unsupported ID types or malformed ID's must cause packet
+rejection.  The padding on the reception is always ignored.
+
+The receiver must also check the packet type and start parsing the
+packet according to the type.  However, note the above sections on
+special packet types and their parsing.
+
+
+.ti 0
+2.11 Packet Broadcasting
+
+SILC packets may be broadcasted in SILC network.  However, only router
+server may send or receive broadcast packets.  Client and normal server
+must not send broadcast packets and they must ignore broadcast packets
+if they receive them.  Broadcast packets are sent by setting Broadcast
+flag to the SILC packet header.
+
+Broadcasting packets means that the packet is sent to all routers in
+the SILC network, except to the router that sent the packet.  The router
+receiving broadcast packet must send the packet to its primary route.
+The fact that SILC routers may have several router connections may
+cause problems, such as race conditions inside the SILC network, if
+care is not taken when broadcasting packets.  Router must not send
+the broadcast packet to any other route except to its primary route.
+
+If the primary route of the router is the original sender of the packet
+the packet must not be sent to the primary route.  This may happen
+if router has several router connections and some other router uses
+the router as its primary route.
+
+Routers use broadcast packets to broadcast for example information
+about newly registered clients, servers, channels etc. so that all the
+routers may keep these informations up to date.
+
+
+.ti 0
+2.12 Packet Routing
+
+Routers are the primary entities in the SILC network that takes care
+of packet routing.  However, normal servers routes packets as well, for
+example, when they are routing channel message to the local clients.
+Routing is quite simple as every packet tells the true origin and the
+true destination of the packet.
+
+It is still recommended for routers that has several routing connections
+to create route cache for those destinations that has faster route than
+the router's primary route.  This information is available for the router
+when other router connects to the router.  The connecting party then
+sends all of its locally connected clients, server and channels.  These
+informations helps to create the route cache.  Also, when new channels
+are created to a cell its information is broadcasted to all routers
+in the network.  Channel ID's are based on router's ID thus it is easy
+to create route cache based on these informations.  If faster route for
+destination does not exist in router's route cache the packet must be
+routed to the primary route (default route).
+
+For server who receives a packet to be routed to its locally connected
+client the server must check whether the particular packet type is
+allowed to be routed to the client.  Not all packets may be sent by
+some odd entity to client that is indirectly connected to the sender.
+See section 2.3 SILC Packet Types and paragraph about indirectly connected
+entities and sending packets to them.  The section mentions the packets
+that may be sent to indirectly connected entities.  It is clear that some
+server cannot send, for example, disconnect packet to client that is not
+directly connected to the server.
+
+
+.ti 0
+2.13 Packet Tunneling
+
+Tunneling is a feature that is available in SILC protocol.  Tunneling
+means that extra SILC Packet Header is applied to the original packet
+and thus hiding the original packet entirely.  There can be some
+interesting applications using tunneling, such as, using ID's based on
+private network IP addresses inside in the tunneled packet.  This can
+open many interesting features relating to connecting to private network
+from the Internet with SILC and many more.  However, this feature is
+optional currently in SILC as there does not exist thorough analysis of
+this feature.  It is with out a doubt that there will be many more
+applications that has not yet been discovered.  Thus, it is left
+to Internet Community to investigate the use of tunneling in SILC
+protocol.  This document is updated according those investigations
+and additional documents on the issue may be written.
+
+
+.ti 0
+3 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+4 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, June 2000.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication 
+             Protocols", Internet Draft, June 2000.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol", 
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key 
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exhange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+
+.ti 0
+5 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
diff --git a/doc/draft-riikonen-silc-spec-00.nroff b/doc/draft-riikonen-silc-spec-00.nroff
new file mode 100644 (file)
index 0000000..a37c0a5
--- /dev/null
@@ -0,0 +1,2956 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2000
+.ds CH Secure Internet Live Conferencing
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                      P. Riikonen
+Internet-Draft
+draft-riikonen-silc-spec-00.txt                           27 June 2000
+Expires: 27 Jan 2001
+
+.in 3
+
+.ce 2
+Secure Internet Live Conferencing (SILC),
+Protocol Specification
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft.  Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups.  Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other 
+documents at any time. It is inappropriate to use Internet-Drafts  
+as reference material or to cite them other than as 
+``work in progress.''
+
+To learn the current status of any Internet-Draft, please check the
+``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Secure Internet Live Conferencing (SILC)
+protocol which provides secure conferencing services over insecure
+network channel.  SILC is IRC [IRC] like protocol, however, it is 
+not equivalent to IRC and does not support IRC.  Strong cryptographic
+methods are used to protect SILC packets inside SILC network.  Two
+other Internet Drafts relates very closely to this memo;  SILC Packet
+Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
+[SILC3].
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  3
+2 SILC Concepts .................................................  3
+  2.1 SILC Network Topology .....................................  4
+  2.2 Communication Inside a Cell ...............................  5
+  2.3 Communication in the Network ..............................  6
+  2.4 Channel Communication .....................................  7
+3 SILC Specification ............................................  7
+  3.1 Client ....................................................  7
+      3.1.1 Client ID ...........................................  8
+  3.2 Server ....................................................  8
+      3.2.1 Server's Local ID List ..............................  9
+      3.2.2 Server ID ........................................... 10
+      3.2.3 SILC Server Ports ................................... 10
+  3.3 Router .................................................... 11
+      3.3.1 Router's Local ID List .............................. 11
+      3.3.2 Router's Global ID List ............................. 12
+      3.3.3 Router's Server ID .................................. 12
+  3.4 Channels .................................................. 12
+      3.4.1 Channel ID .......................................... 13
+  3.5 Operators ................................................. 14
+  3.6 SILC Commands ............................................. 14
+  3.7 SILC Packets .............................................. 15
+  3.8 Packet Encryption ......................................... 15
+      3.8.1 Determination of the Source and the Destination ..... 16
+      3.8.2 Client To Client .................................... 16
+      3.8.3 Client To Channel ................................... 17
+      3.8.4 Server To Server .................................... 18
+  3.9 Key Exchange And Authentication ........................... 18
+  3.10 Algorithms ............................................... 19
+      3.10.1 Ciphers ............................................ 19
+      3.10.2 Public Key Algorithms .............................. 20
+      3.10.3 MAC Algorithms ..................................... 20
+      3.10.4 Compression Algorithms ............................. 20
+  3.11 SILC Public Key .......................................... 21
+4 SILC Procedures ............................................... 23
+  4.1 Creating Client Connection ................................ 23
+  4.2 Creating Server Connection ................................ 24
+  4.3 Joining to a Channel ...................................... 25
+  4.4 Channel Key Generation .................................... 26
+  4.5 Private Message Sending and Reception ..................... 27
+  4.6 Private Message Key Generation ............................ 27
+  4.7 Channel Message Sending and Reception ..................... 28
+  4.8 Session Key Regeneration .................................. 28
+  4.9 Command Sending and Reception ............................. 29
+5 SILC Commands ................................................. 29
+  5.1 SILC Commands Syntax ...................................... 29
+  5.2 SILC Commands List ........................................ 31
+  5.3 SILC Command Status Types ................................. 53
+      5.3.1 SILC Command Status Payload ......................... 53
+      5.3.2 SILC Command Status List ............................ 54
+6 Security Considerations ....................................... 58
+7 References .................................................... 58
+8 Author's Address .............................................. 59
+
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:  SILC Network Topology
+Figure 2:  Communication Inside cell
+Figure 3:  Communication Between Cells
+Figure 4:  SILC Public Key
+Figure 5:  SILC Command Status Payload
+
+
+.ti 0
+1. Introduction
+
+This document describes a Secure Internet Live Conferencing (SILC)
+protocol which provides secure conferencing services over insecure
+network channel.  SILC is IRC [IRC] like protocol, however, it is 
+not equivalent to IRC and does not support IRC.  Strong cryptographic
+methods are used to protect SILC packets inside SILC network.  Two
+other Internet Drafts relates very closely to this memo;  SILC Packet
+Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
+[SILC3].
+
+The protocol uses extensively packets as conferencing protocol 
+requires message and command sending.  The SILC Packet Protocol is
+described in [SILC2] and should be read to fully comprehend this
+document and protocol.  [SILC2] also describes the packet encryption
+and decryption in detail.
+
+The security of SILC protocol and for any security protocol for that
+matter is based on strong and secure key exchange protocol.  The SILC
+Key Exchange protocol is described in [SILC3] along with connection
+authentication protocol and should be read to fully comprehend this
+document and protocol.
+
+The SILC protocol has been developed to work on TCP/IP network
+protocol, although it could be made to work on other network protocols
+with only minor changes.  However, it is recommended that TCP/IP
+protocol is used under SILC protocol.  Typical implementation would
+be made in client-server model.
+
+
+.ti 0
+2. SILC Concepts
+
+This section describes various SILC protocol concepts that forms the 
+actual protocol, and in the end, the actual SILC network.  The mission
+of the protocol is to deliver messages from clients to other clients 
+through routers and servers in secure manner.  The messages may also 
+be delivered from one client to many clients forming a group, also 
+known as a channel.
+
+This section does not focus to security issues, instead basic network 
+concepts are introduced to make the topology of the SILC network 
+clear.
+
+
+.ti 0
+2.1 SILC Network Topology
+
+SILC network is a cellular network as opposed to tree style network 
+topology.  The rationale for this is to have servers that can perform 
+specific kind of tasks what other servers cannot perform.  This leads 
+to two kinds of servers; normal SILC servers and SILC routers.  
+A difference between normal server and router server is that routers 
+knows everything about everything in the network.  They also do the 
+actual routing of the messages to the correct receiver.  Normal servers 
+knows only about local information and nothing about global information.
+This makes the network faster as there are less servers that needs to 
+keep global information up to date at all time.
+
+This, on the other hand, leads to cellular like network, where routers 
+are in the centrum on the cell and servers are connected to the router.
+Following diagram represents SILC network topology.
+
+
+.in 8
+.nf
+  ---- ---- ----         ---- ---- ----
+ | S8 | S5 | S4 |       | S7 | S5 | S6 |
+ ----- ---- -----       ----- ---- -----
+| S7 | S/R1 | S2 | --- | S8 | S/R2 | S4 |
+ ---- ------ ----       ---- ------ ----
+ | S6 | S3 | S1 |       | S1 | S3 | S2 |         ---- ----
+  ---- ---- ----         ---- ---- ----         | S3 | S1 |
+     Cell 1.   \\             Cell 2.  | \\____  ----- -----
+                |                     |        | S4 | S/R4 |
+    ---- ---- ----         ---- ---- ----       ---- ------
+   | S7 | S4 | S2 |       | S1 | S3 | S2 |      | S2 | S5 |
+   ----- ---- -----       ----- ---- -----       ---- ----
+  | S6 | S/R3 | S1 | --- | S4 | S/R5 | S5 |       Cell 4.
+   ---- ------ ----       ---- ------ ----
+   | S8 | S5 | S3 |       | S6 | S7 | S8 |     ... etc ...
+    ---- ---- ----         ---- ---- ----
+       Cell 3.                Cell 5.
+.in 3
+
+.ce
+Figure 1:  SILC Network Topology
+
+
+A cell is formed when a server or servers connect to one router.  In
+SILC network normal server cannot directly connect to other normal
+server.  Normal server may only connect to SILC router which then
+routes the messages to the other servers in the cell.  Router servers
+on the other hand may connect to other routers to form the actual SILC 
+network, as seen in above figure.  However, router is also normal SILC 
+server; clients may connect to it the same way as to normal SILC 
+servers.  Normal server also cannot have active connections to more 
+than one router.  Normal server cannot be connected to two different 
+cells.  Router servers, on the other hand, may have as many router to 
+router connections as needed.
+
+There are many issues in this network topology that needs to be careful
+about.  Issues like the size of the cells, the number of the routers in 
+the SILC network and the capacity requirements of the routers.  These
+issues should be discussed in the Internet Community and additional
+documents on the issue will be written.
+
+
+.ti 0
+2.2 Communication Inside a Cell
+
+It is always guaranteed that inside a cell message is delivered to the 
+recipient with at most two server hops.  Client who is connected to
+server in the cell and is talking on channel to other client connected 
+to other server in the same cell, will have its messages delivered from 
+its local server first to the router of the cell, and from the router 
+to the other server in the cell.  Following diagram represents this 
+scenario.
+
+
+.in 25
+.nf
+1 --- S1     S4 --- 5
+         S/R
+ 2 -- S2     S3
+     /        |
+    4         3
+.in 3
+
+
+.ce
+Figure 2:  Communication Inside cell
+
+
+Example:  Client 1. connected to Server 1. message sent to
+          Client 4. connected to Server 2. travels from Server 1.
+          first to Router which routes the message to Server 2.
+          which then sends it to the Client 4.  All the other
+          servers in the cell will not see the routed message.
+
+
+If client is connected directly to the router, as router is also normal 
+SILC server, the messages inside the cell are always delivered only with 
+one server hop.  If clients communicating with each other are connected 
+to the same server, no router interaction is needed.  This is the optimal
+situation of message delivery in the SILC network.
+
+
+.ti 0
+2.3 Communication in the Network
+
+If the message is destined to server that does not belong to local cell 
+the message is routed to the router server to which the destination 
+server belongs, if the local router is connected to destination router.
+If there is no direct connection to the destination router, the local
+router routes the message to its primary route.  Following diagram
+represents message sending between cells.
+
+
+.in 16
+.nf
+1 --- S1     S4 --- 5            S2 --- 1
+         S/R - - - - - - - - S/R
+ 2 -- S2     S3           S1
+     /        |             \\
+    4         3              2
+
+   Cell 1.               Cell 2.
+.in 3
+
+
+.ce
+Figure 3:  Communication Between Cells
+
+
+Example:  Client 5. connected to Server 4. in Cell 1. message sent
+          to Client 2. connected to Server 1. in Cell 2. travels
+          from Server 4. to Router which routes the message to
+          Router in Cell 2, which then routes the message to 
+          Server 1.  All the other servers and routers in the
+          network will not see the routed message.
+
+
+The optimal case of message delivery from client point of view is
+when clients are connected directly to the routers and the messages
+are delivered from one router to the other router.
+
+
+
+
+
+.ti 0 
+2.4 Channel Communication
+
+Messages may be sent to group of clients as well.  Sending messages to
+many clients works the same way as sending messages point to point, from
+message delivery point of view.  Security issues are another matter
+which are not discussed in this section.
+
+Router server handles the message routing to multiple recipients.  If 
+any recipient is not in the same cell as the sender the messages are 
+routed further.
+
+Server distributes the channel message to its local clients who are 
+joined to the channel.  Also, router distributes the message to its 
+local clients on the channel.
+
+
+.ti 0
+3. SILC Specification
+
+This section describes the SILC protocol.  However, [SILC2] and
+[SILC3] describes other important protocols that are part of this SILC
+specification and must be read.
+
+
+.ti 0
+3.1 Client
+
+A client is a piece of software connecting to SILC server.  SILC client 
+cannot be SILC server.  Purpose of clients is to provide the user 
+interface of the SILC services for end user.  Clients are distinguished
+from other clients by unique Client ID.  Client ID is a 128 bit ID that
+is used in the communication in the SILC network.  The client ID is 
+based on the nickname selected by the user.  User uses logical nicknames
+in communication which are then mapped to the corresponding Client ID.
+Client ID's are low level identifications and must not be seen by the
+end user.
+
+Clients provide other information about the end user as well. Information
+such as the nickname of the user, username and the hostname of the end 
+user and user's real name.  See section 3.2 Server for information of 
+the requirements of keeping this information.
+
+The nickname selected by the user is not unique in the SILC network.
+There can be 2^8 same nicknames for one IP address. As for comparison to
+IRC [IRC] where nicknames are unique this is a fundamental difference
+between SILC and IRC.  This causes the server names to be used along
+with the nicknames to identify specific users when sending messages.
+This feature of SILC makes IRC style nickname-wars obsolete as no one
+owns their nickname; there can always be someone else with the same
+nickname.  Another difference is that there are no limit of the length
+of the nickname in the SILC.
+
+
+.ti 0
+3.1.1 Client ID
+
+Client ID is used to identify users in the SILC network.  The Client ID
+is unique to the extent that there can be 2^128 different Client ID's.
+Collisions are not expected to happen.  The Client ID is defined as 
+follows.
+
+.in 6
+128 bit Client ID based on IPv4 addresses:
+
+32 bit  ServerID IP address (bits 1-32)
+ 8 bit  Random number
+88 bit  Truncated MD5 hash value of the nickname
+
+o Server ID IP address - Indicates the server where this
+  client is coming from.  The IP address hence equals the
+  server IP address where to the client has connected.
+
+o Random number - Random number to further unify the
+  Client ID.  This makes it possible to have 2^8 same
+  nicknames from the same server IP address.
+
+o MD5 hash - MD5 hash value of the nickname is truncated
+  taking 88 bits from the start of the hash value.  This
+  hash value is used to search the user's Client ID from
+  the ID lists.
+
+.in 3
+Collisions could occur when more than 2^8 clients using same nickname
+from the same server IP address is connected to the SILC network.  
+Server must be able to handle this situation by refusing to accept 
+anymore of that nickname.
+
+Another possible collision may happen with the truncated hash value of
+the nickname.  It could be possible to have same truncated hash value for
+two different nicknames.  However, this is not expected to happen nor
+cause any problems if it would occur.  Nicknames are usually logical and
+it is unlikely to have two distinct logical nicknames produce same
+truncated hash value.
+
+
+.ti 0
+3.2 Server
+
+Servers are the most important parts of the SILC network.  They form the
+basis of the SILC, providing a point to which clients may connect to.
+There are two kinds of servers in SILC; normal servers and router servers.
+This section focuses on the normal server and router server is described
+in the section 3.3 Router.
+
+Normal servers may not directly connect to other normal server.  Normal
+servers may only directly connect to router server.  If the message sent
+by the client is destined outside the local server it is always sent to
+the router server for further routing.  Server may only have one active
+connection to router on same port.  Normal server may not connect to other
+cell's router except in situations where its cell's router is unavailable.
+
+Servers and routers in the SILC network are considered to be trusted.
+With out a doubt, servers that are set to work on ports above 1023 are
+not considered to be trusted.  Also, the service provider acts important
+role in the server's trustworthy.
+
+
+.ti 0
+3.2.1 Server's Local ID List
+
+Normal server keeps various information about the clients and their end
+users connected to it.  Every normal server must keep list of all locally
+connected clients, Client ID's, nicknames, usernames and hostnames and
+user's real name.  Normal servers only keeps local information and it
+does not keep any global information.  Hence, normal servers knows only
+about their locally connected clients.  This makes servers efficient as
+they don't have to worry about global clients.  Server is also responsible
+of creating the Client ID's for their clients.
+
+Normal server also keeps information about locally created channels and
+their Channel ID's.
+
+Hence, local list for normal server includes:
+
+.in 6
+server list        - Router connection
+   o Server name
+   o Server IP address
+   o Server ID
+   o Sending key
+   o Receiving key
+   o Public key
+
+client list        - All clients in server
+   o Nickname
+   o Username@host
+   o Real name
+   o Client ID
+   o Sending key
+   o Receiving key
+
+
+
+channel list       - All channels in server
+   o Channel name
+   o Channel ID
+   o Client ID's on channel
+   o Client ID modes on channel
+   o Channel key
+.in 3
+
+
+
+.ti 0
+3.2.2 Server ID
+
+Servers are distinguished from other servers by unique 64 bit Server ID.
+The Server ID is used in the SILC to route messages to correct servers.
+Server ID's also provide information for Client ID's, see section 3.1.1
+Client ID.  Server ID is defined as follows.
+
+.in 6
+64 bit Server ID based on IPv4 addresses:
+
+32 bit  IP address of the server
+16 bit  Port
+16 bit  Random number
+
+o IP address of the server - This is the real IP address of
+  the server.
+
+o Port - This is the port the server is binded to.
+
+o Random number - This is used to further unify the Server ID.
+
+.in 3
+Collisions are not expected to happen in any conditions.  The Server ID
+is always created by the server itself and server is resposible of
+distributing it to the router.
+
+
+.ti 0
+3.2.3 SILC Server Ports
+
+SILC uses currently TCP port 334 on SILC network.  However, this is not
+official port assigned for SILC.  Official port has been requested by 
+the IANA.
+
+If there are needs to create new SILC networks in the future the port
+numbers must be officially assigned by the IANA.  Most convenience case
+would be to assign port numbers upwards from 334.
+
+Server on network above privileged ports (>1023) should not be trusted
+as they could have been set up by untrusted party.
+
+
+.ti 0
+3.3 Router
+
+Router server in SILC network is responsible for keeping the cell together
+and routing messages to other servers and to other routers.  Router server
+is also a normal server thus clients may connect to it as it would be
+just normal SILC server.
+
+However, router servers has a lot of important tasks that normal servers
+do not have.  Router server knows everything about everything in the SILC.
+They know all clients currently on SILC, all servers and routers and all
+channels in SILC.  Routers are the only servers in SILC that care about
+global information and keeping them up to date at all time.  And, this
+is what they must do.
+
+
+.ti 0
+3.3.1 Router's Local ID List
+
+Router server as well must keep local list of connected clients and
+locally created channels.  However, this list is extended to include all
+the informations of the entire cell, not just the server itself as for
+normal servers.
+
+However, on router this list is a lot smaller since routers do not keep
+information about user's nickname, username and hostname and real name
+since these are not needed by the router.  Router keeps only information
+that it needs.
+
+Hence, local list for router includes:
+
+.in 6
+server list        - All servers in the cell
+   o Server name
+   o Server ID
+   o Router's Server ID
+   o Sending key
+   o Receiving key
+
+client list        - All clients in the cell
+   o Client ID
+
+channel list       - All channels in the cell
+   o Channel ID
+   o Client ID's on channel
+   o Client ID modes on channel
+   o Channel key
+.in 3
+
+
+Note that locally connected clients and other information include all the
+same information as defined in section section 3.2.1 Server's Local ID
+List.
+
+
+.ti 0
+3.3.2 Router's Global ID List
+
+Router server must also keep global list.  Normal servers do not have
+global list as they know only about local information.  Global list
+includes all the clients on SILC, their Client ID's, all created channels
+and their Channel ID's and all servers and routers on SILC and their
+Server ID's.  That is said, global list is for global information and the
+list must not include the local information already on the router's local
+list.
+
+Note that the global list does not include information like nicknames,
+usernames and hostnames or user's real names.  Router does not keep
+these informations as they are not needed by the router.  This 
+information is available from the client's server which maybe queried
+when needed.
+
+Hence, global list includes:
+
+.in 6
+server list        - All servers in SILC
+   o Server name
+   o Server ID
+   o Router's Server ID
+
+client list        - All clients in SILC
+   o Client ID
+
+channel list       - All channels in SILC
+   o Channel ID
+   o Client ID's on channel
+   o Client ID modes on channel
+.in 3
+
+
+.ti 0
+3.3.3 Router's Server ID
+
+Router's Server ID's are equivalent to normal Server ID's.  As routers
+are normal servers as well same types of ID's applies for routers as well.
+Thus, see section 3.2.2 Server ID.  Server ID's for routers are always
+created by the remote router where the router is connected to.
+
+
+.ti 0
+3.4 Channels
+
+A channel is a named group of one or more clients which will all receive
+messages addressed to that channel.  The channel is created when first
+client requests JOIN command to the channel, and the channel ceases to
+exist when the last client leaves it.  When channel exists, any client
+can reference it using the name of the channel.
+
+Channel names are unique although the real uniqueness comes from 64 bit
+Channel ID that unifies each channel.  However, channel names are still
+unique and no two global channels with same name may exist.  Channel name
+is a string which begins with `#' character.  There is no limit on the
+length of the channel name.  Channel names may not contain any spaces
+(`  '), any non-printable ASCII characters, commas (`,') and wildcard
+characters.
+
+Channels can have operators that can administrate the channel and
+operate all of its modes.  Following operators on channel exist on SILC
+network.
+
+.in 6
+o Channel founder - When channel is created the joining client becomes
+  channel founder.  Channel founder is channel operator with some more
+  privileges.  Basically, channel founder can fully operate the channel
+  and all of its modes.  The privileges are limited only to the particular
+  channel.  There can be only one channel founder per channel.  Channel
+  founder supersedes channel operator's privileges.
+
+  Channel founder privileges cannot be removed by any other operator on
+  channel.  When channel founder leaves the channel there is no channel
+  founder on the channel.  Channel founder also cannot be removed by
+  force from the channel.
+
+o Channel operator - When client joins to channel that has not existed
+  previously it will become automatically channel operator (and channel
+  founder discussed above).  Channel operator is able administrate the
+  channel, set some modes on channel, remove a badly behaving client from
+  the channel and promote other clients to become channel operator.
+  The privileges are limited only to the particular channel.
+
+  Normal channel user may be promoted (opped) to channel operator
+  gaining channel operator privileges.  Channel founder or other channel
+  operator may also demote (deop) channel operator to normal channel
+  user.
+.in 3
+
+
+.ti 0
+3.4.1 Channel ID
+
+Channels are distinguished from other channels by unique Channel ID.
+The Channel ID is a 64 bit ID and collisions are not expected to happen
+in any conditions.  Channel names are just for logical use of channels.
+The Channel ID is created by the server where the channel is created.
+The Channel ID is defined as follows.
+
+.in 6
+64 bit Channel ID based on IPv4 addresses:
+
+32 bit  Router's Server ID IP address (bits 1-32)
+16 bit  Router's Server ID port (bits 33-48)
+16 bit  Random number
+
+o Router's Server ID IP address - Indicates the IP address of 
+  the router of the cell where this channel is created.  This is 
+  taken from the router's Server ID.  This way SILC router knows 
+  where this channel resides in the SILC network.
+
+o Router's Server ID port - Indicates the port of the channel on 
+  the server.  This is taken from the router's Server ID.
+
+o Random number - To further unify the Channel ID.  This makes
+  sure that there are no collisions.  This also means that
+  in a cell there can be 2^16 channels.
+.in 3
+
+
+.ti 0
+3.5 Operators
+
+Operators are normal users with extra privileges to their server or
+router.  Usually these people are SILC server and router administrators
+that take care of their own server and clients on them.  The purpose of
+operators is to administrate the SILC server or router.  However, even
+an operator with highest privileges is not able to enter invite-only
+channel, to gain access to the contents of a encrypted and authenticated
+packets traveling in the SILC network or to gain channel operator
+privileges on public channels without being promoted.  They have the
+same privileges as everyone else except they are able to administrate
+their server or router.
+
+
+.ti 0
+3.6 SILC Commands
+
+Commands are very important part on SILC network especially for client
+which uses commands to operate on the SILC network.  Commands are used
+to set nickname, join to channel, change modes and many other things.
+
+Client usually sends the commands and server replies by sending a reply
+packet to the command.  Server may also send commands usually to serve
+the original client's request.  However, server may not send command
+to client and there are some commands that server must not send.
+
+Note that the command reply is usually sent only after client has sent
+the command request but server is allowed to send command reply packet
+to client even if client has not requested the command.  Client may,
+however, choose not to accept the command reply, but there are some
+command replies that the client should accept.  Example of a such
+command reply is reply to SILC_COMMAND_CMODE command that the server
+uses to distribute the channel mode on all clients on the channel
+when the mode has changed.
+
+It is expected that some of the commands may be miss-used by clients
+resulting various problems on the server side.  Every implementation
+should assure that commands may not be executed more than once, say,
+in two (2) seconds.  This should be sufficient to prevent the miss-use
+of commands.
+
+SILC commands are described in section 5 SILC Commands.
+
+
+.ti 0
+3.7 SILC Packets
+
+Packets are naturally the most important part of the protocol and the
+packets are what actually makes the protocol.  Packets in SILC network
+are always encrypted using, usually, the shared secret session key
+or some other key, for example, channel key, when encrypting channel
+messages.  The SILC Packet Protocol is a wide protocol and is described
+in [SILC2].  This document does not define or describe details of
+SILC packets.
+
+
+.ti 0
+3.8 Packet Encryption
+
+All packets passed in SILC network must be encrypted.  This section
+defines how packets must be encrypted in the SILC network.  The detailed
+description of the actual encryption process of the packets are
+described in [SILC2].
+
+Client and its server shares secret symmetric session key which is
+established by the SILC Key Exchange Protocol, described in [SILC3]. 
+Every packet sent from client to server, with exception of packets for
+channels, are encrypted with this session key.
+
+Channels has their own key that are shared by every client on the channel.
+However, the channel keys are cell specific thus one cell does not know
+the channel key of the other cell, even if that key is for same channel.
+Channel key is also known by the routers and all servers that has clients
+on the channel.  However, channels may have channel private keys that
+are entirely local setting for client.  All clients on the channel must
+know the channel private key before hand to be able to talk on the
+channel.  In this case, no server or router knows the key for channel.
+
+Server shares secret symmetric session key with router which is
+established by the SILC Key Exchange Protocol.  Every packet passed from
+server to router, with exception of packets for channels, are encrypted
+with the shared session key.  Same way, router server shares secret
+symmetric key with its primary route.  However, every packet passed
+from router to other router, including packets for channels, are
+encrypted with the shared session key.  Every router connection has
+their own session keys.
+
+
+.ti 0
+3.8.1 Determination of the Source and the Destination
+
+The source and the destination of the packet needs to be determined
+to be able to route the packets to correct receiver.  This information
+is available in the SILC Packet Header which is included in all packets
+sent in SILC network.  The SILC Packet Header is described in [SILC2].
+
+The header is always encrypted with the session key who is next receiver
+of the packet along the route.  The receiver of the packet, for example
+a router along the route, is able to determine the sender and the
+destination of the packet by decrypting the SILC Packet Header and
+checking the ID's attached to the header.  The ID's in the header will
+tell to where the packet needs to be sent and where it is coming from.
+
+The header in the packet does not change during the routing of the
+packet.  The original sender, for example client, assembles the packet
+and the packet header and server or router between the sender and the
+receiver must not change the packet header.
+
+Note that the packet and the packet header may be encrypted with
+different keys.  For example, packets to channels are encrypted with
+the channel key, however, the header is encrypted with the session key
+as described above.  However, the header and the packet may be encrypted
+with same key.  This is case, for example, with command packets.
+
+
+.ti 0
+3.8.2 Client To Client
+
+Process of message delivery and encryption from client to another
+client is as follows.
+
+Example:  Private message from client to another client on different
+          servers.  Clients do not share private message delivery
+          keys; normal session keys are used.
+
+o Client 1. sends encrypted packet to its server.  The packet is
+  encrypted with the session key shared between client and its
+  server.
+
+o Server determines the destination of the packet and decrypts
+  the packet.  Server encrypts the packet with session key shared
+  between the server and its router, and sends the packet to the
+  router.
+
+o Router determines the destination of the packet and decrypts
+  the packet.  Router encrypts the packet with session key 
+  shared between the router and the destination server, and sends
+  the packet to the server.
+
+o Server determines the client to which the packet is destined
+  to and decrypts the packet.  Server encrypts the packet with
+  session key shared between the server and the destination client,
+  and sends the packet to the client.
+
+o Client 2. decrypts the packet.
+
+
+Example:  Private message from client to another client on different
+          servers.  Clients has established secret shared private
+          message delivery key with each other and that is used in 
+          the message encryption.
+
+o Client 1. sends encrypted packet to its server.  The packet is
+  encrypted with the private message delivery key shared between
+  clients.
+
+o Server determines the destination of the packet and sends the 
+  packet to the router.
+
+o Router determines the destination of the packet and sends the
+  packet to the server.
+
+o Server determines the client to which the packet is destined
+  to and sends the packet to the client.
+
+o Client 2. decrypts the packet with the secret shared key.
+
+
+If clients share secret key with each other the private message
+delivery is much simpler since servers and routers between the
+clients do not need to decrypt and re-encrypt the packet.
+
+The process for clients on same server is much simpler as there are
+no need to send the packet to the router.  The process for clients 
+on different cells is same as above except that the packet is routed 
+outside the cell.  The router of the destination cell routes the 
+packet to the destination same way as described above.
+
+
+.ti 0
+3.8.3 Client To Channel
+
+Process of message delivery from client on channel to all the clients
+on the channel.
+
+Example:  Channel of four users; two on same server, other two on
+          different cells.  Client sends message to the channel.
+
+o Client 1. encrypts the packet with channel key and sends the
+  packet to its server.
+
+o Server determines local clients on the channel and sends the
+  packet to the Client on the same server.  Server then sends
+  the packet to its router for further routing.
+
+o Router determines local clients on the channel, if found
+  sends packet to the local clients.  Router determines global
+  clients on the channel and sends the packet to its primary
+  router or fastest route.
+
+o (Other router(s) do the same thing and sends the packet to
+   the server(s))
+
+o Server determines local clients on the channel and sends the
+  packet to the client.
+
+o All clients receiving the packet decrypts the packet.
+
+
+.ti 0
+3.8.4 Server To Server
+
+Server to server packet delivery and encryption is described in above
+examples. Router to router packet delivery is analogous to server to
+server.  However, some packets, such as channel packets, are processed
+differently.  These cases are described later in this document and
+more in detail in [SILC2].
+
+
+.ti 0
+3.9 Key Exchange And Authentication
+
+Key exchange is done always when for example client connects to server
+but also when server and router and router and router connects to each
+other.  The purpose of key exchange protocol is to provide secure key
+material to be used in the communication.  The key material is used to
+derive various security parameters used to secure SILC packets.  The
+SILC Key Exchange protocol is described in detail in [SILC3].
+
+Authentication is done after key exchange protocol has been successfully
+completed.  The purpose of authentication is to authenticate for example
+client connecting to the server.  However, Usually clients are accepted
+to connect to server without explicit authentication.  Servers are
+required use authentication protocol when connecting.  The authentication
+may be based on passphrase (pre-shared-secret) or public key.  The
+connection authentication protocol is described in detail in [SILC3].
+
+
+.ti 0
+3.10 Algorithms
+
+This section defines all the allowed algorithms that can be used in
+the SILC protocol.  This includes mandatory cipher, mandatory public
+key algorithm and MAC algorithms.
+
+
+.ti 0
+3.10.1 Ciphers
+
+Cipher is the encryption algorithm that is used to protect the data
+in the SILC packets.  See [SILC2] of the actual encryption process and
+definition of how it must be done.  SILC has a mandatory algorithm that
+must be supported in order to be compliant with this protocol.
+
+Following ciphers are defined in SILC protocol:
+
+.in 6
+blowfish-cbc    Blowfish in CBC mode  (mandatory)
+twofish-cbc     Twofish in CBC mode   (optional)
+rc6-cbc         RC6 in CBC mode       (optional)
+rc5-cbc         RC5 in CBC mode       (optional)
+mars-cbc        Mars in CBC mode      (optional)
+none            No encryption         (optional)
+.in 3
+
+
+All algorithms must use minimum of 128 bit key, by default.  Several
+algorithms, however, supports longer keys and it is recommended to use
+longer keys if they are available.
+
+Algorithm none does not perform any encryption process at all and 
+thus is not recommended to be used.  It is recommended that no client
+or server implementation would accept none algorithms except in special
+debugging mode.
+
+Additional ciphers may be defined to be used in SILC by using the
+same name format as above.
+
+
+
+
+
+
+.ti 0
+3.10.2 Public Key Algorithms
+
+Public keys are used in SILC to authenticate entities in SILC network
+and to perform other tasks related to public key cryptography.  The 
+public keys are also used in the SILC Key Exchange protocol [SILC3].
+
+Following public key algorithms are defined in SILC protocol:
+
+.in 6
+rsa        RSA  (mandatory)
+dss        DSS  (optional)
+.in 3
+
+Both of the algorithms are described in [Scheneir] and [Menezes].
+
+Additional public key algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.10.3 MAC Algorithms
+
+Data integrity is protected by computing a message authentication code
+(MAC) of the packet data.  See [SILC2] for details how to compute the
+MAC.
+
+Following MAC algorithms are defined in SILC protocol:
+
+.in 6
+hmac-sha1        HMAC-SHA1, length = 20  (mandatory)
+hmac-md5         HMAC-MD5, length = 16   (optional)
+none             No MAC                  (optional)
+.in 3
+
+The none MAC is not recommended to be used as the packet is not
+authenticated when MAC is not computed.  It is recommended that no
+client or server would accept none MAC except in special debugging
+mode.
+
+The HMAC algorithm is described in [HMAC] and hash algorithms that
+are used as part of the HMACs are described in [Scheneir] and in
+[Menezes]
+
+Additional MAC algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.10.4 Compression Algorithms
+
+SILC protocol supports compression that may be applied to unencrypted
+data.  It is recommended to use compression on slow links as it may
+significantly speed up the data transmission.  By default, SILC does not
+use compression which is the mode that must be supported by all SILC
+implementations.
+
+Following compression algorithms are defined:
+
+.in 6
+none        No compression               (mandatory)
+zlib        GBU ZLIB (LZ77) compression  (optional)
+.in 3
+
+Additional compression algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.11 SILC Public Key
+
+This section defines the type and format of the SILC public key.  All
+implementations must support this public key type.  See [SILC3] for
+other optional public key and certificate types allowed in SILC
+protocol.  Public keys in SILC may be used to authenticate entities
+and to perform other tasks related to public key cryptography.
+
+The format of the SILC Public Key is as follows:
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Public Key Length                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Algorithm Name Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Algorithm Name                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Identifier Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Identifier                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                           Public Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4:  SILC Public Key
+
+
+.in 6
+o Public Key Length (4 bytes) - Indicates the full length
+  of the public key, not including this field.
+
+o Algorithm Name Length (2 bytes) - Indicates the length
+  of the Algorithm Length field, not including this field.
+
+o Algorithm name (variable length) - Indicates the name
+  of the public key algorithm that the key is.  See the
+  section 3.10.2 Public Key Algorithms for defined names.
+
+o Identifier Length (2 bytes) - Indicates the length of
+  the Identifier field, not including this field.
+
+o Identifier (variable length) - Indicates the identifier
+  of the public key.  This data can be used to identify
+  the owner of the key.  The identifier is of following
+  format:
+
+     UN   User name
+     HN   Host name or IP address
+     RN   Real name
+     E    EMail address
+     O    Organization
+     C    Country
+
+
+  Examples of an identifier:
+
+    `UN=priikone, HN=poseidon.pspt.fi, E=priikone@poseidon.pspt.fi'
+
+    `UN=sam, HN=dummy.fi, RN=Sammy Sam, O=Company XYZ, C=Finland'
+
+  At least user name (UN) and host name (HN) must be provided as
+  identifier.  The fields are separated by commas (`,').  If
+  comma is in the identifier string it must be written as `\\,',
+  for example, `O=Company XYZ\\, Inc.'.
+
+o Public Data (variable length) - Includes the actual
+  public data of the public key.
+
+  The format of this field for RSA algorithm is
+  as follows:
+
+     4 bytes            Length of e
+     variable length    e
+     4 bytes            Length of n
+     variable length    n
+
+
+  The format of this field for DSS algorithm is
+  as follows:
+
+     4 bytes            Length of p
+     variable length    p
+     4 bytes            Length of q
+     variable length    q
+     4 bytes            Length of g
+     variable length    g
+     4 bytes            Length of y
+     variable length    y
+
+  The variable length fields are multiple precession
+  integers encoded as strings in both examples.
+
+  Other algorithms must define their own type of this
+  field if they are used.
+.in 3
+
+All fields in the public key are in MSB (most significant byte first)
+order.
+
+
+.ti 0
+4 SILC Procedures
+
+This section describes various SILC procedures such as how the 
+connections are created and registered, how channels are created and
+so on.  The section describes the procedures only generally as details
+are described in [SILC2] and [SILC3].
+
+
+.ti 0
+4.1 Creating Client Connection
+
+This section descibres the procedure when client connects to SILC server.
+When client connects to server the server must perform IP address lookup
+and reverse IP address lookup to assure that the origin host really is
+who it claims to be.  Client, host, connecting to server must have 
+both valid IP address and fully qualified domain name (FQDN).
+
+After that client and server performs SILC Key Exchange protocol which
+will provide the key material used later in the communication.  The
+key exchange protocol must be completed successfully before the connection
+registration may continue.  The SILC Key Exchange protocol is described
+in [SILC3].
+
+Typical server implementation would keep a list of connections that it
+allows to connect to the server.  The implementation would check, for
+example, the connecting client's IP address from the connection list
+before the SILC Key Exchange protocol has been started.  Reason for
+this is that if the host is not allowed to connect to the server there
+is no reason to perform a key exchange protocol.
+
+After successful key exchange protocol the client and server performs
+connection authentication protocol.  The purpose of the protocol is to
+authenticate the client connecting to the server.  Flexible
+implementation could also accept the client to connect to the server
+without explicit authentication.  However, if authentication is
+desired for a specific client it may be based on passphrase or
+public key authentication.  If authentication fails the connection
+must be terminated.  The connection authentication protocol is described
+in [SILC3].
+
+After successful key exchange and authentication protocol the client
+registers itself by sending SILC_PACKET_NEW_CLIENT packet to the
+server.  This packet includes various information about the client
+that the server uses to create the client.  Server creates the client
+and sends SILC_PACKET_NEW_ID to the client which includes the created
+Client ID that the client must start using after that.  After that
+all SILC packets from the client must have the Client ID as the
+Source ID in the SILC Packet Header, described in [SILC2].
+
+Client must also get the server's Server ID that is to be used as
+Destination ID in the SILC Packet Header when communicating with
+the server (for example when sending commands to the server).  The
+ID may be resolved in two ways.  Client can take the ID from an
+previously received packet from server that must include the ID,
+or to send SILC_COMMAND_INFO command and receive the Server ID as
+command reply.
+
+Server may choose not to use the information received in the
+SILC_PACKET_NEW_CLIENT packet.  For example, if public key or 
+certificate were used in the authentication, server may use those
+informations rather than what it received from client.  This is suitable
+way to get the true information about client if it is available.
+
+The nickname of client is initially set to the username sent in the
+SILC_PACKET_NEW_CLIENT packet.  User should set the nickname to more
+suitable by sending SILC_COMMAND_NICK command.  However, this is not
+required as part of registration process.
+
+Server must also distribute the information about newly registered
+client to its router (or if the server is router, to all routers in
+the SILC network).  More information about this in [SILC2].
+
+
+.ti 0
+4.2 Creating Server Connection
+
+This section descibres the procedure when server connects to its
+router (or when router connects to other router, the cases are
+equivalent).  The procedure is very much alike when client connects
+to the server thus it is not repeated here.
+
+One difference is that server must perform connection authentication
+protocol with proper authentication.  Proper authentication is based
+on passphrase or public key authentication.
+
+After server and router has successfully performed the key exchange
+and connection authentication protocol, the server register itself
+to the router by sending SILC_PACKET_NEW_SERVER packet.  This packet
+includes the server's Server ID that it has created by itself and
+other relevant information about the server.
+
+After router has received the SILC_PACKET_NEW_SERVER packet it
+distributes the information about newly registered server to all routers
+in the SILC network.  More information about this in [SILC2].
+
+As client needed to resolve the destination ID this must be done by the
+server that connected to the router, as well.  The way to resolve it is
+to get the ID from previously received packet.  Server must also start
+using its own Server ID as Source ID in SILC Packet Header and the
+router's Server ID as Destination when communicating with the router.
+
+If the server has already connected clients and locally created
+channels the server must distribute these informations to the router.
+The distribution is done by sending packet SILC_PACKET_NEW_CHANNEL.
+See [SILC2] for more information on this.
+
+
+.ti 0
+4.3 Joining to a Channel
+
+This section describes the procedure when client joins to a channel.
+Client may join to channel by sending command SILC_COMMAND_JOIN to the
+server.  If the receiver receiving join command is normal server the
+server must check its local list whether this channel already exists
+locally.  This would indicate that some client connected to the server
+has already joined to the channel.  If this is case the client is
+joined to the client, new channel key is created and information about
+newly joined channel is sent to the router.  The new channel key is
+also distributed to the router and to all clients on the channel.
+
+If the channel does not exist in the local list the command must be
+sent to the router which will then perform the actual joining
+procedure.  When server receives the reply to the command from the
+router it must be distributed to the client who sent the command
+originally.  Server will also receive the channel key from the server
+that it must distribute to the client who originally requested the
+join command.  The server must also save the channel key.
+
+If the receiver of the join command is router it must first check its
+local list whether anyone in the cell has already joined to the channel.
+If this is the case the client is joined to the channel and reply is
+sent to the client.  If the command was sent by server the command reply
+is sent to the server who sent it.  Then the router must also create
+new channel key and distribute it to all clients on the channel and
+all servers that has clients on the channel.
+
+If the channel does not exist on the router's local list it must
+check the global list whether the channel exists at all.  If it does
+the client is joined to the channel as described previously.  If
+the channel does not exist the channel is created and the client
+is joined to the channel.  The channel key is also created and
+distributed as previously described.  The client joining to the created
+channel is made automatically channel founder and both channel founder
+and channel operator privileges is set for the client.
+
+When the router joins the client to the channel it must send 
+information about newly joined client to all routers in the SILC 
+network.  Also, if the channel was created in the process, information
+about newly created channel must also be distributed to all routers.
+The distribution of newly created channel is done by sending packet
+SILC_PACKET_NEW_CHANNEL.
+
+It is important to note that new channel key is created always when
+new client joins to channel, whether the channel has existed previously
+or not.  This way the new client on the channel is not able to decrypt
+any of the old traffic on the channel.
+
+Client who receives the reply to the join command must start using
+the received Channel ID in the channel message communication thereafter.
+However, client must not start communicating on the channel before
+it has received the packet SILC_PACKET_CHANNEL_KEY.
+
+If client wants to know the other clients currently on the channel
+the client must send SILC_COMMAND_NAMES command to receive a list of
+channel users.  Server implementation, however, may send command reply
+packet to SILC_COMMAND_NAMES command after client has joined to the
+channel even if the client has not sent the command.
+
+
+.ti 0
+4.4 Channel Key Generation
+
+Channel keys are created by router who creates the channel by taking
+enough randomness from cryptographically strong random number generator.
+The key is generated always when channel is created, when new client
+joins a channel and after the key has expired.  Key could expire for
+example in an hour.
+
+The key must also be re-generated whenever some client leaves a channel.
+In this case the key is created from scratch by taking enough randomness
+from the random number generator.  After that the key is distributed to
+all clients on the channel.  However, channel keys are cell specific thus
+the key is created only on the cell where the client, who leaved the
+channel, exists.  While the server or router is creating the new channel
+key, no other client may join to the channel.  Messages that are sent
+while creating the new key are still processed with the old key.  After
+server has sent the SILC_PACKET_CHANNEL_KEY packet must client start
+using the new key.  If server creates the new key the server must also
+send the new key to its router.  See [SILC2] on more information about
+how channel messages must be encrypted and decrypted when router is
+processing them.
+
+
+.ti 0
+4.5 Private Message Sending and Reception
+
+Private messages are sent point to point.  Client explicitly destines
+a private message to specific client that is delivered to only to that
+client.  No other client may receive the private message.  The receiver
+of the private message is destined in the SILC Packet Header as any
+other packet as well.
+
+If the sender of a private message does not know the receiver's Client
+ID, it must resolve it from server.  There are two ways to resolve the
+client ID from server; it is recommended that client ipmlementations
+send SILC_COMMAND_IDENTIFY command to receive the Client ID.  Client
+may also send SILC_COMMAND_WHOIS command to receive the Client ID.
+If the sender has received earlier a private message from the receiver
+it should have cached the Client ID from the SILC Packet Header.
+
+Receiver of a private message should not explicitly trust the nickname
+that it receives in the Private Message Payload, described in [SILC2].
+Implementations could resolve the nickname from server, as described
+previously, and compare the received Client ID and the SILC Packet
+Header's Client ID.  The nickname in the payload is merely provided
+to be displayed for end user.
+
+See [SILC2] for describtion of private message encryption and decryption
+process.
+
+
+.ti 0
+4.6 Private Message Key Generation
+
+Private message may be protected by key generated by client.  The key
+may be generated and sent to the other client by sending packet
+SILC_PACKET_PRIVATE_MESSAGE_KEY which travels through the network
+and is secured by session keys.  After that the private message key
+is used in the private message communication between those clients.
+See more information about how this works technically in [SILC2].
+
+Other choice is to entirely use keys that are not sent through
+the SILC network at all.  This significantly adds security.  This key
+would be pre-shared-key that is known by both of the clients.  Both
+agree about using the key and starts sending packets that indicate
+that the private message is secured using private message key.  This
+is the technical aspect mentioned previously that is described
+in [SILC2].
+
+If the private message keys are not set to be used, which is the
+case by default in SILC, the private messages are secured by using
+normal session keys established by SILC Key Exchange protocol.
+
+
+.ti 0
+4.7 Channel Message Sending and Reception
+
+Channel messages are delivered to group of users.  The group forms a
+channel and all clients on the channel receives messages sent to the
+channel.
+
+Channel messages are destined to channel by specifying the Channel ID
+as Destination ID in the SILC Packet Header.  The server must then
+distribute the message to all clients on the channel by sending the
+channel message destined explicitly to a client on the channel.
+
+See [SILC2] for describtion of channel message encryption and decryption
+process.
+
+
+.ti 0
+4.8 Session Key Regeneration
+
+Session keys should be regenerated peridiocally, say, once in an hour.
+The re-key process is started by sending SILC_PACKET_REKEY packet to
+other end, to indicate that re-key must be performed.
+
+If perfect forward secrecy (PFS) flag was selected in the SILC Key
+Exchange protocol [SILC3] the re-key must cause new key exchange with
+SKE protocol.  In this case the protocol is secured with the old key
+and the protocol results to new key material.  See [SILC3] for more
+information.  After the SILC_PACKET_REKEY packet is sent the sender
+will perform the SKE protocol.
+
+If PFS flag was not set, which is the default case, then re-key is done
+without executing SKE protocol.  In this case, the new key is created by
+hashing the old key with hash function selected earlier in the SKE
+protocol.  If the digest length of the hash function is too short for the
+key, then the key is distributed as described in section Processing the
+Key Material in [SILC3].  After both parties has regenerated the session
+key, both send SILC_PACKET_REKEY_DONE packet to each other.  These packets
+are still secured with the old key.  After these packets, following
+packets must be protected with the new key.
+
+
+.ti 0
+4.9 Command Sending and Reception
+
+Client usually sends the commands in the SILC network.  In this case
+the client simply sends the command packet to server and the server
+processes it and replies with command reply packet.
+
+However, if the server is not able to process the command, it is usually
+sent to the server's router.  This is case for example with commands such
+as, SILC_COMMAND_JOIN and SILC_COMMAND_WHOIS commands.  However, there
+are other commands as well.  For example, if client sends the WHOIS
+command requesting specific information about some client the server must
+send the WHOIS command to router so that all clients in SILC network
+are searched.  The router, on the other hand, sends the WHOIS command
+to further to receive the exact information about the requested client.
+The WHOIS command travels all the way to the server who owns the client
+and it replies with command reply packet.  Finally, the server who
+sent the command receives the command reply and it must be able to
+determine which client sent the original command.  The server then
+sends command reply to the client.  Implementations should have some
+kind of cache to handle, for example, WHOIS information.  Servers
+and routers along the route could all cache the information for faster
+referencing in the future.
+
+The commands sent by server may be sent hop by hop until someone is able
+to process the command.  However, it is preferred to destine the command
+as precisely as it is possible.  In this case, other routers en route
+must route the command packet by checking the true sender and true
+destination of the packet.  However, servers and routers must not route
+command reply packets to clients coming from other server.  Client
+must not accept command reply packet originated from anyone else but
+from its own server.
+
+
+.ti 0
+5 SILC Commands
+
+.ti 0
+5.1 SILC Commands Syntax
+
+This section briefly describes the syntax of the command notions
+in this document.  Every field in command is separated from each
+other by whitespaces (` ') indicating that each field is independent
+argument and each argument must have own Command Argument Payload.
+The number of maximum arguments are defined with each command
+separately.  The Command Argument Payload is described in [SILC2].
+
+Every command defines specific number for each argument.  Currently,
+they are defined in ascending order; first argument has number one 
+(1), second has number two (2) and so on.  This number is set into the
+Argument Type field in the Command Argument Payload.  This makes it
+possible to send the arguments in free order as the number must be
+used to identify the type of the argument.  This makes is it also
+possible to have multiple optional arguments in commands and in
+command replies.  The number of argument is marked in parentheses
+before the actual argument.
+
+.in 6
+Example:  Arguments:  (1) <nickname> (2) <username@host>
+.in 3
+   
+
+Every command replies with Status Payload.  This payload tells the
+sender of the command whether the command was completed succefully or
+whether there was an error.  If error occured the payload includes the
+error type.  In the next section the Status Payload is not described 
+as it is common to all commands and has been described here.  Commands 
+may reply with other arguments as well.  These arguments are command 
+specific and are described in the next section.
+
+Example command:
+.in 6
+
+EXAMPLE_COMMAND
+
+.in 8
+Max Arguments:  3
+    Arguments:  (1) <nickname>[@<server>]  (2) <message>
+                (3) [<count>]
+
+The command has maximum of 3 arguments.  However, only first
+and second arguments are mandatory.
+
+First argument <nickname> is mandatory but may have optional
+<nickname@server> format as well.  Second argument is mandatory
+<message> argument.  Third argument is optional <count> argument.
+
+The numbers in parentheses are the argument specific numbers
+that specify the type of the argument in Command Argument Payload.
+The receiver always knows that, say, argument number two (2) is
+<message> argument, regardles of the ordering of the arguments in
+the Command Payload.
+
+Reply messages to the command:
+
+Max Arguments:  4
+    Arguments:  (1) <Status Payload>  (2) [<channel list>]
+                (3) <idle time>       (4) [<away message>]
+
+This command may reply with maximum of 4 arguments.  However,
+only the first and third arguments are mandatory.  The numbers
+in the parentheses have the same meaning as in the upper
+command sending specification.
+
+Every command reply with <Status Payload>, it is mandatory 
+argument for all command replies and for this reason it is not
+described in the command reply descriptions.
+
+Status messages:
+
+    SILC_STATUS_OK
+    SILC_STATUS_ERR_TOO_MANY_TARGETS
+    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+    SILC_STATUS_ERR_NO_SUCH_NICK
+
+Every command reply also defines set of status message that it
+may return inside the <Status Payload>.  All status messages
+are defined in the section 5.3 SILC Command Status Types.
+.in 3
+
+
+.ti 0
+5.2 SILC Commands List
+
+This section lists all SILC commands, however, it is expected that a
+implementation and especially client implementation has many more
+commands that has only local affect.  These commands are official
+SILC commands that has both client and server sides and cannot be
+characterized as local commands.
+
+List of all defined commands in SILC follows.
+
+.in 0
+   0    SILC_COMMAND_NONE
+
+        None.  This is reserved command and must not be sent.
+
+
+   2    SILC_COMMAND_WHOIS
+
+        Max Arguments:  2
+            Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
+
+        Whois.  Whois command is used to query various information about
+        specific user.  The user maybe requested by their nickname and
+        server name.  The query may find multiple matching users as
+        there are no unique nicknames in the SILC.  The <count> option
+        maybe given to narrow down the number of accepted results.  If
+        this is not defined there are no limit of accepted results.
+        The query may also be narrowed down by defining the server name
+        of the nickname.
+
+        To prevent miss-use of this service wildcards in the nickname
+        or in the servername are not permitted.  It is not allowed
+        to request all users on some server.  The WHOIS requests must 
+        be based on specific nickname request.
+
+        The WHOIS request must be always forwarded to router by server
+        so that all users are searched.  However, the server still must
+        search its locally connected clients.  The server must send
+        this command to the server who owns the requested client.  That
+        server must reply to the command.
+
+        Reply messages to the command:
+
+        Max Arguments:  7
+            Arguments:  (1) <Status Payload>       (2) <Client ID> 
+                        (3) <nickname>[@<server>]  (4) <username@host> 
+                        (5) <real name>            (6) [<channel list>] 
+                        (7) [<idle time>]
+
+        This command may reply with several command reply messages to
+        form a list of results.  In this case the status payload will
+        include STATUS_LIST_START status in the first reply and
+        STATUS_LIST_END in the last reply to indicate the end of the
+        list.  If there are only one reply the status is set to normal
+        STATUS_OK.
+
+        The command replies include the Client ID of the nickname,
+        nickname and servername, username and hostnamea and users real
+        name.  Client should process these replies only after the last
+        reply has been received with the STATUS_LIST_END status.  If the
+        <count> option were defined in the query there will be only
+        <count> many replies from the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   3    SILC_COMMAND_WHOWAS
+
+        Max Arguments:  2
+            Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
+
+        Whowas.  This command is used to query history information about
+        specific user.  The user maybe requested by their nickname and 
+        server name.  The query may find multiple matching users as there
+        are no unique nicknames in the SILC.  The <count> option maybe
+        given to narrow down the number of accepted results.  If this
+        is not defined there are no limit of accepted results.  The query
+        may also be narrowed down by defining the server name of the 
+        nickname.
+
+        To prevent miss-use of this service wildcards in the nickname
+        or in the servername are not permitted.  The WHOWAS requests must 
+        be based on specific nickname request.
+
+        The WHOWAS request must be always forwarded to router by server
+        so that all users are searched.  However, the server still must
+        search its locally connected clients.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <nickname>[@<server>]
+                        (3) <username@host>
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in 
+        the last reply to indicate the end of the list.  If there are only 
+        one reply the status is set to normal STATUS_OK.
+
+        The command replies with nickname and username and hostname.
+        Every server must keep history for some period of time of its
+        locally connected clients.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   4    SILC_COMMAND_IDENTIFY
+
+        Max Arguments:  2
+            Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
+
+        Identify.  Identify command is almost analogous to WHOIS command,
+        except that it does not return as much information.  Only relevant
+        information such as Client ID is returned.  This is usually used
+        to get the Client ID of a client used in the communication with
+        the client.
+
+        The query may find multiple matching users as there are no unique 
+        nicknames in the SILC.  The <count> option maybe given to narrow 
+        down the number of accepted results.  If this is not defined there 
+        are no limit of accepted results.  The query may also be narrowed 
+        down by defining the server name of the nickname.
+
+        To prevent miss-use of this service wildcards in the nickname
+        or in the servername are not permitted.  It is not allowed
+        to request all users on some server.  The IDENTIFY requests must 
+        be based on specific nickname request.
+
+        Implementations may not want to give interface access to this
+        commands as it is hardly a command that would be used a end user.
+        However, it must be implemented as it is used with private message
+        sending.
+
+        The IDENTIFY must be always forwarded to router by server so that
+        all users are searched.  However, server must still search its
+        locally connected clients.
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>         (2) <Client ID>
+                        (3) [<nickname>[@<server>]]  (4) [<username@host>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in 
+        the last reply to indicate the end of the list.  If there are only 
+        one reply the status is set to normal STATUS_OK.
+
+        The command replies with Client ID of the nickname and if more
+        information is available it may reply with nickname and username
+        and hostname.  If the <count> option were defined in the query
+        there will be only <count> many replies from the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   5    SILC_COMMAND_NICK
+
+        Max Arguments:  1
+            Arguments:  (1) <nickname>
+
+        Set/change nickname.  This command is used to set nickname for
+        user.  There is no limit of the length of the nickname in SILC.
+        Nickname must not include any spaces (` '), non-printable
+        characters, commas (`,') and any wildcard characters.  Note:
+        nicknames in SILC are case-sensitive which must be taken into
+        account when searching clients by nickname.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <New ID Payload>
+
+        This command is replied always with New ID Payload that is
+        generated by the server every time user changes their nickname.
+        Client receiving this payload must start using the received
+        Client ID as its current valid Client ID.  The New ID Payload
+        is described in [SILC2].
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NICKNAME_IN_USE
+            SILC_STATUS_ERR_BAD_NICKNAME
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   6    SILC_COMMAND_LIST
+
+        Max Arguments:  2
+            Arguments:  (1) [<Channel ID>] [<server>]
+
+        The list command is used to list channels and their topics on
+        current server.  If the <Channel ID> parameter is used, only the
+        status of that channel is displayed.  Secret channels are not
+        listed at all.  Private channels are listed with status indicating
+        that the channel is private.
+
+        If the <server> argument is specified the specified server's
+        channels are listed.  In this case the command must be sent to
+        the server who owns the channel that was requested.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <channel>
+                        (3) <topic>
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in 
+        the last reply to indicate the end of the list.  If there are only 
+        one reply the status is set to normal STATUS_OK.
+
+        This command replies with channel name and the topic of the
+        channel.  If the channel is private channel the <topic> includes
+        "*private*" string.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+   7    SILC_COMMAND_TOPIC
+
+        Max Arguments:  2
+            Arguments:  (1) <Channel ID>  (2) [<server>]]
+
+        This command is used to change or view the topic of a channel.
+        The topic for channel <Channel ID> is returned if there is no
+        <topic> given.  If the <topic> parameter is present, the topic
+        for that channel will be changed, if the channel modes permit
+        this action.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) [<topic>]
+
+        The command may reply with the topic of the channel if it is
+        set.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+
+   8    SILC_COMMAND_INVITE
+
+        Max Arguments:  2
+            Arguments:  (1) <Client ID>  (2) <channel>
+
+        This command is used to invite other clients to join to the
+        channel.  There is no requirement that the channel the target
+        client is being invited to must exist or be a valid channel.
+        The <Client ID> argument is the target client's ID that is being
+        invited.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_RECIPIENT
+            SILC_STATUS_ERR_USER_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   9    SILC_COMMAND_QUIT
+
+        Max Arguments:  1
+            Arguments:  (1) [<quit message>]
+
+        This command is used by client to end SILC session.  The server
+        must close the connection to a client which sends this command.
+        if <quit message> is given it will be sent to other clients on
+        channel if the client is on channel when quitting.
+
+        Reply messages to the command:
+
+        This command does not reply anything.
+
+
+   10   SILC_COMMAND_KILL
+
+        Max Arguments:  2
+            Arguments:  (1) <Client ID>  (2) [<comment>]
+
+        This command is used by SILC operators to remove a client from
+        SILC network.  The removing has temporary effects and client may
+        reconnect to SILC network.  The <Client ID> is the client to be
+        removed from SILC.  The <comment> argument may be provided to 
+        give to the removed client some information why it was removed
+        from the network.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   11   SILC_COMMAND_INFO
+
+        Max Arguments:  1
+            Arguments:  (1) [<server>]
+
+        This command is used to fetch various information about a server.
+        If <server> argument is specified the command must be sent to
+        the requested server.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) <string>
+
+        This command replies with the Server ID of the server and a
+        string which tells the information about the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+
+
+   12   SILC_COMMAND_CONNECT
+
+        Max Arguments:  2
+            Arguments:  (1) <Server ID>  
+                        (2) [<remote server/router>[:<port>]]
+
+        This command is used by operators to force a server to try to
+        establish a new connection to another router (if the connecting
+        server is normal server) or server (if the conneceting server is
+        router server).  Operator may specify the server/router to be
+        connected by setting <remote server> argument.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+            SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+
+   13   SILC_COMMAND_PING
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used by clients to test the communication
+        channel to its server if client suspects that the communication
+        is not working correctly.  The <Server ID> is the ID of the
+        server the client is connected to.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.  Server returns
+        SILC_STATUS_OK in Status Payload if pinging was successful.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NOT_REGISTERED
+
+
+   14   SILC_COMMAND_OPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication data>
+
+        This command is used by normal client to obtain server operator
+        privileges on some server or router.  Note that router operator
+        has router privileges that supersedes the server operator
+        privileges and this does not obtain those privileges.  Client
+        must use SILCOPER command to obtain router level privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication data> is the data that the
+        client is authenticated against.  It may be passphrase prompted
+        for user on client's screen or it may be public key
+        authentication data (data signed with private key), or 
+        certificate.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_BAD_PASSWORD
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   15   SILC_COMMAND_JOIN
+
+        Max Arguments:  3
+            Arguments:  (1) <channel>  (2) [<passphrase>] 
+                        (3) [<cipher>]
+
+        Join to channel/create new channel.  This command is used to
+        join to a channel.  If the channel does not exist the channel is
+        created on the server receiving the join request.  The channel 
+        may be protected with passphrase.  If this is the case the 
+        passphrase must be sent along the join command.
+
+        The name of the <channel> must not include any spaces (` '),
+        non-printable characters, commas (`,') or any wildcard characters.
+
+        Cipher to be used to secure the traffic on the channel may be
+        requested by sending the name of the requested <cipher>.  This
+        is used only if the channel does not exist and is created.  If
+        the channel already exists the cipher set previously for the
+        channel will be used to secure the traffic.
+
+        The server must check whether the user is allowed to join to
+        the requested channel.  Various modes set to the channel affect
+        the ability of the user to join the channel.  These conditions
+        are:
+
+            o  The user must be invited to the channel if the channel
+               is invite-only channel.
+
+            o  The Client ID/nickname/username/hostname must not match
+               any active bans.
+
+            o  The correct passphrase must be provided if passphrase 
+               is set to the channel.
+
+            o  The user count limit, if set, must not be reached.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>  (2) <channel> 
+                        (3) <Channel ID>      (4) <channel mode mask>
+                        (5) [<topic>]
+
+        This command replies with the channel name requested by the
+        client, channel ID of the channel and topic of the channel
+        if it exists.  It also replies with the channel mode mask
+        which tells all the modes set on the channel.  If the
+        channel is created the mode mask is zero (0).
+
+        Client must not start transmitting to the channel even after
+        server has replied to this command.  Client is permitted to 
+        start transmitting on channel after server has sent packet 
+        SILC_PACKET_CHANNEL_KEY to the client.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_BAD_PASSWORD
+            SILC_STATUS_ERR_CHANNEL_IS_FULL
+            SILC_STATUS_ERR_NOT_INVITED
+            SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+            SILC_STATUS_ERR_BAD_CHANNEL
+            SILC_STATUS_ERR_USER_ON_CHANNEL
+
+
+   16   SILC_COMMAND_MOTD
+
+        Max Arguments:  1
+            Arguments:  (1) <server>
+
+        This command is used to query the Message of the Day of a server.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) [<motd>]
+
+        This command replies with the motd message if it exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+   17   SILC_COMMAND_UMODE
+
+        Max Arguments:  2
+            Arguments:  (1) <Client ID>  (2) <client mode mask>
+
+        This command is used by client to set/unset modes for itself.
+        However, there are some modes that the client may not set itself,
+        but they will be set by server.  However, client may unset any
+        mode.  Modes may be masked together ORing them thus having
+        several modes set.  Client must keep its client mode mask
+        locally so that the mode setting/unsetting would work without
+        problems.  Client may change only its own modes.
+
+        Following client modes are defined:
+
+           0x0000    SILC_UMODE_NONE
+
+              No specific mode for client.  This is the initial
+              setting when new client is created.  The client is
+              normal client now.
+
+
+           0x0001    SILC_UMODE_SERVER_OPERATOR
+
+              Marks the user as server operator.  Client cannot
+              set this mode itself.  Server sets this mode to the
+              client when client attains the server operator
+              privileges by SILC_COMMAND_OPER command.  Client
+              may unset the mode itself.
+
+
+           0x0002    SILC_UMODE_ROUTER_OPERATOR
+
+              Marks the user as router (SILC) operator.  Client
+              cannot this mode itself.  Router sets this mode to
+              the client when client attains the router operator
+              privileges by SILC_COMMAND_SILCOPER command.  Client
+              may unset the mode itself.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <client mode mask>
+
+        This command replies with the changed client mode mask that
+        the client is required to keep locally.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_BAD_CLIENT_ID
+            SILC_STATUS_ERR_NOT_YOU
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_RECIPIENT
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   18   SILC_COMMAND_CMODE
+
+        Max Arguments:  6
+            Arguments:  (1) <Channel ID>    (2) <channel mode mask>
+                        (3) [<user limit>]  (4) [<passphrase>]
+                        (5) [<Client ID>]   (6) [<cipher>[:<key len>]]
+
+        This command is used by client to set or change channel flags on
+        a channel.  Channel has several modes that set various properties
+        of a channel.  Modes may be masked together by ORing them thus
+        having several modes set.  The <Channel ID> is the ID of the
+        target channel.  The client changing channel mode must be on
+        the same channel and poses sufficient privileges to be able to
+        change the mode.
+
+        Following channel modes are defined:
+
+           0x0000    SILC_CMODE_NONE
+
+              No specific mode on channel.  This is the default when
+              channel is created.  This means that channel is just plain
+              normal channel.
+
+
+           0x0001    SILC_CMODE_PRIVATE
+
+              Channel is private channel.  Private channels are shown
+              in the channel list listed with SILC_COMMAND_LIST command
+              with indicatioin that the channel is private.  Also,
+              client on private channel will no be detected to be on
+              the channel as the channel is not shown in the client's
+              currently joined channel list.  Channel founder and 
+              channel operator may set/unset this mode.
+
+              Typical implementation would use [+|-]p on user interface
+              to set/unset this mode.
+
+
+           0x0002    SILC_CMODE_SECRET
+
+              Channel is secret channel.  Secret channels are not shown
+              in the list listed with SILC_COMMAND_LIST command.  Secret
+              channels can be considered to be invisible channels.
+              Channel founder and channel operator may set/unset this
+              mode.
+
+              Typical implementation would use [+|-]s on user interface
+              to set/unset this mode.
+
+
+           0x0004    SILC_CMODE_PRIVKEY
+
+              Channel uses private channel key to protect the traffic
+              on the channel.  When this mode is set the client will be
+              responsible to set the key it wants to use to encrypt and
+              decrypt the traffic on channel.  Server generated channel
+              keys are not used at all.  This mode provides additional
+              security as clients on channel may agree to use private
+              channel key that even servers do not know.  Naturally,
+              this requires that every client on the channel knows
+              the key before hand (it is considered to be pre-shared-
+              key).  This specification does not define how the private
+              channel key is set as it is entirely local setting on
+              client end.
+
+              As it is local setting it is possible to have several
+              private channel keys on one channel.  In this case several
+              clients can talk on same channel but only those clients
+              that share the key with the message sender will be able
+              to hear the talking.  Client should not display those
+              message for the end user that it is not able to decrypt
+              when this mode is set.
+
+              Only channel founder may set/unset this mode.  If this
+              mode is unset the server will distribute new channel
+              key to all clients on the channel which will be used
+              thereafter.
+
+              Typical implementation would use [+|-]k on user interface
+              to set/unset this mode.
+
+
+           0x0008    SILC_CMODE_INVITE
+
+              Channel is invite only channel.  Client may join to this
+              channel only if it is invited to the channel.  Channel
+              founder and channel operator may set/unset this mode.
+
+              Typical implementation would use [+|-]i on user interface
+              to set/unset this mode.
+
+
+           0x0010    SILC_CMODE_TOPIC
+
+              The topic of the channel may only be set by client that
+              is channel founder or channel operator.  Normal clients
+              on channel will not be able to set topic when this mode
+              is set.  Channel founder and channel operator may set/
+              unset this mode.
+
+              Typical implementation would use [+|-]t on user interface
+              to set/unset this mode.
+
+
+           0x0020    SILC_CMODE_ULIMIT
+
+              User limit has been set to the channel.  New clients
+              may not join to the channel when the limit set is
+              reached.  Channel founder and channel operator may set/
+              unset the limit.  The <user limit> argument is the
+              number of limited users.
+
+              Typical implementation would use [+|-]l on user interface
+              to set/unset this mode.
+
+
+           0x0040    SILC_CMODE_PASSPHRASE
+
+              Passphrase has been set to the channel.  Client may
+              join to the channel only if it is able to provide the
+              correct passphrase.  Setting passphrases to channel
+              is entirely safe as all commands are protected in the
+              SILC network.  Only channel founder may set/unset
+              the passphrase.  The <passphrase> argument is the
+              set passphrase.
+
+              Typical implementation would use [+|-]a on user interface
+              to set/unset this mode.
+
+
+           0x0080    SILC_CMODE_BAN
+
+              Ban mask has been set to the channel.  The ban mask
+              may be used to ban specific clients to join the channel.
+              The <ban mask> argument is the set ban mask.  When
+              unsetting a ban mask the mask must be provided as
+              argument.  Channel founder and channel operator may
+              set/unset this mode.  Channel founder may not be
+              added to the ban list.
+
+              Typical implementation would use [+|-]b on user interface
+              to set/unset this mode.
+
+        
+           0x0100    SILC_CMODE_OPERATOR
+
+              Sets channel operator privileges on the channel for a
+              client on the channel.  The <Client ID> argument is the
+              target client on the channel.  Channel founder and
+              channel operator may set/unset (promote/demote) this
+              mode.
+
+              Typical implementation would use [+|-]o on user interface
+              to set/unset this mode.
+
+
+           0x0200    SILC_CMODE_CIPHER
+
+              Sets specific cipher to be used to protect channel
+              traffic.  The <cipher> argument is the requested cipher.
+              When set or unset the server must re-generate new
+              channel key.  If <key len> argument is specified with
+              <cipher> argument the new key is generated of <key len>
+              length.
+
+              Typical implementation would use [+|-]c on user interface
+              to set/unset this mode.
+
+
+        To make the mode system work, client must keep the channel mode
+        mask locally so that the mode setting and unsetting would work
+        without problems.  The client receives the initial channel mode
+        mask when it joins to the channel.  When the mode changes on
+        channel the server distributes the changed channel mode mask to
+        all clients on the channel by sending SILC_COMMAND_CMODE command
+        reply packet.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <channel mode mask>
+
+        This command replies with the changed channel mode mask that
+        client is required to keep locally.  The same mask is also
+        sent to all clients on channel by sending additional command
+        reply to them.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   19   SILC_COMMAND_KICK
+
+        Max Arguments:  3
+            Arguments:  (1) <channel>  (2) <Client ID>  
+                        (3) [<comment>]
+
+        This command is used by channel operators to remove a client from
+        channel.  The <channel> argument is the channel the client to be
+        removed is on currently.  Note that the "kicker" must be on the same
+        channel.  If <comment> is provided it will be sent to the removed
+        client.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   20   SILC_COMMAND_RESTART
+
+        Max Arguments:  0
+            Arguments:  None
+
+        This command may only be used by server operator to force a
+        server to restart itself.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+
+
+   21   SILC_COMMAND_CLOSE
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used only by operator to close connection to a
+        remote site.  The <Server ID> argument is the ID of the remote
+        site and must be valid.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+
+   22   SILC_COMMAND_DIE
+
+        Max Arguments:  0
+            Arguments:  None
+
+        This command is used only by operator to shutdown the server.
+        All connections to the server will be closed and the server is
+        shutdown.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+
+
+   23   SILC_COMMAND_SILCOPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication data>
+
+        This command is used by normal client to obtain router operator
+        privileges (also known as SILC operator) on some router.  Note
+        that router operator has router privileges that supersedes the
+        server operator privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication data> is the data that the
+        client is authenticated against.  It may be passphrase prompted
+        for user on client's screen or it may be public key
+        authentication data (data signed with private key), or 
+        certificate.
+
+        Difference between router operator and server operator is that
+        router operator is able to handle cell level properties while
+        server operator (even on router server) is able to handle only
+        local properties, such as, local connections and normal server
+        administration.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_BAD_PASSWORD
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   24   SILC_COMMAND_LEAVE
+
+        Max Arguments:  1
+            Arguments:  (1) <Channel ID>
+
+        This command is used by client to leave a channel the client is
+        joined to.  After a client has leaved the channel the server
+        must create new key for the channel and distribute to all clients
+        still currently on the channel.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+
+
+   25   SILC_COMMAND_NAMES
+
+        Max Arguments:  1
+            Arguments:  (1) <Channel ID>
+
+        This command is used to list user names currently on the requested
+        channel; argument <Channel ID>.  The server must resolve the
+        user names and send a comma (`,') separated list of user names
+        on the channel.  Server or router may resolve the names by sending
+        SILC_COMMAND_WHOIS commands.
+
+        If the requested channel is a private or secret channel, this
+        command must not send the list of users, as private and secret
+        channels cannot be seen by outside.  In this case the returned
+        name list may include a indication that the server could not 
+        resolve the names of the users on the channel.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <name list>
+
+        This command replies with the comma separated list of users on
+        the channel.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+
+   26 - 254
+
+        Currently undefined commands.
+
+
+   255  SILC_COMMAND_MAX
+
+        Reserved command.  This must not be sent.
+.in 3
+
+
+.ti 0
+5.3 SILC Command Status Types
+
+.ti 0
+5.3.1 SILC Command Status Payload
+
+Command Status Payload is sent in command reply messages to indicate
+the status of the command.  The payload is one of argument in the
+command thus this is the data area in Command Argument Payload described
+in [SILC2].  The payload is only 2 bytes of length.  Following diagram
+represents the Command Status Payload (field is always in MSB order).
+
+
+.in 21
+.nf
+                     1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Status Message         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  SILC Command Status Payload
+
+
+.in 6
+o Status Message (2 bytes) - Indicates the status message.
+  All Status messages are described in the next section.
+.in 3
+
+
+.ti 0
+5.3.2 SILC Command Status List
+
+Command Status messages are returned in the command reply messages
+to indicate whether the command were executed without errors.  If error
+has occured the status tells which error occured.  Status payload only
+sends numeric reply about the status.  Receiver of the payload must
+convert the numeric values into human readable error messages.  The
+list of status messages below has an example human readable error
+messages that client may display for the user.
+
+List of all defined command status messages following.
+
+.in 0
+   Generic status messages:
+
+   0    SILC_STATUS_OK
+
+        Ok status.  Everything went Ok.  The status payload maybe
+        safely ignored in this case.
+
+   1    SILC_STATUS_LIST_START
+
+        Start of the list.  There will be several command replies and
+        this reply is the start of the list.
+
+   2    SILC_STATUS_LIST_END
+
+        End of the list.  There were several command replies and this
+        reply is the last of the list.  There won't be other replies
+        beloning to this list after this one.
+
+   3 - 9
+
+        Currently undefined and has been reserved for the future.
+
+
+   Error status message:
+
+   10   SILC_STATUS_ERR_NO_SUCH_NICK
+
+        "No such nickname".  Requested nickname does not exist.
+
+   11   SILC_STATUS_ERR_NO_SUCH_CHANNEL
+
+        "No such channel".  Requested channel name does not exist.
+
+   12   SILC_STATUS_ERR_NO_SUCH_SERVER
+
+        "No such server".  Requested server name does not exist.
+
+   13   SILC_STATUS_ERR_TOO_MANY_TARGETS
+
+        "Duplicate recipients. No message delivered".  Message were
+        tried to be sent to recipient which has several occurrences in 
+        the recipient list.
+
+   14   SILC_STATUS_ERR_NO_RECIPIENT
+
+        "No recipient given".  Command required recipient which was
+        not provided.
+
+   15   SILC_STATUS_ERR_UNKNOWN_COMMAND
+
+        "Unknown command".  Command sent to server is unknown by the
+        server.
+
+   16   SILC_STATUS_ERR_WILDCARDS
+
+        "Wildcards cannot be used".  Wildcards were provided but they
+        weren't permitted.
+
+   17   SILC_STATUS_ERR_NO_CLIENT_ID
+
+        "No Client ID given".  Client ID were expected as command
+        parameter but were not found.
+
+   18   SILC_STATUS_ERR_NO_CHANNEL_ID
+
+        "No Channel ID given".  Channel ID were expected as command
+        parameter but were not found.
+
+   19   SILC_STATUS_ERR_BAD_CLIENT_ID
+
+        "Bad Client ID".  Client ID provided were erroneous.
+
+   20   SILC_STATUS_ERR_BAD_CHANNEL_ID
+
+        "Bad Channel ID".  Channel ID provided were erroneous.
+
+   21   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+        "No such Client ID".  Client ID provided does not exist.
+
+
+
+   22   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+
+        "No such Channel ID".  Channel ID provided does not exist.
+
+   23   SILC_STATUS_ERR_NICKNAME_IN_USE
+
+        "Nickname already exists".  Nickname created could not be 
+        registered because number of same nicknames were already set to
+        maximum.  This is not expected to happen in real life but is
+        possible to occur.
+
+   24   SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+        "You are not on that channel".  The command were specified for
+        client user is not currently on.
+
+   25   SILC_STATUS_ERR_USER_ON_CHANNEL
+
+        "User already on channel".  User were invited on channel they
+        already are on.
+
+   26   SILC_STATUS_ERR_NOT_REGISTERED
+
+        "You have not registered".  User executed command that requires
+        the client to be registered on the server before it may be
+        executed.
+
+   27   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+
+        "Not enough parameters".  Command requires more parameters
+        than provided.
+
+   28   SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+        "Too many parameters".  Too many parameters were provided
+        for the command.
+
+   29   SILC_STATUS_ERR_PERM_DENIED
+
+        "Your host is not among the privileged".  The client tried to
+        register on server that does not allow this host to connect.
+
+   30   SILC_STATUS_ERR_BANNED_FROM_SERVER
+
+        "You are banned from this server".  The client tried to register
+        on server that has explicitly denied this host to connect.
+
+
+
+   31   SILC_STATUS_ERR_BAD_PASSWORD
+
+        "Cannot join channel. Incorrect password".  Password provided for 
+        channel were not accepted.
+
+   32   SILC_STATUS_ERR_CHANNEL_IS_FULL
+
+        "Cannot join channel. Channel is full".  The channel is full
+        and client cannot be joined to it.
+
+   33   SILC_STATUS_ERR_NOT_INVITED
+
+        "Cannot join channel. You have not been invited".  The channel
+        is invite only channel and client has not been invited.
+
+   34   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+
+        "Cannot join channel. You have been banned".  The client has
+        been banned from the channel.
+
+   35   SILC_STATUS_ERR_UNKNOWN_MODE
+
+        "Unknown mode".  Mode provided by the client were unknown to
+        the server.
+
+   36   SILC_STATUS_ERR_NOT_YOU
+
+        "Cannot change mode for other users".  User tried to change
+        someone else's mode.
+
+   37   SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+        "Permission denied. You are not channel operator".  Command may 
+        be executed only by channel operator.
+
+   38   SILC_STATUS_ERR_NO_SERVER_PRIV
+
+        "Permission denied. You are not server operator".  Command may
+        be executed only by server operator.
+
+   39   SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+        "Permission denied. You are not SILC operator".  Command may be
+        executed only by router (SILC) operator.
+
+   40   SILC_STATUS_ERR_BAD_NICKNAME
+
+        "Bad nickname".  Nickname requested contained illegal characters
+        or were malformed.
+
+   41   SILC_STATUS_ERR_BAD_CHANNEL
+
+        "Bad channel name".  Channel requested contained illegal characters
+        or were malformed.
+
+   42   SILC_STATUS_ERR_AUTH_FAILED
+
+        "Authentication failed".  The authentication data sent as 
+        argument were wrong and thus authentication failed.
+.in 3
+
+
+.ti 0
+6 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+7 References
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             June 2000.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication 
+             Protocols", Internet Draft, June 2000.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol", 
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key 
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exhange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+
+.ti 0
+8 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
diff --git a/doc/example_silc.conf b/doc/example_silc.conf
new file mode 100644 (file)
index 0000000..64574a9
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Configured ciphers.
+#
+# Format: <name>:<module path>:<key length>:<block length>
+#
+# If the cipher is builtin the <module path> maybe omitted.
+#
+[cipher]
+twofish-cbc:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6-cbc:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars-cbc:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+#
+# Configured hash functions.
+#
+# Format: <name>:<module path>:<block length>:<digest length>
+#
+# If the hash function is builtin the <module path> maybe omitted.
+#
+[hash]
+md5::64:16
+sha1::64:20
+
+#
+# Configured PKCS.
+#
+# Format: <name>:<module path>:<key length>
+#
+# NOTE: <module path> must be omitted as PKCS cannot be modules currently.
+#
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+#
+# Configured connections to servers.
+#
+# Format: <remote host>:<auth type>:<auth data>:<port>
+#
+# <auth type> maybe `passwd' or `pubkey'.
+#
+[connection]
+#lassi.kuo.fi.ssh.com:passwd::1333
+
+#
+# Commands.  These are executed when SILC client is run.  Normal
+# SILC commands may be executed here.
+#
+# Format: <command>
+#
+[commands]
+/server silc.pspt.fi
diff --git a/doc/example_silcd.conf b/doc/example_silcd.conf
new file mode 100644 (file)
index 0000000..fd67a4c
--- /dev/null
@@ -0,0 +1,149 @@
+#
+# Configured ciphers.
+#
+# Format: <name>:<module path>:<key length>:<block length>
+#
+# If the cipher is builtin the <module path> maybe omitted.
+#
+[cipher]
+twofish-cbc:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
+rc6-cbc:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
+mars-cbc:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
+none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+
+#
+# Configured hash functions.
+#
+# Format: <name>:<module path>:<block length>:<digest length>
+#
+# If the hash function is builtin the <module path> maybe omitted.
+#
+[hash]
+md5::64:16
+sha1::64:20
+
+#
+# Configured PKCS.
+#
+# Format: <name>:<module path>:<key length>
+#
+# NOTE: <module path> must be omitted as PKCS cannot be modules currently.
+#
+#[pkcs]
+#rsa::1024
+#dss::1024
+
+#
+# Server's administrative information.
+#
+# Format: <location>:<server type>:<admin's name>:<admin's email address>
+#
+[AdminInfo]
+Kuopio, Finland:Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi
+
+#
+# Server information.
+#
+# Format: +<server FQDN>:<server IP>:<geographic location>:<port>
+#
+[ServerInfo]
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+
+#
+# Listenning ports.
+#
+# Format: <local IP/UNIX socket path>:<remote IP>:<port>
+#
+[ListenPort]
+10.2.1.6:10.2.1.6:1333
+
+#
+# Log files.
+#
+# This section is used to set various logging files, their paths
+# and maximum sizes. All the other directives except those defined
+# below are ignored in this section. Log files are purged after they
+# reach the maximum set byte size.
+#
+# Format: infologfile:<path>:<max byte size>
+#         warninglogile:<path>:<max byte size>
+#         errorlogile:<path>:<max byte size>
+#         fatallogile:<path>:<max byte size>
+#
+[Logging]
+infologfile:silcd.log:10000
+#warninglogfile:/var/log/silcd_warning.log:10000
+#errorlogfile:ERROR.log:10000
+#fatallogfile:/var/log/silcd_error.log:
+
+#
+# Connection classes.
+#
+# This section is used to define connection classes. These can be
+# used to optimize the server and the connections.#
+#
+# Format: <class number>:<ping freq>:<connect freq>:<max links>
+#
+[ConnectionClass]
+1:100:100:100
+2:200:300:400
+
+#
+# Configured client connections.
+#
+# Format: <remote host>:<auth method>:<auth data>:<port>:<class>
+#
+[ClientConnection]
+:::1333:1
+
+#
+# Configured server administrator connections
+#
+# Format: <host>:<auth method>:<auth data>:<nickname hash>:<class>
+#
+[AdminConnection]
+10.2.1.199:passwd:veryscret:XXX:1
+
+#
+# Configured server connections.
+#
+# If server connections are configured it means that our server is
+# router server.  Normal server must not configure server connections.
+# Thus, if your server is not router do not configure this section.  If
+# your server is router, this must be configured.
+#
+# Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:<vlass>
+#
+[ServerConnection]
+10.2.1.7:passwd:veryscret:1333:1:1
+
+#
+# Configured router connections.
+#
+# For normal server only one entry maybe configured to this section.  It
+# must be the router this server will be connected to.  For router server,
+# this sections includes all configured router connections.  The first
+# configured connection is the primary route.
+#
+# Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:<class>
+#
+[RouterConnection]
+10.2.1.100:passwd:veryverysecret:1333:1:1
+
+#
+# Denied connections.
+#
+# These connections are denied to connect our server.
+#
+# Format: <remote host/nickname>:<time interval>:<comment>:<port>
+#
+[DenyConnection]
+
+#
+# Redirected client connections.
+#
+# Clients will be redirected to these servers when our server is full.
+#
+# Format: <remote host>:<port>
+#
+[RedirectClient]
diff --git a/doc/fix.pl b/doc/fix.pl
new file mode 100755 (executable)
index 0000000..dca618e
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+
+# fix.pl  17-Nov-93  Craig Milo Rogers at USC/ISI
+#  
+#       The style guide for RFCs calls for pages to be delimited by the
+# sequence <last-non-blank-line><formfeed-line><first-non-blank-line>.
+# Unfortunately, NROFF is reluctant to produce output that conforms to
+# this convention.  This script fixes RFC-style documents by searching
+# for the token "FORMFEED[Page", replacing "FORMFEED" with spaces,
+# appending a formfeed line, and deleting white space up to the next
+# non-white space character.
+#
+#       There is one difference between this script's output and that of
+# the "fix.sh" and "pg" programs it replaces:  this script includes a
+# newline after the formfeed after the last page in a file, whereas the
+# earlier programs left a bare formfeed as the last character in the
+# file.  To obtain bare formfeeds, uncomment the second substitution
+# command below.  To strip the final formfeed, uncomment the third
+# substitution command below.
+#
+#       This script is intended to run as a filter, as in:
+#
+# nroff -ms input-file | fix.pl > output-file
+#
+#       When porting this script, please observe the following points:
+#
+# 1)    ISI keeps perl in "/local/bin/perl";  your system may keep it  
+#       elsewhere.
+# 2)    On systems with a CRLF end-of-line convention, the "0s below
+#       may have to be replaced with "^[70s.
+
+$* = 1;                                 # Enable multiline patterns.
+undef $/;                               # Read whole files in a single
+                                        # gulp.
+while (<>) {                            # Read the entire input file.
+    s/FORMFEED(\[Page\s+\d+\])\s+/        \1\n\f\n/g;
+    s/\f\n$/\f/;                       # Want bare formfeed at end?
+    print;                              # Print the resultant file.
+}  
diff --git a/doc/makerfc b/doc/makerfc
new file mode 100755 (executable)
index 0000000..a8b3a46
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+# Creates RFC
+#
+# Usage: makerfc <input_file> <output_file>
+#
+nroff -ms $1 | ./fix.pl > $2
diff --git a/includes/Makefile.am b/includes/Makefile.am
new file mode 100644 (file)
index 0000000..6702d83
--- /dev/null
@@ -0,0 +1,24 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+all:
+       -cd ..
+
+EXTRA_DIST = *.h
\ No newline at end of file
diff --git a/includes/Makefile.in b/includes/Makefile.in
new file mode 100644 (file)
index 0000000..0b8bc33
--- /dev/null
@@ -0,0 +1,209 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+EXTRA_DIST = *.h
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = silcdefs.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in silcdefs.h.in stamp-h.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile silcdefs.h
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign includes/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+silcdefs.h: stamp-h
+       @:
+stamp-h: $(srcdir)/silcdefs.h.in $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES= CONFIG_HEADERS=includes/silcdefs.h \
+            $(SHELL) ./config.status
+       @echo timestamp > stamp-h
+$(srcdir)/silcdefs.h.in: $(srcdir)/stamp-h.in
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOHEADER)
+       @echo timestamp > $(srcdir)/stamp-h.in
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+       -rm -f silcdefs.h
+
+maintainer-clean-hdr:
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = includes
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-hdr mostlyclean-generic
+
+clean:  clean-hdr clean-generic mostlyclean
+
+distclean:  distclean-hdr distclean-generic clean
+       -rm -f config.status
+
+maintainer-clean:  maintainer-clean-hdr maintainer-clean-generic \
+               distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+tags distdir info dvi installcheck install-exec install-data install \
+uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+all:
+       -cd ..
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/includes/bitmove.h b/includes/bitmove.h
new file mode 100644 (file)
index 0000000..aca83a4
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+
+  bitmove.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef BITMOVE_H
+#define BITMOVE_H
+
+/* Returns four 8-bit bytes, most significant bytes first. */
+#define SILC_GET32_MSB(l, cp) \
+       (l) = ((unsigned long)(unsigned char)(cp)[0]) << 24 \
+           | ((unsigned long)(unsigned char)(cp)[1] << 16) \
+           | ((unsigned long)(unsigned char)(cp)[2] << 8) \
+           | ((unsigned long)(unsigned char)(cp)[3])
+#define SILC_PUT32_MSB(l, cp) \
+       (cp)[0] = l >> 24; \
+       (cp)[1] = l >> 16; \
+       (cp)[2] = l >> 8; \
+       (cp)[3] = l;
+
+
+/* Returns four 8-bit bytes, less significant bytes first. */
+#define SILC_GET32_LSB(l, cp) \
+       (l) = ((unsigned long)(unsigned char)(cp)[0]) \
+           | ((unsigned long)(unsigned char)(cp)[1] << 8) \
+           | ((unsigned long)(unsigned char)(cp)[2] << 16) \
+           | ((unsigned long)(unsigned char)(cp)[3] << 24)
+/* same as upper but XOR the result always */
+#define SILC_GET32_X_LSB(l, cp) \
+       (l) ^= ((unsigned long)(unsigned char)(cp)[0]) \
+           | ((unsigned long)(unsigned char)(cp)[1] << 8) \
+           | ((unsigned long)(unsigned char)(cp)[2] << 16) \
+           | ((unsigned long)(unsigned char)(cp)[3] << 24)
+#define SILC_PUT32_LSB(l, cp) \
+       (cp)[0] = l; \
+       (cp)[1] = l >> 8; \
+       (cp)[2] = l >> 16; \
+       (cp)[3] = l >> 24;
+
+
+/* Returns two 8-bit bytes, most significant bytes first. */
+#define SILC_GET16_MSB(l, cp) \
+       (l) = ((unsigned long)(unsigned char)(cp)[0] << 8) \
+           | ((unsigned long)(unsigned char)(cp)[1])
+#define SILC_PUT16_MSB(l, cp) \
+       (cp)[0] = l >> 8; \
+       (cp)[1] = l;
+
+/* Returns two 8-bit bytes, less significant bytes first. */
+#define SILC_GET16_LSB(l, cp) \
+       (l) = ((unsigned long)(unsigned char)(cp)[0]) \
+           | ((unsigned long)(unsigned char)(cp)[1] << 8)
+#define SILC_PUT16_LSB(l, cp) \
+       (cp)[0] = l; \
+       (cp)[1] = l >> 8;
+
+#endif
diff --git a/includes/clientincludes.h b/includes/clientincludes.h
new file mode 100644 (file)
index 0000000..479c000
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+
+  clientincludes.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENTINCLUDES_H
+#define CLIENTINCLUDES_H
+
+#include <curses.h>
+#include <paths.h>
+#include <sys/param.h>
+#include <pwd.h>
+
+/* Generic includes */
+#include "silcincludes.h"
+
+/* SILC Client includes */
+#include "idlist.h"
+#include "screen.h"
+#include "clientconfig.h"
+#include "client.h"
+#include "clientutil.h"
+#include "protocol.h"
+#include "command.h"
+#include "command_reply.h"
+#include "silc.h"
+
+#endif
diff --git a/includes/serverincludes.h b/includes/serverincludes.h
new file mode 100644 (file)
index 0000000..3c8eedf
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+
+  serverincludes.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERVERINCLUDES_H
+#define SERVERINCLUDES_H
+
+/* Generic includes */
+#include "silcincludes.h"
+
+/* SILC Server includes */
+#include "idlist.h"
+#include "route.h"
+#include "serverid.h"
+#include "serverconfig.h"
+#include "server.h"
+#include "protocol.h"
+#include "command.h"
+#include "command_reply.h"
+#include "silcd.h"
+
+#endif
diff --git a/includes/silcdefs.h.in b/includes/silcdefs.h.in
new file mode 100644 (file)
index 0000000..61be749
--- /dev/null
@@ -0,0 +1,231 @@
+/* includes/silcdefs.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef gid_t
+
+/* Define as __inline if that's what the C compiler calls it.  */
+#undef inline
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef mode_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly.  */
+#undef STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef uid_t
+
+/* Name of the package. */
+#undef PACKAGE
+
+/* Version of the package. */
+#undef VERSION
+
+/* Debugging */
+#undef SILC_DEBUG
+
+/* Default configuration file */
+#undef SILC_SERVER_CONFIG_FILE
+
+/* SIM (SILC Module) support */
+#undef SILC_SIM
+#undef HAVE_RTLD_NOW
+#undef HAVE_RTLD_LAZY
+
+/* Define if you have the bind function.  */
+#undef HAVE_BIND
+
+/* Define if you have the chmod function.  */
+#undef HAVE_CHMOD
+
+/* Define if you have the close function.  */
+#undef HAVE_CLOSE
+
+/* Define if you have the connect function.  */
+#undef HAVE_CONNECT
+
+/* Define if you have the ctime function.  */
+#undef HAVE_CTIME
+
+/* Define if you have the fcntl function.  */
+#undef HAVE_FCNTL
+
+/* Define if you have the fstat function.  */
+#undef HAVE_FSTAT
+
+/* Define if you have the getenv function.  */
+#undef HAVE_GETENV
+
+/* Define if you have the getgid function.  */
+#undef HAVE_GETGID
+
+/* Define if you have the gethostbyaddr function.  */
+#undef HAVE_GETHOSTBYADDR
+
+/* Define if you have the gethostbyname function.  */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define if you have the gethostname function.  */
+#undef HAVE_GETHOSTNAME
+
+/* Define if you have the getopt_long function.  */
+#undef HAVE_GETOPT_LONG
+
+/* Define if you have the getpgid function.  */
+#undef HAVE_GETPGID
+
+/* Define if you have the getpgrp function.  */
+#undef HAVE_GETPGRP
+
+/* Define if you have the getpid function.  */
+#undef HAVE_GETPID
+
+/* Define if you have the getservbyname function.  */
+#undef HAVE_GETSERVBYNAME
+
+/* Define if you have the getservbyport function.  */
+#undef HAVE_GETSERVBYPORT
+
+/* Define if you have the getsid function.  */
+#undef HAVE_GETSID
+
+/* Define if you have the gettimeofday function.  */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the getuid function.  */
+#undef HAVE_GETUID
+
+/* Define if you have the listen function.  */
+#undef HAVE_LISTEN
+
+/* Define if you have the memcpy function.  */
+#undef HAVE_MEMCPY
+
+/* Define if you have the memmove function.  */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the memset function.  */
+#undef HAVE_MEMSET
+
+/* Define if you have the mlock function.  */
+#undef HAVE_MLOCK
+
+/* Define if you have the munlock function.  */
+#undef HAVE_MUNLOCK
+
+/* Define if you have the putenv function.  */
+#undef HAVE_PUTENV
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setsockopt function.  */
+#undef HAVE_SETSOCKOPT
+
+/* Define if you have the shutdown function.  */
+#undef HAVE_SHUTDOWN
+
+/* Define if you have the socket function.  */
+#undef HAVE_SOCKET
+
+/* Define if you have the stat function.  */
+#undef HAVE_STAT
+
+/* Define if you have the strchr function.  */
+#undef HAVE_STRCHR
+
+/* Define if you have the strcpy function.  */
+#undef HAVE_STRCPY
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strncpy function.  */
+#undef HAVE_STRNCPY
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the time function.  */
+#undef HAVE_TIME
+
+/* Define if you have the <arpa/inet.h> header file.  */
+#undef HAVE_ARPA_INET_H
+
+/* Define if you have the <assert.h> header file.  */
+#undef HAVE_ASSERT_H
+
+/* Define if you have the <ctype.h> header file.  */
+#undef HAVE_CTYPE_H
+
+/* Define if you have the <dlfcn.h> header file.  */
+#undef HAVE_DLFCN_H
+
+/* Define if you have the <errno.h> header file.  */
+#undef HAVE_ERRNO_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <getopt.h> header file.  */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <grp.h> header file.  */
+#undef HAVE_GRP_H
+
+/* Define if you have the <ncurses.h> header file.  */
+#undef HAVE_NCURSES_H
+
+/* Define if you have the <netdb.h> header file.  */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <netinet/in.h> header file.  */
+#undef HAVE_NETINET_IN_H
+
+/* Define if you have the <netinet/tcp.h> header file.  */
+#undef HAVE_NETINET_TCP_H
+
+/* Define if you have the <pwd.h> header file.  */
+#undef HAVE_PWD_H
+
+/* Define if you have the <signal.h> header file.  */
+#undef HAVE_SIGNAL_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/mman.h> header file.  */
+#undef HAVE_SYS_MMAN_H
+
+/* Define if you have the <sys/stat.h> header file.  */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file.  */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the <termcap.h> header file.  */
+#undef HAVE_TERMCAP_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
diff --git a/includes/silcincludes.h b/includes/silcincludes.h
new file mode 100644 (file)
index 0000000..abb8b3f
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+
+  silcincludes.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+  This file includes common definitions for SILC. This file MUST be included
+  by all files in SILC (directly or through other global include file).
+*/
+
+#ifndef SILCINCLUDES_H
+#define SILCINCLUDES_H
+
+/* Automatically generated configuration header */
+#include "silcdefs.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#error getopt.h not found in the system
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#else
+#error signal.h not found in the system
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#error fcntl.h not found in the system
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <errno.h>
+#else
+#error errno.h not found in the system
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#else
+#error assert.h not found in the system
+#endif
+
+#include <sys/socket.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#else
+#error netinet/in.h not found in the system
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#else
+#error netinet/tcp.h not found in the system
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#else
+#error netdb.h not found in the system
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#else
+#error arpa/inet.h not found in the system
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* Generic global SILC includes */
+#include "bitmove.h"
+
+/* Math library includes */
+#include "silcmp.h"
+#include "modinv.h"
+#include "silcprimegen.h"
+
+/* Crypto library includes */
+#include "silccipher.h"
+#include "silchash.h"
+#include "silchmac.h"
+#include "silcrng.h"
+#include "silcpkcs.h"
+
+/* SILC core library includes */
+#include "silclog.h"
+#include "silcmemory.h"
+#include "silcbuffer.h"
+#include "silcbufutil.h"
+#include "silcbuffmt.h"
+#include "silcnet.h"
+#include "silcutil.h"
+#include "silcconfig.h"
+#include "id.h"
+#include "idcache.h"
+#include "silcpacket.h"
+#include "silctask.h"
+#include "silcschedule.h"
+#include "silcprotocol.h"
+#include "silccommand.h"
+#include "silcchannel.h"
+#include "silcsockconn.h"
+
+#ifdef SILC_SIM
+/* SILC Module library includes */
+#include "silcsim.h"
+#include "silcsimutil.h"
+#endif
+
+/* SILC Key Exchange library includes */
+#include "silcske.h"
+#include "payload.h"
+#include "groups.h"
+
+#endif
diff --git a/includes/version.h b/includes/version.h
new file mode 100644 (file)
index 0000000..e225709
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+
+  version.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef VERSION_H
+#define VERSION_H
+
+/* Version type definition */
+typedef unsigned char SilcVersion;
+
+/* SILC Versions. XXX not used currently */
+#define SILC_VERSION_MAJ 1
+#define SILC_VERSION_MIN 0
+#define SILC_VERSION_BUILD 0
+
+/* SILC Protocol version number used in SILC packets */
+#define SILC_VERSION_1 '\1'
+
+/* SILC version string */
+const char *silc_version = "27062000";
+const char *silc_name = "SILC";
+const char *silc_fullname = "Secure Internet Live Conferencing";
+
+#endif
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..e9de238
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644 (file)
index 0000000..66c6682
--- /dev/null
@@ -0,0 +1,36 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+SUBDIRS = \
+       silccore \
+       silccrypt \
+       silcsim \
+       silcmath \
+       silcske
+#        zlib
+
+CLEANFILES = libsilc.a
+DISTCLEANFILES = libsilc.a
+
+all:   libsilc.a
+
+libsilc.a:
+       find . -type f -name *.o | xargs $(AR) cru libsilc.a
+       ranlib libsilc.a
diff --git a/lib/silccore/Makefile.am b/lib/silccore/Makefile.am
new file mode 100644 (file)
index 0000000..5811b56
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilccore.a
+
+libsilccore_a_SOURCES = \
+       id.c \
+       idcache.c \
+       silcbuffer.c \
+       silcbuffmt.c \
+       silcbufutil.c \
+       silcchannel.c \
+       silccommand.c \
+       silcconfig.c \
+       silclog.c \
+       silcmemory.c \
+       silcnet.c \
+       silcpacket.c \
+       silcprotocol.c \
+       silcschedule.c \
+       silcsockconn.c \
+       silctask.c \
+       silcutil.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
+       -I../silcsim -I../.. -I../../includes \
+       -I../silcmath/gmp-3.0.1
diff --git a/lib/silccore/id.c b/lib/silccore/id.c
new file mode 100644 (file)
index 0000000..d7aaf3a
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+
+  id.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Converts ID to string. */
+
+unsigned char *silc_id_id2str(void *id, SilcIdType type)
+{
+  unsigned char *ret_id;
+  SilcServerID *server_id;
+  SilcClientID *client_id;
+  SilcChannelID *channel_id;
+
+  switch(type) {
+  case SILC_ID_SERVER:
+    server_id = (SilcServerID *)id;
+    ret_id = silc_calloc(8, sizeof(unsigned char));
+    SILC_PUT32_MSB(server_id->ip.s_addr, ret_id);
+    SILC_PUT16_MSB(server_id->port, &ret_id[4]);
+    SILC_PUT16_MSB(server_id->rnd, &ret_id[6]);
+    return ret_id;
+    break;
+  case SILC_ID_CLIENT:
+    client_id = (SilcClientID *)id;
+    ret_id = silc_calloc(16, sizeof(unsigned char));
+    SILC_PUT32_MSB(client_id->ip.s_addr, ret_id);
+    ret_id[4] = client_id->rnd;
+    memcpy(&ret_id[5], client_id->hash, CLIENTID_HASH_LEN);
+    return ret_id;
+    break;
+  case SILC_ID_CHANNEL:
+    channel_id = (SilcChannelID *)id;
+    ret_id = silc_calloc(8, sizeof(unsigned char));
+    SILC_PUT32_MSB(channel_id->ip.s_addr, ret_id);
+    SILC_PUT16_MSB(channel_id->port, &ret_id[4]);
+    SILC_PUT16_MSB(channel_id->rnd, &ret_id[6]);
+    return ret_id;
+    break;
+  }
+
+  return NULL;
+}
+
+/* Converts string to a ID */
+
+void *silc_id_str2id(unsigned char *id, SilcIdType type) 
+{
+
+  switch(type) {
+  case SILC_ID_SERVER:
+    {
+      SilcServerID *server_id = silc_calloc(1, sizeof(*server_id));
+      SILC_GET32_MSB(server_id->ip.s_addr, id);
+      SILC_GET16_MSB(server_id->port, &id[4]);
+      SILC_GET16_MSB(server_id->rnd, &id[6]);
+      return server_id;
+    }
+    break;
+  case SILC_ID_CLIENT:
+    {
+      SilcClientID *client_id = silc_calloc(1, sizeof(*client_id));
+      SILC_GET32_MSB(client_id->ip.s_addr, id);
+      client_id->rnd = id[4];
+      memcpy(client_id->hash, &id[5], CLIENTID_HASH_LEN);
+      return client_id;
+    }
+    break;
+  case SILC_ID_CHANNEL:
+    {
+      SilcChannelID *channel_id = silc_calloc(1, sizeof(*channel_id));
+      SILC_GET32_MSB(channel_id->ip.s_addr, id);
+      SILC_GET16_MSB(channel_id->port, &id[4]);
+      SILC_GET16_MSB(channel_id->rnd, &id[6]);
+      return channel_id;
+    }
+    break;
+  }
+
+  return NULL;
+}
+
+/* Returns length of the ID */
+
+unsigned int silc_id_get_len(SilcIdType type)
+{
+  switch(type) {
+  case SILC_ID_SERVER:
+    return SILC_ID_SERVER_LEN;
+    break;
+  case SILC_ID_CLIENT:
+    return SILC_ID_CLIENT_LEN;
+    break;
+  case SILC_ID_CHANNEL:
+    return SILC_ID_CHANNEL_LEN;
+    break;
+  }
+
+  return 0;
+}
diff --git a/lib/silccore/id.h b/lib/silccore/id.h
new file mode 100644 (file)
index 0000000..56551c4
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+
+  id.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* These are important ID types used in SILC. SILC server creates these
+   but SILC client has to handle these as well since these are used in
+   packet sending and reception. However, client never creates these
+   but it receives the correct ID's from server. Clients, servers and
+   channels are identified by the these ID's.
+
+   Note that these are currently IPv4 specific, although adding IPv6
+   support is not a bad task and SILC protocol already supports IPv6.
+*/
+
+#ifndef ID_H
+#define ID_H
+
+#define SILC_ID_SERVER_LEN     (64 / 8)
+#define SILC_ID_CLIENT_LEN     (128 / 8)
+#define SILC_ID_CHANNEL_LEN    (64 / 8)
+#define CLIENTID_HASH_LEN       (88 / 8) /* Client ID's 88 bit MD5 hash */
+
+/* SILC ID Types */
+#define SILC_ID_NONE 0
+#define SILC_ID_SERVER 1
+#define SILC_ID_CLIENT 2
+#define SILC_ID_CHANNEL 3
+
+/* Type definition for the ID types. */
+typedef unsigned char SilcIdType;
+
+/* 
+   64 bit SilcServerID structure:
+   
+   32 bit IP address
+   16 bit port
+   16 bit random number
+*/
+typedef struct {
+  struct in_addr ip;                           /* 32 bit IP */
+  unsigned short port;                         /* 16 bit port */
+  unsigned short rnd;                          /* 16 bit random number */
+} SilcServerID;
+
+/* 
+   128 bit SilcClientID structure:
+
+   32 bit ServerID IP address [bits 1-32]
+    8 bit random number
+   88 bit hash value from nickname
+*/
+typedef struct {
+  struct in_addr ip;                           /* 32 bit IP */
+  unsigned char rnd;                           /* 8 bit random number */
+  unsigned char hash[CLIENTID_HASH_LEN];       /* 88 bit MD5 hash */
+} SilcClientID;
+
+/* 
+   64 bit SilcChannel ID structure:
+
+   32 bit Router's ServerID IP address [bits 1-32]
+   16 bit Router's ServerID port [bits 33-48]
+   16 bit random number
+*/
+typedef struct {
+  struct in_addr ip;                           /* 32 bit IP */
+  unsigned short port;                         /* 16 bit port */
+  unsigned short rnd;                          /* 16 bit random number */
+} SilcChannelID;
+
+/* Macros */
+
+/* Compares two ID's */
+#define SILC_ID_COMPARE(id1, id2, len) (memcmp(id1, id2, len))
+
+/* Compares Channel ID's */
+#define SILC_ID_CHANNEL_COMPARE(id1, id2) \
+  SILC_ID_COMPARE(id1, id2, SILC_ID_CHANNEL_LEN)
+
+/* Compares Client ID's */
+#define SILC_ID_CLIENT_COMPARE(id1, id2) \
+  SILC_ID_COMPARE(id1, id2, SILC_ID_CLIENT_LEN)
+
+/* Compares Server ID's */
+#define SILC_ID_SERVER_COMPARE(id1, id2) \
+  SILC_ID_COMPARE(id1, id2, SILC_ID_SERVER_LEN)
+
+/* Compares IP addresses from the ID's. */
+#define SILC_ID_COMPARE_IP(id1, id2) \
+  SILC_ID_COMPARE(id1, id2, 4)
+
+/* Compare nickname hash from Client ID */
+#define SILC_ID_COMPARE_HASH(id, hash) \
+  memcmp(id->hash, hash, CLIENTID_HASH_LEN)
+
+/* Prototypes */
+unsigned char *silc_id_id2str(void *id, SilcIdType type);
+void *silc_id_str2id(unsigned char *id, SilcIdType type);
+unsigned int silc_id_get_len(SilcIdType type);
+
+#endif
diff --git a/lib/silccore/idcache.c b/lib/silccore/idcache.c
new file mode 100644 (file)
index 0000000..a16bdc1
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+
+  idcache.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* XXX: This ID cache system sucks and must be rewritten! */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* qsort() sorter function. */
+
+static int silc_idcache_sorter(const void *a, const void *b)
+{
+  SilcIDCache *a1, *b1;
+  
+  a1 = (SilcIDCache *)a;
+  b1 = (SilcIDCache *)b;
+  
+  return a1->data[0] - b1->data[0];
+}
+
+/* Sorts given cache by data */
+
+void silc_idcache_sort_by_data(SilcIDCache *cache, unsigned int count)
+{
+  qsort(cache, count, sizeof(*cache), silc_idcache_sorter);
+}
+
+/* Find ID Cache entry by data. The data maybe anything that must
+   match exactly. */
+
+int silc_idcache_find_by_data(SilcIDCache *cache, unsigned int cache_count,
+                             char *data, SilcIDCache **ret)
+{
+  int i;
+
+  if (cache == NULL)
+    return FALSE;
+
+  if (data == NULL)
+    return FALSE;
+
+  for (i = 0; i < cache_count; i++)
+    if (cache[i].data && !memcmp(cache[i].data, data, strlen(data))) {
+      if (ret)
+       *ret = &(cache[i]);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Find ID Cache entry by ID. */
+
+int silc_idcache_find_by_id(SilcIDCache *cache, unsigned int cache_count, 
+                           void *id, SilcIdType type, SilcIDCache **ret)
+{
+  int i, id_len;
+
+  if (cache == NULL)
+    return FALSE;
+
+  if (id == NULL)
+    return FALSE;
+
+  id_len = silc_id_get_len(type);
+
+  for (i = 0; i < cache_count; i++)
+    if (cache[i].id && !memcmp(cache[i].id, id, id_len)) {
+      if (ret)
+       *ret = &(cache[i]);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Add new entry to the cache. Returns number of allocated cache
+   entries in the cache. */
+
+int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
+                    char *data, SilcIdType id_type, void *id, 
+                    void *context)
+{
+  SilcIDCache *c;
+  int i;
+  unsigned long curtime = time(NULL);
+
+  SILC_LOG_DEBUG(("Adding cache entry"));
+
+  c = *cache;
+
+  if (c == NULL) {
+    c = silc_calloc(5, sizeof(*c));
+    if (!c)
+      return 0;
+    cache_count = 5;
+  }
+
+  /* See if it exists already */
+  if (silc_idcache_find_by_id(c, cache_count, id, id_type, NULL) == TRUE)
+    return cache_count;
+
+  for (i = 0; i < cache_count; i++) {
+    if (c[i].data == NULL) {
+      c[i].data = data;
+      c[i].type = id_type;
+      c[i].id = id;
+      c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
+      c[i].context = context;
+      break;
+    }
+  }
+
+  if (i == cache_count) {
+    c = silc_realloc(c, sizeof(*c) * (cache_count + 5));
+    if (!c)
+      return cache_count;
+    for (i = cache_count; i < cache_count + 5; i++) {
+      c[i].data = NULL;
+      c[i].id = NULL;
+    }
+    c[cache_count].data = data;
+    c[cache_count].type = id_type;
+    c[cache_count].id = id;
+    c[cache_count].expire = curtime + SILC_ID_CACHE_EXPIRE;
+    c[cache_count].context = context;
+    cache_count += 5;
+  }
+
+  *cache = c;
+
+  return cache_count;
+}
+
+/* Delete cache entry from cache. */
+/* XXX */
+
+int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old)
+{
+
+  return TRUE;
+}
+
+/* XXX */
+
+int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
+                            char *data)
+{
+
+  return TRUE;
+}
+
+/* Deletes ID cache entry by ID. */
+
+int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
+                          SilcIdType type, void *id)
+{
+  int i, id_len;
+
+  if (cache == NULL)
+    return FALSE;
+
+  if (id == NULL)
+    return FALSE;
+
+  id_len = silc_id_get_len(type);
+
+  for (i = 0; i < cache_count; i++)
+    if (cache[i].id && !memcmp(cache[i].id, id, id_len)) {
+      cache[i].id = NULL;
+      cache[i].data = NULL;
+      cache[i].type = 0;
+      cache[i].context = NULL;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Deletes all ID entries from cache. Free's memory as well. */
+
+int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count)
+{
+  SilcIDCache *c = *cache;
+  int i;
+
+  if (c == NULL)
+    return FALSE;
+
+  for (i = 0; i < cache_count; i++) {
+    c[i].id = NULL;
+    c[i].data = NULL;
+    c[i].type = 0;
+    c[i].expire = 0;
+    c[i].context = NULL;
+  }
+
+  silc_free(*cache);
+  *cache = NULL;
+
+  return TRUE;
+}
+
+/* Purges the cache by removing expired cache entires. This does not
+   free any memory though. */
+
+int silc_idcache_purge(SilcIDCache *cache, unsigned int cache_count)
+{
+  unsigned long curtime = time(NULL);
+  int i;
+
+  if (cache == NULL)
+    return FALSE;
+
+  for (i = 0; i < cache_count; i++) {
+    if (cache[i].data && 
+       (cache[i].expire == 0 || cache[i].expire < curtime)) {
+      cache[i].id = NULL;
+      cache[i].data = NULL;
+      cache[i].type = 0;
+      cache[i].expire = 0;
+      cache[i].context = NULL;
+    }
+  }
+
+  return TRUE;
+}
diff --git a/lib/silccore/idcache.h b/lib/silccore/idcache.h
new file mode 100644 (file)
index 0000000..074dc48
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+
+  idcache.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef IDCACHE_H
+#define IDCACHE_H
+
+/* 
+   SilcIDCache structure.
+
+   char *data
+
+      The data that is usually used to find the data from the cache.
+      For example for Client ID's this is nickname.
+
+   SilcIdType type
+
+      Type of the ID.
+
+   void *id
+
+      The actual ID.
+
+   unsigned long expire
+
+      Time when this cache entry expires.  This is normal time() value
+      plus the validity.  Cache entry has expired if current time is
+      more than value in this field, or if this field has been set to
+      zero (0) value.
+
+   void *context
+
+      Any caller specified context.
+
+*/
+typedef struct {
+  char *data;
+  SilcIdType type;
+  void *id;
+  unsigned long expire;
+  void *context;
+} SilcIDCache;
+
+#define SILC_ID_CACHE_EXPIRE 3600
+
+/* Prototypes */
+void silc_idcache_sort_by_data(SilcIDCache *cache, unsigned int count);
+int silc_idcache_find_by_data(SilcIDCache *cache, unsigned int cache_count,
+                             char *data, SilcIDCache **ret);
+int silc_idcache_find_by_id(SilcIDCache *cache, unsigned int cache_count, 
+                           void *id, SilcIdType type, SilcIDCache **ret);
+int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
+                    char *data, SilcIdType id_type, void *id, 
+                    void *context);
+int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old);
+int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
+                            char *data);
+int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
+                          SilcIdType type, void *id);
+int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count);
+int silc_idcache_purge(SilcIDCache *cache, unsigned int cache_count);
+
+#endif
diff --git a/lib/silccore/silcbuffer.c b/lib/silccore/silcbuffer.c
new file mode 100644 (file)
index 0000000..662cf31
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+
+  silcbuffer.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1998 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcbuffer.h"
+
+static unsigned char *silc_buffer_pull_i(SilcBuffer sb, unsigned int len)
+{
+  return silc_buffer_pull(sb, len);
+}
+
+static unsigned char *silc_buffer_push_i(SilcBuffer sb, unsigned int len)
+{
+  return silc_buffer_push(sb, len);
+}
+
+static unsigned char *silc_buffer_pull_tail_i(SilcBuffer sb, unsigned int len)
+{
+  return silc_buffer_pull_tail(sb, len);
+}
+
+static unsigned char *silc_buffer_push_tail_i(SilcBuffer sb, unsigned int len)
+{
+  return silc_buffer_push_tail(sb, len);
+}
+
+static unsigned char *silc_buffer_put_head_i(SilcBuffer sb, 
+                                            unsigned char *data,
+                                            unsigned int len)
+{
+  return silc_buffer_put_head(sb, data, len);
+}
+
+static unsigned char *silc_buffer_put_i(SilcBuffer sb, 
+                                       unsigned char *data,
+                                       unsigned int len)
+{
+  return silc_buffer_put(sb, data, len);
+}
+
+static unsigned char *silc_buffer_put_tail_i(SilcBuffer sb, 
+                                            unsigned char *data,
+                                            unsigned int len)
+{
+  return silc_buffer_put_tail(sb, data, len);
+}
+
+/* Allocates a new SilcBuffer and returns a pointer to it. The data
+   area of the new buffer is set to the real beginning of the buffer. 
+
+   Buffer after allocation:
+   ---------------------------------
+   |                               |
+   ---------------------------------
+   ^ head, data, tail              ^ end
+
+*/
+
+SilcBuffer silc_buffer_alloc(unsigned int len)
+{
+  SilcBuffer sb;
+  unsigned char *data;
+
+  /* Allocate new SilcBuffer */
+  sb = silc_calloc(1, sizeof(*sb));
+  if (!sb)
+    return NULL;
+
+  /* Allocate the actual data area */
+  data = silc_malloc(len);
+  if (!data)
+    return NULL;
+  memset(data, 0, len);
+
+  /* Set pointers to the new buffer */
+  sb->truelen = len;
+  sb->len = 0;
+  sb->head = data;
+  sb->data = data;
+  sb->tail = data;
+  sb->end = data + sb->truelen;
+
+  /* Set the function pointers */
+  sb->pull = silc_buffer_pull_i;
+  sb->push = silc_buffer_push_i;
+  sb->pull_tail = silc_buffer_pull_tail_i;
+  sb->push_tail = silc_buffer_push_tail_i;
+  sb->put = silc_buffer_put_i;
+  sb->put_head = silc_buffer_put_head_i;
+  sb->put_tail = silc_buffer_put_tail_i;
+
+  return sb;
+}
+
+/* Free's a SilcBuffer */
+
+void silc_buffer_free(SilcBuffer sb)
+{
+  if (sb) {
+    memset(sb->head, 'F', sb->truelen);
+    silc_free(sb->head);
+    silc_free(sb);
+  }
+}
+
+#ifdef SILC_DEBUG              /* If we are doing debugging we won't
+                                  have the optimized inline buffer functions
+                                  available as optimization is not set
+                                  to compiler. These normal routines are
+                                  used in debugging mode. */
+
+/* XXX These are currenly obsolte as SILC is compiled always with -O
+   flag thus inline functions maybe used. So, fix these. */
+
+/* Pulls current data area towards end. The length of the currently
+   valid data area is also decremented. Returns pointer to the data
+   area before pulling. 
+
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+           ^
+           Pulls the start of the data area.
+
+   ---------------------------------
+   | head     | data    | tail     |
+   ---------------------------------
+           ^
+*/
+
+unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_data = sb->data;
+
+  assert(len <= (sb->tail - sb->data));
+
+  sb->data += len;
+  sb->len -= len;
+
+  return old_data;
+}
+
+/* Pushes current data area towards beginning. Length of the currently
+   valid data area is also incremented. Returns a pointer to the 
+   data area before pushing. 
+
+   Example:
+   ---------------------------------
+   | head     | data    | tail     |
+   ---------------------------------
+              ^
+              Pushes the start of the data area.
+
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+              ^
+*/
+
+unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_data = sb->data;
+
+  assert((sb->data - len) >= sb->head);
+
+  sb->data -= len;
+  sb->len += len;
+
+  return old_data;
+}
+
+/* Pulls current tail section towards end. Length of the current valid
+   data area is also incremented. Returns a pointer to the data area 
+   before pulling.
+
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+                        ^
+                        Pulls the start of the tail section.
+
+   ---------------------------------
+   | head  | data           | tail |
+   ---------------------------------
+                        ^
+*/
+
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_tail = sb->tail;
+
+  assert((sb->end - sb->tail) >= len);
+
+  sb->tail += len;
+  sb->len += len;
+
+  return old_tail;
+}
+
+/* Pushes current tail section towards beginning. Length of the current
+   valid data area is also decremented. Returns a pointer to the 
+   tail section before pushing. 
+
+   Example:
+   ---------------------------------
+   | head  | data           | tail |
+   ---------------------------------
+                            ^
+                            Pushes the start of the tail section.
+
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+                            ^
+*/
+
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_tail = sb->tail;
+
+  assert((sb->tail - len) >= sb->data);
+
+  sb->tail -= len;
+  sb->len -= len;
+
+  return old_tail;
+}
+
+/* Puts data at the head of the buffer. Returns pointer to the copied
+   data area. 
+   
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+   ^
+   Puts data to the head section. 
+*/
+
+unsigned char *silc_buffer_put_head(SilcBuffer sb, 
+                                   unsigned char *data,
+                                   unsigned int len)
+{
+  assert((sb->data - sb->head) >= len);
+  return memcpy(sb->head, data, len);
+}
+
+/* Puts data at the start of the valid data area. Returns a pointer 
+   to the copied data area. 
+
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+           ^
+           Puts data to the data section.
+*/
+
+unsigned char *silc_buffer_put(SilcBuffer sb, 
+                              unsigned char *data,
+                              unsigned int len)
+{
+  assert((sb->tail - sb->data) >= len);
+  return memcpy(sb->data, data, len);
+}
+
+/* Puts data at the tail of the buffer. Returns pointer to the copied
+   data area. 
+
+   Example:
+   ---------------------------------
+   | head  | data           | tail |
+   ---------------------------------
+                            ^
+                           Puts data to the tail section.
+*/
+
+unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
+                                   unsigned char *data,
+                                   unsigned int len)
+{
+  assert((sb->end - sb->tail) >= len);
+  return memcpy(sb->tail, data, len);
+}
+
+#endif
diff --git a/lib/silccore/silcbuffer.h b/lib/silccore/silcbuffer.h
new file mode 100644 (file)
index 0000000..179c3d0
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+
+  silcbuffer.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1998 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCBUFFER_H
+#define SILCBUFFER_H
+
+/* 
+   SILC Buffer object.
+
+   SilcBuffer is very simple and easy to use, yet you can do to the
+   buffer almost anything you want with its method functions. The buffer
+   is constructed of four different data sections that in whole creates
+   the allocated data area. Following short description of the fields
+   of the buffer.
+
+   unsigned int truelen;
+
+       True length of the buffer. This is set at the allocation of the
+       buffer and it should not be touched after that. This field should
+       be considered read-only.
+
+   unsigned int len;
+
+       Length of the currently valid data area. Tells the length of the 
+       data at the buffer. This is set to zero at the allocation of the
+       buffer and should not be updated by hand. Method functions of the
+       buffer automatically updates this field. However, it is not
+       read-only field and can be updated manually if necessary.
+
+   unsiged char *head;
+
+       Head of the allocated buffer. This is the start of the allocated
+       data area and remains as same throughout the lifetime of the buffer.
+       However, the end of the head area or the start of the currently valid
+       data area is variable.
+
+       --------------------------------
+       | head  | data         | tail  |
+       --------------------------------
+       ^       ^
+
+       Current head section in the buffer is sb->data - sb->head.
+
+   unsigned char *data;
+
+       Currently valid data area. This is the start of the currently valid
+       main data area. The data area is variable in all directions.
+
+       --------------------------------
+       | head  | data         | tail  |
+       --------------------------------
+               ^              ^
+       Current valid data area in the buffer is sb->tail - sb->data.
+
+    unsigned char *tail;
+
+       Tail of the buffer. This is the end of the currently valid data area
+       or start of the tail area. The start of the tail area is variable.
+
+       --------------------------------
+       | head  | data         | tail  |
+       --------------------------------
+                              ^       ^
+
+       Current tail section in the buffer is sb->end - sb->tail.
+
+   unsigned char *end;
+
+       End of the allocated buffer. This is the end of the allocated data
+       area and remains as same throughout the lifetime of the buffer.
+       Usually this field is not needed except when checking the size
+       of the buffer.
+
+       --------------------------------
+       | head  | data         | tail  |
+       --------------------------------
+                                      ^
+
+       Length of the entire buffer is (ie. truelen) sb->end - sb->head.
+
+    Currently valid data area is considered to be the main data area in
+    the buffer. However, the entire buffer is of course valid data and can
+    be used as such. Usually head section of the buffer includes different
+    kind of headers or similiar. Data section includes the main data of
+    the buffer. Tail section can be seen as a reserve space of the data
+    section. Tail section can be pulled towards end thus the data section
+    becomes larger.
+
+    This buffer scheme is based on Linux kernel's Socket Buffer, the 
+    idea were taken directly from there and credits should go there.
+
+*/
+
+typedef struct SilcBufferStruct {
+  unsigned int truelen;
+  unsigned int len;
+  unsigned char *head;
+  unsigned char *data;
+  unsigned char *tail;
+  unsigned char *end;
+
+  /* Method functions. */
+  unsigned char *(*pull)(struct SilcBufferStruct *, unsigned int);
+  unsigned char *(*push)(struct SilcBufferStruct *, unsigned int);
+  unsigned char *(*pull_tail)(struct SilcBufferStruct *, unsigned int);
+  unsigned char *(*push_tail)(struct SilcBufferStruct *, unsigned int);
+  unsigned char *(*put)(struct SilcBufferStruct *, unsigned char *, 
+                       unsigned int);
+  unsigned char *(*put_head)(struct SilcBufferStruct *, unsigned char *, 
+                            unsigned int);
+  unsigned char *(*put_tail)(struct SilcBufferStruct *, unsigned char *, 
+                            unsigned int);
+} SilcBufferObject;
+
+typedef SilcBufferObject *SilcBuffer;
+
+/* Macros */
+
+/* Returns the true length of the buffer. This is used to pull
+   the buffer area to the end of the buffer. */
+#define SILC_BUFFER_END(x) ((x)->end - (x)->head)
+
+#ifndef SILC_DEBUG             /* When we are not doing debugging we use
+                                  optimized inline buffer functions. */
+/* 
+ * Optimized buffer managing routines.  These are short inline
+ * functions.
+ */
+
+/* Pulls current data area towards end. The length of the currently
+   valid data area is also decremented. Returns pointer to the data
+   area before pulling. 
+
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+           ^
+           Pulls the start of the data area.
+
+   ---------------------------------
+   | head     | data    | tail     |
+   ---------------------------------
+           ^
+*/
+
+extern inline 
+unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_data = sb->data;
+
+  assert(len <= (sb->tail - sb->data));
+
+  sb->data += len;
+  sb->len -= len;
+
+  return old_data;
+}
+
+/* Pushes current data area towards beginning. Length of the currently
+   valid data area is also incremented. Returns a pointer to the 
+   data area before pushing. 
+
+   Example:
+   ---------------------------------
+   | head     | data    | tail     |
+   ---------------------------------
+              ^
+              Pushes the start of the data area.
+
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+              ^
+*/
+
+extern inline 
+unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_data = sb->data;
+
+  assert((sb->data - len) >= sb->head);
+
+  sb->data -= len;
+  sb->len += len;
+
+  return old_data;
+}
+
+/* Pulls current tail section towards end. Length of the current valid
+   data area is also incremented. Returns a pointer to the data area 
+   before pulling.
+
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+                        ^
+                        Pulls the start of the tail section.
+
+   ---------------------------------
+   | head  | data           | tail |
+   ---------------------------------
+                        ^
+*/
+
+extern inline 
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_tail = sb->tail;
+
+  assert((sb->end - sb->tail) >= len);
+
+  sb->tail += len;
+  sb->len += len;
+
+  return old_tail;
+}
+
+/* Pushes current tail section towards beginning. Length of the current
+   valid data area is also decremented. Returns a pointer to the 
+   tail section before pushing. 
+
+   Example:
+   ---------------------------------
+   | head  | data           | tail |
+   ---------------------------------
+                            ^
+                            Pushes the start of the tail section.
+
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+                            ^
+*/
+
+extern inline
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len)
+{
+  unsigned char *old_tail = sb->tail;
+
+  assert((sb->tail - len) >= sb->data);
+
+  sb->tail -= len;
+  sb->len -= len;
+
+  return old_tail;
+}
+
+/* Puts data at the head of the buffer. Returns pointer to the copied
+   data area. 
+   
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+   ^
+   Puts data to the head section. 
+*/
+
+extern inline
+unsigned char *silc_buffer_put_head(SilcBuffer sb, 
+                                   unsigned char *data,
+                                   unsigned int len)
+{
+  assert((sb->data - sb->head) >= len);
+  return memcpy(sb->head, data, len);
+}
+
+/* Puts data at the start of the valid data area. Returns a pointer 
+   to the copied data area. 
+
+   Example:
+   ---------------------------------
+   | head  | data       | tail     |
+   ---------------------------------
+           ^
+           Puts data to the data section.
+*/
+
+extern inline
+unsigned char *silc_buffer_put(SilcBuffer sb, 
+                              unsigned char *data,
+                              unsigned int len)
+{
+  assert((sb->tail - sb->data) >= len);
+  return memcpy(sb->data, data, len);
+}
+
+/* Puts data at the tail of the buffer. Returns pointer to the copied
+   data area. 
+
+   Example:
+   ---------------------------------
+   | head  | data           | tail |
+   ---------------------------------
+                            ^
+                           Puts data to the tail section.
+*/
+
+extern inline
+unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
+                                   unsigned char *data,
+                                   unsigned int len)
+{
+  assert((sb->end - sb->tail) >= len);
+  return memcpy(sb->tail, data, len);
+}
+
+#endif /* !SILC_DEBUG */
+
+/* Prototypes */
+SilcBuffer silc_buffer_alloc(unsigned int len);
+void silc_buffer_free(SilcBuffer sb);
+#ifdef SILC_DEBUG
+unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len);
+unsigned char *silc_buffer_put_head(SilcBuffer sb, 
+                                   unsigned char *data,
+                                   unsigned int len);
+unsigned char *silc_buffer_put(SilcBuffer sb, 
+                              unsigned char *data,
+                              unsigned int len);
+unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
+                                   unsigned char *data,
+                                   unsigned int len);
+#endif
+
+#endif
diff --git a/lib/silccore/silcbuffmt.c b/lib/silccore/silcbuffmt.c
new file mode 100644 (file)
index 0000000..5d56f18
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+
+  silcbuffmt.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* XXX: These routines needs to be made more stable as these can crash
+   if the data (for unformatting for example) is malformed or the buffer
+   is too short. Must be fixed. There are some other obvious bugs as
+   well. */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Formats the arguments sent and puts them into the buffer sent as
+   argument. The buffer must be initialized beforehand and it must have
+   enough free space to include the formatted data. If this function
+   fails caller should not trust the buffer anymore and should free it. 
+   This function is used, for example, to create packets to send over
+   network. */
+
+int silc_buffer_format(SilcBuffer dst, ...)
+{
+  va_list ap;
+  SilcBufferParamType fmt;
+  unsigned char *start_ptr = dst->data;
+
+  va_start(ap, dst);
+
+  /* Parse the arguments by formatting type. */
+  while(1) {
+    fmt = va_arg(ap, SilcBufferParamType);
+
+    switch(fmt) {
+    case SILC_BUFFER_PARAM_SI8_CHAR:
+      {
+       char x = va_arg(ap, char);
+       silc_buffer_put(dst, &x, 1);
+       silc_buffer_pull(dst, 1);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI8_CHAR:
+      {
+       unsigned char x = va_arg(ap, unsigned char);
+       silc_buffer_put(dst, &x, 1);
+       silc_buffer_pull(dst, 1);
+       break;
+      }
+    case SILC_BUFFER_PARAM_SI16_SHORT:
+      {
+       unsigned char xf[2];
+       short x = va_arg(ap, short);
+       SILC_PUT16_MSB(x, xf);
+       silc_buffer_put(dst, xf, 2);
+       silc_buffer_pull(dst, 2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_SHORT:
+      {
+       unsigned char xf[2];
+       unsigned short x = va_arg(ap, unsigned short);
+       SILC_PUT16_MSB(x, xf);
+       silc_buffer_put(dst, xf, 2);
+       silc_buffer_pull(dst, 2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_SI32_INT:
+      {
+       unsigned char xf[4];
+       int x = va_arg(ap, int);
+       SILC_PUT32_MSB(x, xf);
+       silc_buffer_put(dst, xf, 4);
+       silc_buffer_pull(dst, 4);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI32_INT:
+      {
+       unsigned char xf[4];
+       unsigned int x = va_arg(ap, unsigned int);
+       SILC_PUT32_MSB(x, xf);
+       silc_buffer_put(dst, xf, 4);
+       silc_buffer_pull(dst, 4);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_STRING:
+    case SILC_BUFFER_PARAM_UI32_STRING:
+    case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
+    case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
+      {
+       unsigned char *x = va_arg(ap, unsigned char *);
+       silc_buffer_put(dst, x, strlen(x));
+       silc_buffer_pull(dst, strlen(x));
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_NSTRING:
+    case SILC_BUFFER_PARAM_UI32_NSTRING:
+    case SILC_BUFFER_PARAM_UI_XNSTRING:
+    case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
+    case SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC:
+    case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
+      {
+       unsigned char *x = va_arg(ap, unsigned char *);
+       unsigned int len = va_arg(ap, unsigned int);
+       silc_buffer_put(dst, x, len);
+       silc_buffer_pull(dst, len);
+       break;
+      }
+    case SILC_BUFFER_PARAM_END:
+      goto ok;
+      break;
+    default:
+      SILC_LOG_ERROR(("Bad buffer formatting type `%d'. Could not "
+                     "format the data.", fmt));
+      goto fail;
+      break;
+    }
+  }
+
+ fail:
+  SILC_LOG_ERROR(("Error occured while formatting data"));
+  return FALSE;
+
+ ok:
+  /* Push the buffer back to where it belongs. */
+  silc_buffer_push(dst, dst->data - start_ptr);
+  return dst->len;
+}
+
+/* Unformats the buffer sent as argument. The unformatted data is returned
+   to the variable argument list of pointers. The buffer must point to the
+   start of the data area to be unformatted. Buffer maybe be safely free'd
+   after this returns succesfully. */
+
+int silc_buffer_unformat(SilcBuffer src, ...)
+{
+  va_list ap;
+  SilcBufferParamType fmt;
+  unsigned char *start_ptr = src->data;
+  int len = 0;
+
+  va_start(ap, src);
+
+  /* Parse the arguments by formatting type. */
+  while(1) {
+    fmt = va_arg(ap, SilcBufferParamType);
+
+    switch(fmt) {
+    case SILC_BUFFER_PARAM_SI8_CHAR:
+      {
+       char *x = va_arg(ap, char *);
+       if (x)
+         *x = src->data[0];
+       silc_buffer_pull(src, 1);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI8_CHAR:
+      {
+       unsigned char *x = va_arg(ap, unsigned char *);
+       if (x)
+         *x = src->data[0];
+       silc_buffer_pull(src, 1);
+       break;
+      }
+    case SILC_BUFFER_PARAM_SI16_SHORT:
+      {
+       short *x = va_arg(ap, short *);
+       if (x)
+         SILC_GET16_MSB(*x, src->data);
+       silc_buffer_pull(src, 2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_SHORT:
+      {
+       unsigned short *x = va_arg(ap, unsigned short *);
+       if (x)
+         SILC_GET16_MSB(*x, src->data);
+       silc_buffer_pull(src, 2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_SI32_INT:
+      {
+       int *x = va_arg(ap, int *);
+       if (x)
+         SILC_GET32_MSB(*x, src->data);
+       silc_buffer_pull(src, 4);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI32_INT:
+      {
+       unsigned int *x = va_arg(ap, unsigned int *);
+       if (x)
+         SILC_GET32_MSB(*x, src->data);
+       silc_buffer_pull(src, 4);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_STRING:
+      {
+       unsigned short len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       SILC_GET16_MSB(len2, src->data);
+       silc_buffer_pull(src, 2);
+       if ((len2 > src->len))
+         goto fail;
+       if (len2 < 1)
+         break;
+       if (x)
+         memcpy(x, src->data, len2);
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_STRING_ALLOC:
+      {
+       unsigned short len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       SILC_GET16_MSB(len2, src->data);
+       silc_buffer_pull(src, 2);
+       if ((len2 > src->len))
+         goto fail;
+       if (len2 < 1)
+         break;
+       if (x) {
+         *x = silc_calloc(len2 + 1, sizeof(unsigned char));
+         memcpy(*x, src->data, len2);
+       }
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI32_STRING:
+      {
+       unsigned int len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       SILC_GET32_MSB(len2, src->data);
+       silc_buffer_pull(src, 4);
+       if ((len2 > src->len))
+         goto fail;
+       if (len2 < 1)
+         break;
+       if (x)
+         memcpy(x, src->data, len2);
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI32_STRING_ALLOC:
+      {
+       unsigned int len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       SILC_GET32_MSB(len2, src->data);
+       silc_buffer_pull(src, 4);
+       if ((len2 > src->len))
+         goto fail;
+       if (len2 < 1)
+         break;
+       if (x) {
+         *x = silc_calloc(len2 + 1, sizeof(unsigned char));
+         memcpy(*x, src->data, len2);
+       }
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_NSTRING:
+      {
+       unsigned short len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       unsigned short *len = va_arg(ap, unsigned short *);
+       SILC_GET16_MSB(len2, src->data);
+       silc_buffer_pull(src, 2);
+       if ((len2 > src->len))
+         break;
+       if (len2 < 1)
+         break;
+       if (len)
+         *len = len2;
+       if (x)
+         memcpy(x, src->data, len2);
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC:
+      {
+       unsigned short len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       unsigned short *len = va_arg(ap, unsigned short *);
+       SILC_GET16_MSB(len2, src->data);
+       silc_buffer_pull(src, 2);
+       if ((len2 > src->len))
+         break;
+       if (len2 < 1)
+         break;
+       if (len)
+         *len = len2;
+       if (x) {
+         *x = silc_calloc(len2 + 1, sizeof(unsigned char));
+         memcpy(*x, src->data, len2);
+       }
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI32_NSTRING:
+      {
+       unsigned int len2;
+       unsigned char **x = va_arg(ap, unsigned char **);
+       unsigned int *len = va_arg(ap, unsigned int *);
+       SILC_GET32_MSB(len2, src->data);
+       silc_buffer_pull(src, 4);
+       if ((len2 > src->len))
+         goto fail;
+       if (len2 < 1)
+         break;
+       if (len)
+         *len = len2;
+       if (x)
+         memcpy(x, src->data, len2);
+       silc_buffer_pull(src, len2);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC:
+      {
+       unsigned char **x = va_arg(ap, unsigned char **);
+       unsigned int len = va_arg(ap, unsigned int);
+       if (len && x) {
+         *x = silc_calloc(len + 1, sizeof(unsigned char));
+         memcpy(*x, src->data, len);
+       }
+       silc_buffer_pull(src, len);
+       break;
+      }
+    case SILC_BUFFER_PARAM_UI_XNSTRING:
+      {
+       unsigned char **x = va_arg(ap, unsigned char **);
+       unsigned int len = va_arg(ap, unsigned int);
+       if (len && x)
+         memcpy(x, src->data, len);
+       silc_buffer_pull(src, len);
+       break;
+      }
+    case SILC_BUFFER_PARAM_END:
+      goto ok;
+      break;
+    default:
+      SILC_LOG_ERROR(("Bad buffer formatting type `%d'. Could not "
+                     "format the data.", fmt));
+      goto fail;
+      break;
+    }
+  }
+
+ fail:
+  SILC_LOG_ERROR(("Error occured while unformatting buffer"));
+  return FALSE;
+
+ ok:
+  /* Push the buffer back to the start. */
+  len = src->data - start_ptr;
+  silc_buffer_push(src, len);
+  return len;
+}
diff --git a/lib/silccore/silcbuffmt.h b/lib/silccore/silcbuffmt.h
new file mode 100644 (file)
index 0000000..6d9acae
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+
+  silcbuffmt.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCBUFFMT_H
+#define SILCBUFFMT_H
+
+/* Buffer parameter types.
+
+   _SI_ = signed
+   _UI_ = unsigned
+
+*/
+typedef enum {
+  SILC_BUFFER_PARAM_SI8_CHAR,
+  SILC_BUFFER_PARAM_UI8_CHAR,
+
+  SILC_BUFFER_PARAM_SI16_SHORT,
+  SILC_BUFFER_PARAM_UI16_SHORT,
+
+  SILC_BUFFER_PARAM_SI32_INT,
+  SILC_BUFFER_PARAM_UI32_INT,
+
+  SILC_BUFFER_PARAM_UI16_STRING,
+  SILC_BUFFER_PARAM_UI16_STRING_ALLOC,
+  SILC_BUFFER_PARAM_UI32_STRING,
+  SILC_BUFFER_PARAM_UI32_STRING_ALLOC,
+  SILC_BUFFER_PARAM_UI16_NSTRING,
+  SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC,
+  SILC_BUFFER_PARAM_UI32_NSTRING,
+  SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC,
+  SILC_BUFFER_PARAM_UI_XNSTRING,
+  SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC,
+
+  SILC_BUFFER_PARAM_END
+} SilcBufferParamType;
+
+/* Macros for expanding parameters into variable function argument list. 
+   These are passed to silc_buffer_format and silc_buffer_unformat 
+   functions. */
+
+/* One signed/unsigned character.
+
+   Formatting:    SILC_STR_SI_CHAR(char)
+                  SILC_STR_UI_CHAR(unsigned char)
+   Unformatting:  SILC_STR_SI_CHAR(char *)
+                  SILC_STR_UI_CHAR(unsigned char *)
+
+*/
+#define SILC_STR_SI_CHAR(x) SILC_BUFFER_PARAM_SI8_CHAR, (x)
+#define SILC_STR_UI_CHAR(x) SILC_BUFFER_PARAM_UI8_CHAR, (x)
+
+/* Signed/unsigned short. 
+
+   Formatting:    SILC_STR_SI_SHORT(short)
+                  SILC_STR_UI_SHORT(unsigned short)
+   Unformatting:  SILC_STR_SI_SHORT(short *)
+                  SILC_STR_UI_SHORT(unsigned short *)
+
+*/
+#define SILC_STR_SI_SHORT(x) SILC_BUFFER_PARAM_SI16_SHORT, (x)
+#define SILC_STR_UI_SHORT(x) SILC_BUFFER_PARAM_UI16_SHORT, (x)
+
+/* Signed/unsigned int. 
+
+   Formatting:    SILC_STR_SI_INT(int)
+                  SILC_STR_UI_INT(unsigned int)
+   Unformatting:  SILC_STR_SI_INT(int *)
+                  SILC_STR_UI_INT(unsigned int *)
+
+*/
+#define SILC_STR_SI_INT(x) SILC_BUFFER_PARAM_SI32_INT, (x)
+#define SILC_STR_UI_INT(x) SILC_BUFFER_PARAM_UI32_INT, (x)
+
+/* Unsigned NULL terminated string. Note that the string must be
+   NULL terminated because strlen() will be used to get the length of
+   the string. 
+
+   Formatting:    SILC_STR_UI32_STRING(unsigned char *)
+   Unformatting:  SILC_STR_UI32_STRING(unsigned char **)
+
+   Unformatting procedure will check for length of the string from the
+   buffer before trying to get the string out. Thus, one *must* format the
+   length as UI_INT or UI_SHORT into the buffer *before* formatting the 
+   actual string to the buffer, and, in unformatting one must ignore the 
+   length of the string because unformatting procedure will take it 
+   automatically.
+
+   Example:
+
+   Formatting:    ..., SILC_STR_UI_INT(strlen(string)), 
+                       SILC_STR_UI32_STRING(string), ...
+   Unformatting:  ..., SILC_STR_UI32_STRING(&string), ...
+
+   I.e., you ignore the formatted length field in unformatting. If you don't
+   the unformatting procedure might fail and it definitely does not unformat
+   the data reliably. 
+
+   _ALLOC routines automatically allocates memory for the variable sent 
+   as argument in unformatting.
+
+*/
+#define SILC_STR_UI16_STRING(x) SILC_BUFFER_PARAM_UI16_STRING, (x)
+#define SILC_STR_UI16_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI16_STRING_ALLOC, (x)
+#define SILC_STR_UI32_STRING(x) SILC_BUFFER_PARAM_UI32_STRING, (x)
+#define SILC_STR_UI32_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI32_STRING_ALLOC, (x)
+
+/* Unsigned string. Second argument is the length of the string.
+
+   Formatting:    SILC_STR_UI32_NSTRING(unsigned char *, unsigned int)
+   Unformatting:  SILC_STR_UI32_NSTRING(unsigned char **, unsigned int *)
+
+   Unformatting procedure will check for length of the string from the
+   buffer before trying to get the string out. Thus, one *must* format the
+   length as UI_INT or UI_SHORT into the buffer *before* formatting the 
+   actual string to the buffer, and, in unformatting one must ignore the 
+   length of the string because unformatting procedure will take it 
+   automatically.
+
+   Example:
+
+   Formatting:    ..., SILC_STR_UI_INT(strlen(string)), 
+                       SILC_STR_UI32_NSTRING(string, strlen(string)), ...
+   Unformatting:  ..., SILC_STR_UI32_NSTRING(&string, &len), ...
+
+   I.e., you ignore the formatted length field in unformatting. If you don't
+   the unformatting procedure might fail and it definitely does not unformat
+   the data reliably. The length taken from the buffer is returned to the
+   pointer sent as argument (&len in above example).
+
+   UI/SI16 and UI/SI32 means that the length is considered to be either
+   short (16 bits) or int (32 bits) in unformatting.
+
+   _ALLOC routines automatically allocates memory for the variable sent 
+   as argument in unformatting.
+
+*/
+#define SILC_STR_UI16_NSTRING(x, l) SILC_BUFFER_PARAM_UI16_NSTRING, (x), (l)
+#define SILC_STR_UI16_NSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC, (x), (l)
+#define SILC_STR_UI32_NSTRING(x, l) SILC_BUFFER_PARAM_UI32_NSTRING, (x), (l)
+#define SILC_STR_UI32_NSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC, (x), (l)
+
+/* Extended Unsigned string formatting. Second argument is the length of 
+   the string.
+
+   Formatting:    This is equal to using *_NSTRING
+   Unformatting:  SILC_STR_UI_XNSTRING(unsigned char **, unsigned int)
+
+   This type can be used to take arbitrary length string from the buffer
+   by sending the requested amount of bytes as argument. This differs
+   from *_STRING and *_NSTRING so that this doesn't try to find the
+   length of the data from the buffer but the length of the data is
+   sent as argument. This a handy way to unformat fixed length strings
+   from the buffer without having the length of the string formatted
+   in the buffer.
+
+   _ALLOC routines automatically allocates memory for the variable sent 
+   as argument in unformatting.
+
+*/
+#define SILC_STR_UI_XNSTRING(x, l) SILC_BUFFER_PARAM_UI_XNSTRING, (x), (l)
+#define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
+
+/* Marks end of the argument list. This must the at the end of the
+   argument list or error will occur. */
+#define SILC_STR_END SILC_BUFFER_PARAM_END
+
+/* Prototypes */
+int silc_buffer_format(SilcBuffer dst, ...);
+int silc_buffer_unformat(SilcBuffer src, ...);
+
+#endif
diff --git a/lib/silccore/silcbufutil.c b/lib/silccore/silcbufutil.c
new file mode 100644 (file)
index 0000000..f89389d
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+
+  silcbufutil.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#ifdef SILC_DEBUG              /* If we are doing debugging we won't
+                                  have the optimized inline buffer functions
+                                  available as optimization is not set
+                                  to compiler. These normal routines are
+                                  used in debugging mode. */
+
+/* Clears and initialiazes the buffer to the state as if it was just
+   allocated by silc_buffer_alloc. */
+
+void silc_buffer_clear(SilcBuffer sb)
+{
+  memset(sb->head, 0, sb->truelen);
+  sb->data = sb->head;
+  sb->tail = sb->head;
+  sb->len = 0;
+}
+
+/* Generates copy of a SilcBuffer. This copies everything inside the
+   currently valid data area, nothing more. Use silc_buffer_clone to
+   copy entire buffer. */
+
+SilcBuffer silc_buffer_copy(SilcBuffer sb)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_alloc(sb->len);
+  silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+  silc_buffer_put(sb_new, sb->data, sb->len);
+
+  return sb_new;
+}
+
+/* Clones SilcBuffer. This generates new SilcBuffer and copies
+   everything from the source buffer. The result is exact clone of
+   the original buffer. */
+
+SilcBuffer silc_buffer_clone(SilcBuffer sb)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_alloc(sb->truelen);
+  silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+  silc_buffer_put(sb_new, sb->head, sb->truelen);
+  sb_new->data = sb_new->head + sb->len;
+  sb_new->tail = sb_new->head + (sb->end - sb->tail);
+  sb_new->len = sb->len;
+
+  return sb_new;
+}
+
+#endif /* SILC_DEBUG */
diff --git a/lib/silccore/silcbufutil.h b/lib/silccore/silcbufutil.h
new file mode 100644 (file)
index 0000000..acbbcaf
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+
+  silcbufutil.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCBUFUTIL_H
+#define SILCBUFUTIL_H
+
+#ifndef SILC_DEBUG             /* When we are not doing debugging we use
+                                  optimized inline buffer functions. */
+
+/* Clears and initialiazes the buffer to the state as if it was just
+   allocated by silc_buffer_alloc. */
+
+extern inline
+void silc_buffer_clear(SilcBuffer sb)
+{
+  memset(sb->head, 0, sb->truelen);
+  sb->data = sb->head;
+  sb->tail = sb->head;
+  sb->len = 0;
+}
+
+/* Generates copy of a SilcBuffer. This copies everything inside the
+   currently valid data area, nothing more. Use silc_buffer_clone to
+   copy entire buffer. */
+
+extern inline
+SilcBuffer silc_buffer_copy(SilcBuffer sb)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_alloc(sb->len);
+  silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+  silc_buffer_put(sb_new, sb->data, sb->len);
+
+  return sb_new;
+}
+
+/* Clones SilcBuffer. This generates new SilcBuffer and copies
+   everything from the source buffer. The result is exact clone of
+   the original buffer. */
+
+extern inline
+SilcBuffer silc_buffer_clone(SilcBuffer sb)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_alloc(sb->truelen);
+  silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+  silc_buffer_put(sb_new, sb->head, sb->truelen);
+  sb_new->data = sb_new->head + sb->len;
+  sb_new->tail = sb_new->head + (sb->end - sb->tail);
+  sb_new->len = sb->len;
+
+  return sb_new;
+}
+
+#endif /* !SILC_DEBUG */
+
+/* Prototypes */
+#ifdef SILC_DEBUG
+void silc_buffer_clear(SilcBuffer sb);
+SilcBuffer silc_buffer_copy(SilcBuffer sb);
+SilcBuffer silc_buffer_clone(SilcBuffer sb);
+#endif
+
+#endif
diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c
new file mode 100644 (file)
index 0000000..6355f71
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+
+  silcchannel.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcchannel.h"
+
+/* Channel Payload structure. Contents of this structure is parsed
+   from SILC packets. */
+struct SilcChannelPayloadStruct {
+  unsigned short nick_len;
+  unsigned char *nick;
+  unsigned short data_len;
+  unsigned char *data;
+  unsigned short iv_len;
+  unsigned char *iv;
+};
+
+/* Channel Key Payload structrue. Channel keys are parsed from SILC
+   packets into this structure. */
+struct SilcChannelKeyPayloadStruct {
+  unsigned short id_len;
+  unsigned char *id;
+  unsigned short cipher_len;
+  unsigned char *cipher;
+  unsigned short key_len;
+  unsigned char *key;
+};
+
+/* Parses channel payload returning new channel payload structure */
+
+SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
+{
+  SilcChannelPayload new;
+
+  SILC_LOG_DEBUG(("Parsing channel payload"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new channel payload"));
+    return NULL;
+  }
+
+  /* Parse the Channel Payload. Ignore padding and IV, we don't need
+     them. */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_NSTRING_ALLOC(&new->nick, &new->nick_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL),
+                      SILC_STR_END);
+
+  if (new->data_len < 1) {
+    SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
+    goto err;
+  }
+
+  return new;
+
+ err:
+  if (new->nick)
+    silc_free(new->nick);
+  if (new->data)
+    silc_free(new->data);
+  if (new->iv)
+    silc_free(new->iv);
+  silc_free(new);
+  return NULL;
+}
+
+/* Encodes channel payload into a buffer and returns it. This is used 
+   to add channel payload into a packet. As the channel payload is
+   encrypted separately from other parts of the packet padding must
+   be applied to the payload. */
+
+SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
+                                      unsigned char *nick,
+                                      unsigned short data_len,
+                                      unsigned char *data,
+                                      unsigned short iv_len,
+                                      unsigned char *iv,
+                                      SilcRng rng)
+{
+  int i;
+  SilcBuffer buffer;
+  unsigned int len, pad_len;
+  unsigned char pad[SILC_PACKET_MAX_PADLEN];
+
+  SILC_LOG_DEBUG(("Encoding channel payload"));
+
+  /* Calculate length of padding. IV is not included into the calculation
+     since it is not encrypted. */
+  len = 2 + nick_len + 2 + data_len + 2;
+  pad_len = SILC_PACKET_PADLEN((len + 2));
+
+  /* Allocate channel payload buffer */
+  len += pad_len;
+  buffer = silc_buffer_alloc(len + iv_len);
+  if (!buffer)
+    return NULL;
+
+  /* Generate padding */
+  for (i = 0; i < pad_len; i++)
+    pad[i] = silc_rng_get_byte(rng);
+
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+  /* Encode the Channel Payload */
+  silc_buffer_format(buffer, 
+                    SILC_STR_UI_SHORT(nick_len),
+                    SILC_STR_UI_XNSTRING(nick, nick_len),
+                    SILC_STR_UI_SHORT(data_len),
+                    SILC_STR_UI_XNSTRING(data, data_len),
+                    SILC_STR_UI_SHORT(pad_len),
+                    SILC_STR_UI_XNSTRING(pad, pad_len),
+                    SILC_STR_UI_XNSTRING(iv, iv_len),
+                    SILC_STR_END);
+
+  memset(pad, 0, pad_len);
+  return buffer;
+}
+
+/* Free's Channel Payload */
+
+void silc_channel_free_payload(SilcChannelPayload payload)
+{
+  if (payload) {
+    if (payload->data)
+      silc_free(payload->data);
+    if (payload->iv)
+      silc_free(payload->iv);
+    silc_free(payload);
+  }
+}
+
+/* Return nickname */
+
+unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
+                                        unsigned int *nick_len)
+{
+  if (nick_len)
+    *nick_len = payload->nick_len;
+
+  return payload->nick;
+}
+
+/* Return data */
+
+unsigned char *silc_channel_get_data(SilcChannelPayload payload,
+                                    unsigned int *data_len)
+{
+  if (data_len)
+    *data_len = payload->data_len;
+
+  return payload->data;
+}
+
+/* Return initial vector */
+
+unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
+                                  unsigned int *iv_len)
+{
+  if (iv_len)
+    *iv_len = payload->iv_len;
+
+  return payload->iv;
+}
+
+/* Parses channel key payload returning new channel key payload structure */
+
+SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer)
+{
+  SilcChannelKeyPayload new;
+
+  SILC_LOG_DEBUG(("Parsing channel key payload"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new channel key payload"));
+    return NULL;
+  }
+
+  /* Parse the Channel Key Payload */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
+                                                  &new->cipher_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
+                      SILC_STR_END);
+
+  if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
+    SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
+    goto err;
+  }
+
+  return new;
+
+ err:
+  if (new->id)
+    silc_free(new->id);
+  if (new->cipher)
+    silc_free(new->cipher);
+  if (new->key)
+    silc_free(new->key);
+  silc_free(new);
+  return NULL;
+}
+
+/* Encodes channel key payload into a buffer and returns it. This is used 
+   to add channel key payload into a packet. */
+
+SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
+                                          unsigned char *id,
+                                          unsigned short cipher_len,
+                                          unsigned char *cipher,
+                                          unsigned short key_len,
+                                          unsigned char *key)
+{
+  SilcBuffer buffer;
+  unsigned int len;
+
+  SILC_LOG_DEBUG(("Encoding channel key payload"));
+
+  /* Sanity checks */
+  if (!id_len || !key_len || !id || !key || !cipher_len || !cipher)
+    return NULL;
+
+  /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
+     2 + cipher */
+  len = 2 + id_len + 2 + key_len + 2 + cipher_len;
+  buffer = silc_buffer_alloc(len);
+  if (!buffer)
+    return NULL;
+
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+  /* Encode the Channel Payload */
+  silc_buffer_format(buffer, 
+                    SILC_STR_UI_SHORT(id_len),
+                    SILC_STR_UI_XNSTRING(id, id_len),
+                    SILC_STR_UI_SHORT(cipher_len),
+                    SILC_STR_UI_XNSTRING(cipher, cipher_len),
+                    SILC_STR_UI_SHORT(key_len),
+                    SILC_STR_UI_XNSTRING(key, key_len),
+                    SILC_STR_END);
+
+  return buffer;
+}
+
+/* Free's Channel Key Payload */
+
+void silc_channel_key_free_payload(SilcChannelKeyPayload payload)
+{
+  if (payload) {
+    if (payload->id)
+      silc_free(payload->id);
+    if (payload->cipher)
+      silc_free(payload->cipher);
+    if (payload->key) {
+      memset(payload->key, 0, payload->key_len);
+      silc_free(payload->key);
+    }
+    silc_free(payload);
+  }
+}
+
+/* Return ID */
+
+unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
+                                      unsigned int *id_len)
+{
+  if (id_len)
+    *id_len = payload->id_len;
+
+  return payload->id;
+}
+
+/* Return cipher name */
+
+unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
+                                          unsigned int *cipher_len)
+{
+  if (cipher_len)
+    *cipher_len = payload->cipher_len;
+
+  return payload->cipher;
+}
+
+/* Return key */
+
+unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
+                                       unsigned int *key_len)
+{
+  if (key_len)
+    *key_len = payload->key_len;
+
+  return payload->key;
+}
diff --git a/lib/silccore/silcchannel.h b/lib/silccore/silcchannel.h
new file mode 100644 (file)
index 0000000..b39045f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+
+  silcchannel.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCHANNEL_H
+#define SILCCHANNEL_H
+
+/* Forward declaration for Channel Payload parsed from packet. The
+   actual structure is defined in source file and is private data. */
+typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
+
+/* Forward declaration for Channel Key Payload parsed from packet. The
+   actual structure is defined in source file and is private data. */
+typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
+
+/* Channel modes */
+#define SILC_CHANNEL_MODE_NONE       0x0000
+#define SILC_CHANNEL_MODE_PRIVATE    0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET     0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY    0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE     0x0008 /* invite only channel */
+
+/* User modes on channel */
+#define SILC_CHANNEL_UMODE_NONE      0x0000
+#define SILC_CHANNEL_UMODE_CHANFO    0x0001 /* channel founder */
+#define SILC_CHANNEL_UMODE_CHANOP    0x0002 /* channel operator */
+
+/* Prototypes */
+SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer);
+SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
+                                      unsigned char *nick,
+                                      unsigned short data_len,
+                                      unsigned char *data,
+                                      unsigned short iv_len,
+                                      unsigned char *iv,
+                                      SilcRng rng);
+void silc_channel_free_payload(SilcChannelPayload payload);
+unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
+                                        unsigned int *nick_len);
+unsigned char *silc_channel_get_data(SilcChannelPayload payload,
+                                    unsigned int *data_len);
+unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
+                                  unsigned int *iv_len);
+SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer);
+SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
+                                          unsigned char *id,
+                                          unsigned short cipher_len,
+                                          unsigned char *cipher,
+                                          unsigned short key_len,
+                                          unsigned char *key);
+void silc_channel_key_free_payload(SilcChannelKeyPayload payload);
+unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
+                                      unsigned int *id_len);
+unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
+                                          unsigned int *cipher_len);
+unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
+                                       unsigned int *key_len);
+
+#endif
diff --git a/lib/silccore/silccommand.c b/lib/silccore/silccommand.c
new file mode 100644 (file)
index 0000000..881477d
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+
+  silccommand.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silccommand.h"
+
+/* Command Payload structure. Contents of this structure is parsed
+   from SILC packets. */
+struct SilcCommandPayloadStruct {
+  SilcCommand cmd;
+  unsigned int argc;
+  unsigned char **argv;
+  unsigned int *argv_lens;
+  unsigned int *argv_types;
+  unsigned int pos;
+};
+
+/* Length of the command payload */
+#define SILC_COMMAND_PAYLOAD_LEN 4
+
+/* Parses command payload returning new command payload structure */
+
+SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer)
+{
+  SilcCommandPayload new;
+  unsigned short payload_len = 0;
+  unsigned char args_num = 0;
+  unsigned char arg_num = 0;
+  unsigned int arg_type = 0;
+  unsigned int pull_len = 0;
+  int i = 0;
+
+  SILC_LOG_DEBUG(("Parsing command payload"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new command payload"));
+    return NULL;
+  }
+
+  /* Parse the Command Payload */
+  silc_buffer_unformat(buffer, 
+                      SILC_STR_UI_CHAR(&new->cmd),
+                      SILC_STR_UI_CHAR(&args_num),
+                      SILC_STR_UI_SHORT(&payload_len),
+                      SILC_STR_END);
+
+  if (payload_len != buffer->len) {
+    SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
+    return NULL;
+  }
+
+  if (new->cmd == 0)
+    return NULL;
+
+  if (args_num && payload_len) {
+
+    new->argv = silc_calloc(args_num, sizeof(unsigned char *));
+    new->argv_lens = silc_calloc(args_num, sizeof(unsigned int));
+    new->argv_types = silc_calloc(args_num, sizeof(unsigned int));
+
+    silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
+    pull_len += SILC_COMMAND_PAYLOAD_LEN;
+
+    /* Parse Command Argument Payloads */
+    arg_num = 1;
+    while(arg_num) {
+      silc_buffer_unformat(buffer,
+                          SILC_STR_UI_CHAR(&arg_num),
+                          SILC_STR_UI_CHAR(&arg_type),
+                          SILC_STR_UI_SHORT(&payload_len),
+                          SILC_STR_END);
+
+      /* Check that argument number is correct */
+      if (arg_num != i + 1)
+       goto err;
+
+      new->argv_lens[i] = payload_len;
+      new->argv_types[i] = arg_type;
+
+      /* Get argument data */
+      silc_buffer_pull(buffer, 4);
+      silc_buffer_unformat(buffer,
+                          SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
+                                                     payload_len),
+                          SILC_STR_END);
+      silc_buffer_pull(buffer, payload_len);
+      pull_len += 4 + payload_len;
+
+      i++;
+
+      if (i == args_num)
+       break;
+    }
+
+    /* Check the number of arguments */
+    if (arg_num != args_num)
+      goto err;
+  }
+
+  new->argc = i;
+  new->pos = 0;
+
+  silc_buffer_push(buffer, pull_len);
+
+  return new;
+
+ err:
+  if (i) {
+    int k;
+
+    for (k = 0; k < i; k++)
+      silc_free(new->argv[k]);
+  }
+
+  silc_free(new->argv);
+  silc_free(new->argv_lens);
+  silc_free(new->argv_types);
+
+  if (new)
+    silc_free(new);
+
+  return NULL;
+}
+
+/* Encodes Command Payload returning it to SilcBuffer. */
+
+SilcBuffer silc_command_encode_payload(SilcCommand cmd,
+                                      unsigned int argc,
+                                      unsigned char **argv,
+                                      unsigned int *argv_lens,
+                                      unsigned int *argv_types)
+{
+  SilcBuffer buffer;
+  unsigned int len;
+  int i;
+
+  SILC_LOG_DEBUG(("Encoding command payload"));
+
+  len = 1 + 1 + 2;
+  for (i = 0; i < argc; i++)
+    len += 1 + 1 + 2 + argv_lens[i];
+
+  buffer = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+  /* Create Command payload */
+  silc_buffer_format(buffer,
+                    SILC_STR_UI_CHAR(cmd),
+                    SILC_STR_UI_CHAR(argc),
+                    SILC_STR_UI_SHORT(len),
+                    SILC_STR_END);
+
+  /* Put arguments */
+  if (argc) {
+    silc_buffer_pull(buffer, 4);
+   
+    for (i = 0; i < argc; i++) {
+      silc_buffer_format(buffer,
+                        SILC_STR_UI_CHAR(i + 1),
+                        SILC_STR_UI_CHAR(argv_types[i]),
+                        SILC_STR_UI_SHORT(argv_lens[i]),
+                        SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
+                        SILC_STR_END);
+      silc_buffer_pull(buffer, 4 + argv_lens[i]);
+    }
+
+    silc_buffer_push(buffer, len);
+  }
+
+  return buffer;
+}
+
+/* Encodes Command payload with variable argument list. The arguments
+   must be: unsigned char *, unsigned int, ... One unsigned char *
+   and unsigned int forms one argument, hence `argc' in case when
+   sending one unsigned char * and unsigned int equals one (1) and
+   when sending two of those it equals two (2), and so on. This has
+   to be preserved or bad things will happen. */
+
+SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, 
+                                         unsigned int argc, ...)
+{
+  va_list ap;
+  unsigned char **argv;
+  unsigned int *argv_lens = NULL, *argv_types = NULL;
+  unsigned char *x;
+  unsigned int x_len;
+  SilcBuffer buffer;
+  int i;
+
+  va_start(ap, argc);
+
+  argv = silc_calloc(argc, sizeof(unsigned char *));
+  argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  argv_types = silc_calloc(argc, sizeof(unsigned int));
+
+  for (i = 0; i < argc; i++) {
+    x = va_arg(ap, unsigned char *);
+    x_len = va_arg(ap, unsigned int);
+
+    argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+    memcpy(argv[i], x, x_len);
+    argv_lens[i] = x_len;
+    argv_types[i] = i + 1;
+  }
+
+  buffer = silc_command_encode_payload(cmd, argc, argv, 
+                                      argv_lens, argv_types);
+
+  for (i = 0; i < argc; i++)
+    silc_free(argv[i]);
+  silc_free(argv);
+  silc_free(argv_lens);
+  silc_free(argv_types);
+
+  return buffer;
+}
+
+/* Free's Command Payload */
+
+void silc_command_free_payload(SilcCommandPayload payload)
+{
+  int i;
+
+  if (payload) {
+    for (i = 0; i < payload->argc; i++)
+      silc_free(payload->argv[i]);
+
+    silc_free(payload->argv);
+    silc_free(payload);
+  }
+}
+
+/* Returns the command type in payload */
+
+SilcCommand silc_command_get(SilcCommandPayload payload)
+{
+  return payload->cmd;
+}
+
+/* Returns number of arguments in payload */
+
+unsigned int silc_command_get_arg_num(SilcCommandPayload payload)
+{
+  return payload->argc;
+}
+
+/* Returns first argument from payload. */
+
+unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
+                                         unsigned int *ret_len)
+{
+  payload->pos = 0;
+
+  if (ret_len)
+    *ret_len = payload->argv_lens[payload->pos];
+
+  return payload->argv[payload->pos++];
+}
+
+/* Returns next argument from payload or NULL if no more arguments. */
+
+unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
+                                        unsigned int *ret_len)
+{
+  if (payload->pos >= payload->argc)
+    return NULL;
+
+  if (ret_len)
+    *ret_len = payload->argv_lens[payload->pos];
+
+  return payload->argv[payload->pos++];
+}
+
+/* Returns argument which type is `type'. */
+
+unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
+                                        unsigned int type,
+                                        unsigned int *ret_len)
+{
+  int i;
+
+  for (i = 0; i < payload->argc; i++)
+    if (payload->argv_types[i] == type)
+      break;
+
+  if (i >= payload->argc)
+    return NULL;
+
+  if (ret_len)
+    *ret_len = payload->argv_lens[i];
+
+  return payload->argv[i];
+}
+
+/* Encodes command status payload. Status payload is sent as one reply
+   argument. The returned payload still has to be saved into the 
+   Command Argument payload. */
+
+SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
+                                             unsigned char *data,
+                                             unsigned int len)
+{
+  SilcBuffer sp;
+
+  sp = silc_buffer_alloc(len + 2);
+  silc_buffer_pull_tail(sp, SILC_BUFFER_END(sp));
+  silc_buffer_format(sp,
+                    SILC_STR_UI_SHORT(status),
+                    SILC_STR_UI_XNSTRING(data, len),
+                    SILC_STR_END);
+
+  return sp;
+}
diff --git a/lib/silccore/silccommand.h b/lib/silccore/silccommand.h
new file mode 100644 (file)
index 0000000..80c7ece
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+
+  silccommand.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCOMMAND_H
+#define SILCCOMMAND_H
+
+/* Command function callback. The actual command function pointer. */
+typedef void (*SilcCommandCb)(void *context);
+
+/* Typedefinition for SILC commands. */
+typedef unsigned char SilcCommand;
+
+/* Forward declaration for Command Payload parsed from packet. The
+   actual structure is defined in source file and is private data. */
+typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
+
+/* Command flags. These set how the commands behave on different
+   situations. These can be OR'ed together to set multiple flags. */
+typedef enum {
+  SILC_CF_NONE = 0,
+
+  /* Command may only be used once per (about) 2 seconds */
+  SILC_CF_LAG = (1L << 1),
+
+  /* Command is available for registered connections (connections
+     whose ID has been created. */
+  SILC_CF_REG = (1L << 2),
+
+  /* Command is available only for server operators */
+  SILC_CF_OPER = (1L << 3),
+
+  /* Command is available only for SILC (router) operators. If this 
+     is set SILC_CF_OPER is not necessary to be set. */
+  SILC_CF_SILC_OPER = (1L << 4),
+
+} SilcCommandFlag;
+
+/* All SILC commands. These are commands that have client and server
+   counterparts. These are pretty much the same as in IRC. */
+#define SILC_COMMAND_NONE               0
+#define SILC_COMMAND_WHOIS             2
+#define SILC_COMMAND_WHOWAS            3
+#define SILC_COMMAND_IDENTIFY           4
+#define SILC_COMMAND_NICK              5
+#define SILC_COMMAND_LIST              6
+#define SILC_COMMAND_TOPIC             7
+#define SILC_COMMAND_INVITE            8
+#define SILC_COMMAND_QUIT              9
+#define SILC_COMMAND_KILL              10
+#define SILC_COMMAND_INFO              11
+#define SILC_COMMAND_CONNECT           12
+#define SILC_COMMAND_PING              13
+#define SILC_COMMAND_OPER              14
+#define SILC_COMMAND_JOIN              15
+#define SILC_COMMAND_MOTD              16
+#define SILC_COMMAND_UMODE             17
+#define SILC_COMMAND_CMODE             18
+#define SILC_COMMAND_KICK              19
+#define        SILC_COMMAND_RESTART            20
+#define        SILC_COMMAND_CLOSE              21
+#define        SILC_COMMAND_DIE                22
+#define SILC_COMMAND_SILCOPER          23
+#define SILC_COMMAND_LEAVE             24
+#define SILC_COMMAND_NAMES             25
+
+/* Local commands. Local commands are unofficial commands and
+   are implementation specific commands. These are used only by the
+   SILC client to extend user commands. */
+#define SILC_COMMAND_HELP              100
+#define SILC_COMMAND_CLEAR             101
+#define SILC_COMMAND_VERSION           102
+#define SILC_COMMAND_SERVER             103
+#define SILC_COMMAND_MSG               104
+#define SILC_COMMAND_AWAY              105
+
+/* Reserved */
+#define SILC_COMMAND_RESERVED           255
+
+/* Command Status type */
+typedef unsigned short SilcCommandStatus;
+
+/* Command Status messages */
+#define SILC_STATUS_OK                      0
+#define SILC_STATUS_LIST_START              1
+#define SILC_STATUS_LIST_END                2
+#define SILC_STATUS_ERR_NO_SUCH_NICK        10
+#define SILC_STATUS_ERR_NO_SUCH_CHANNEL     11
+#define SILC_STATUS_ERR_NO_SUCH_SERVER      12
+#define SILC_STATUS_ERR_TOO_MANY_TARGETS    13
+#define SILC_STATUS_ERR_NO_RECIPIENT        14
+#define SILC_STATUS_ERR_UNKNOWN_COMMAND     15
+#define SILC_STATUS_ERR_WILDCARDS           16
+#define SILC_STATUS_ERR_NO_CLIENT_ID        17
+#define SILC_STATUS_ERR_NO_CHANNEL_ID       18
+#define SILC_STATUS_ERR_BAD_CLIENT_ID       19
+#define SILC_STATUS_ERR_BAD_CHANNEL_ID      20
+#define SILC_STATUS_ERR_NO_SUCH_CLIENT_ID   21
+#define SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID  22
+#define SILC_STATUS_ERR_NICKNAME_IN_USE     23
+#define SILC_STATUS_ERR_NOT_ON_CHANNEL      24
+#define SILC_STATUS_ERR_USER_ON_CHANNEL     25
+#define SILC_STATUS_ERR_NOT_REGISTERED      26
+#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS   27
+#define SILC_STATUS_ERR_TOO_MANY_PARAMS     28
+#define SILC_STATUS_ERR_PERM_DENIED         29
+#define SILC_STATUS_ERR_BANNED_FROM_SERVER  30
+#define SILC_STATUS_ERR_BAD_PASSWORD        31
+#define SILC_STATUS_ERR_CHANNEL_IS_FULL     32
+#define SILC_STATUS_ERR_NOT_INVITED         33
+#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 34
+#define SILC_STATUS_ERR_UNKNOWN_MODE        35
+#define SILC_STATUS_ERR_NOT_YOU             36
+#define SILC_STATUS_ERR_NO_CHANNEL_PRIV     37
+#define SILC_STATUS_ERR_NO_SERVER_PRIV      38
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV      39
+#define SILC_STATUS_ERR_BAD_NICKNAME        40
+#define SILC_STATUS_ERR_BAD_CHANNEL         41
+#define SILC_STATUS_ERR_AUTH_FAILED         42
+
+/* Prototypes */
+SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer);
+SilcBuffer silc_command_encode_payload(SilcCommand cmd,
+                                      unsigned int argc,
+                                      unsigned char **argv,
+                                      unsigned int *argv_lens,
+                                      unsigned int *argv_types);
+SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, 
+                                         unsigned int argc, ...);
+void silc_command_free_payload(SilcCommandPayload payload);
+SilcCommand silc_command_get(SilcCommandPayload payload);
+unsigned int silc_command_get_arg_num(SilcCommandPayload payload);
+unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
+                                         unsigned int *ret_len);
+unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
+                                        unsigned int *ret_len);
+unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
+                                        unsigned int type,
+                                        unsigned int *ret_len);
+SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
+                                             unsigned char *data,
+                                             unsigned int len);
+
+#endif
diff --git a/lib/silccore/silcconfig.c b/lib/silccore/silcconfig.c
new file mode 100644 (file)
index 0000000..bb32422
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+
+  silcconfig.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Opens and reads a configuration file to a buffer. The read data is 
+   returned to the ret_buffer argument. */
+
+void silc_config_open(char *filename, SilcBuffer *ret_buffer)
+{
+  char *buffer;
+  int filelen;
+
+  buffer = silc_file_read(filename, &filelen);
+  if (buffer == NULL)
+    return;
+
+  /* Buffer don't have EOF, but we'll need it. */
+  buffer[filelen] = EOF;
+
+  *ret_buffer = silc_buffer_alloc(filelen + 1);
+  silc_buffer_pull_tail(*ret_buffer, filelen + 1);
+  silc_buffer_put(*ret_buffer, buffer, filelen + 1);
+
+  SILC_LOG_DEBUG(("Config file `%s' opened", filename));
+}
+
+/* Returns next token from a buffer to the dest argument. Returns the
+   length of the token. This is used to take tokens from a configuration
+   line. */
+
+int silc_config_get_token(SilcBuffer buffer, char **dest)
+{
+  int len;
+
+  if (strchr(buffer->data, ':')) {
+    len = strcspn(buffer->data, ":");
+    if (len) {
+      *dest = silc_calloc(len + 1, sizeof(char));
+      memset(*dest, 0, len + 1);
+      memcpy(*dest, buffer->data, len);
+    }
+    silc_buffer_pull(buffer, len + 1);
+    return len;
+  }
+
+  return -1;
+}
+
+/* Returns number of tokens in a buffer. */
+
+int silc_config_check_num_token(SilcBuffer buffer)
+{
+  int len, len2, num;
+
+  if (strchr(buffer->data, ':')) {
+    len = 0;
+    num = 0;
+    while (strchr(buffer->data + len, ':')) {
+      num++;
+      len2 = strcspn(buffer->data + len, ":") + 1;
+      len += len2;
+    }
+
+    return num;
+  }
+
+  return 0;
+}
diff --git a/lib/silccore/silcconfig.h b/lib/silccore/silcconfig.h
new file mode 100644 (file)
index 0000000..3153f25
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+
+  silcconfig.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCONFIG_H
+#define SILCCONFIG_H
+
+/* Prototypes */
+void silc_config_open(char *filename, SilcBuffer *ret_buffer);
+int silc_config_get_token(SilcBuffer buffer, char **dest);
+int silc_config_check_num_token(SilcBuffer);
+
+#endif
diff --git a/lib/silccore/silclog.c b/lib/silccore/silclog.c
new file mode 100644 (file)
index 0000000..d866ecc
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+
+  silclog.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* SILC Log name strings. These strings are printed to the log file. */
+const SilcLogTypeName silc_log_types[] =
+{
+  { "Info", SILC_LOG_INFO },
+  { "Warning", SILC_LOG_WARNING },
+  { "Error", SILC_LOG_ERROR },
+  { "Fatal", SILC_LOG_FATAL },
+
+  { NULL, -1 },
+};
+
+char *log_info_file;
+char *log_warning_file;
+char *log_error_file;
+char *log_fatal_file;
+unsigned int log_info_size;
+unsigned int log_warning_size;
+unsigned int log_error_size;
+unsigned int log_fatal_size;
+
+/* Formats arguments to a string and returns it after allocating memory
+   for it. It must be remembered to free it later. */
+
+char *silc_log_format(char *fmt, ...)
+{
+  va_list args;
+  static char buf[1024];
+
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  va_end(args);
+
+  return strdup(buf);
+}
+
+/* Outputs the log message to what ever log file selected. */
+
+void silc_log_output(const char *filename, unsigned int maxsize,
+                     SilcLogType type, char *string)
+{
+  FILE *fp;
+  const SilcLogTypeName *np;
+
+  /* Purge the log file if the max size is defined. */
+  if (maxsize) {
+    fp = fopen(filename, "r");
+    if (fp) {
+      int filelen;
+      
+      filelen = fseek(fp, (off_t)0L, SEEK_END);
+      fseek(fp, (off_t)0L, SEEK_SET);  
+      
+      /* Purge? */
+      if (maxsize >= filelen)
+       unlink(filename);
+    }
+  }
+
+  /* Open the log file */
+  if ((fp = fopen(filename, "a+")) == NULL) {
+    fprintf(stderr, "warning: could not open log file "
+           "%s: %s\n", filename, strerror(errno));
+    fprintf(stderr, "warning: log messages will be displayed on the screen\n");
+    fp = stderr;
+  }
+  /* Get the log type name */
+  for(np = silc_log_types; np->name; np++) {
+    if (np->type == type)
+      break;
+  }
+
+  fprintf(fp, "[%s] [%s] %s\n", silc_get_time(), np->name, string);
+  fflush(fp);
+  fclose(fp);
+  silc_free(string);
+}
+
+/* Outputs the debug message to stderr. */
+
+void silc_log_output_debug(char *file, char *function, 
+                          int line, char *string)
+{
+  /* fprintf(stderr, "%s:%s:%d: %s\n", file, function, line, string); */
+  fprintf(stderr, "%s:%d: %s\n", function, line, string);
+  fflush(stderr);
+  silc_free(string);
+}
+
+/* Hexdumps a message */
+
+void silc_log_output_hexdump(char *file, char *function, 
+                            int line, void *data_in,
+                            unsigned int len, char *string)
+{
+  int i, k;
+  int off, pos, count;
+  unsigned char *data = (unsigned char *)data_in;
+
+  /* fprintf(stderr, "%s:%s:%d: %s\n", file, function, line, string); */
+  fprintf(stderr, "%s:%d: %s\n", function, line, string);
+  silc_free(string);
+
+  k = 0;
+  off = len % 16;
+  pos = 0;
+  count = 16;
+  while (1) {
+
+    if (off) {
+      if ((len - pos) < 16 && (len - pos <= len - off))
+       count = off;
+    } else {
+      if (pos == len)
+       count = 0;
+    }
+    if (off == len)
+      count = len;
+
+    if (count)
+      fprintf(stderr, "%08X  ", k++ * 16);
+
+    for (i = 0; i < count; i++) {
+      fprintf(stderr, "%02X ", data[pos + i]);
+      
+      if ((i + 1) % 4 == 0)
+       fprintf(stderr, " ");
+    }
+
+    if (count && count < 16) {
+      int j;
+      
+      for (j = 0; j < 16 - count; j++) {
+       fprintf(stderr, "   ");
+
+       if ((j + count + 1) % 4 == 0)
+         fprintf(stderr, " ");
+      }
+    }
+  
+    for (i = 0; i < count; i++) {
+      char ch;
+      
+      if (data[pos] < 32 || data[pos] >= 127)
+       ch = '.';
+      else
+       ch = data[pos];
+
+      fprintf(stderr, "%c", ch);
+      pos++;
+    }
+
+    if (count)
+      fprintf(stderr, "\n");
+
+    if (count < 16)
+      break;
+  }
+}
+
+/* Sets log files */
+
+void silc_log_set_files(char *info, unsigned int info_size, 
+                       char *warning, unsigned int warning_size,
+                       char *error, unsigned int error_size,
+                       char *fatal, unsigned int fatal_size)
+{
+  log_info_file = info;
+  log_warning_file = warning;
+  log_error_file = error;
+  log_fatal_file = fatal;
+
+  log_info_size = info_size;
+  log_warning_size = warning_size;
+  log_error_size = error_size;
+  log_fatal_size = fatal_size;
+}
diff --git a/lib/silccore/silclog.h b/lib/silccore/silclog.h
new file mode 100644 (file)
index 0000000..3cfc499
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+
+  silclog.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCLOG_H
+#define SILCLOG_H
+
+/* SILC Log types */
+typedef enum {
+  SILC_LOG_INFO,
+  SILC_LOG_WARNING,
+  SILC_LOG_ERROR,
+  SILC_LOG_FATAL
+} SilcLogType;
+
+/* Log type name structure. */
+typedef struct {
+  char *name;
+  SilcLogType type;
+} SilcLogTypeName;
+
+/* Default log filenames */
+#define SILC_LOG_FILE_INFO "silcd.log"
+#define SILC_LOG_FILE_WARNING "silcd_error.log"
+#define SILC_LOG_FILE_ERROR SILC_LOG_FILE_WARNING
+#define SILC_LOG_FILE_FATAL SILC_LOG_FILE_WARNING
+
+/* Log files. Set by silc_log_set_logfiles. */
+extern char *log_info_file;
+extern char *log_warning_file;
+extern char *log_error_file;
+extern char *log_fatal_file;
+extern unsigned int log_info_size;
+extern unsigned int log_warning_size;
+extern unsigned int log_error_size;
+extern unsigned int log_fatal_size;
+
+/* Log macros. */
+#define SILC_LOG_INFO(fmt) silc_log_output(log_info_file, \
+                                           log_info_size, \
+                                          SILC_LOG_INFO, \
+                                          silc_log_format fmt)) 
+#define SILC_LOG_WARNING(fmt) (silc_log_output(log_warning_file, \
+                                               log_warning_size, \
+                                              SILC_LOG_WARNING, \
+                                              silc_log_format fmt))
+#define SILC_LOG_ERROR(fmt) (silc_log_output(log_error_file, \
+                                             log_error_size, \
+                                            SILC_LOG_ERROR, \
+                                            silc_log_format fmt))
+#define SILC_LOG_FATAL(fmt) (silc_log_output(log_fatal_file, \
+                                             log_fatal_size, \
+                                            SILC_LOG_FATAL, \
+                                            silc_log_format fmt))
+
+/* Debug macro is a bit different from other logging macros and it
+   is compiled in only if debugging is enabled. */
+#ifdef SILC_DEBUG
+#define SILC_LOG_DEBUG(fmt) (silc_log_output_debug(__FILE__, \
+                                                  __FUNCTION__, \
+                                                  __LINE__, \
+                                                  silc_log_format fmt))
+#define SILC_LOG_HEXDUMP(fmt, data, len) \
+  (silc_log_output_hexdump(__FILE__, \
+                          __FUNCTION__, \
+                          __LINE__, \
+                           (data), (len), \
+                          silc_log_format fmt))
+#else
+#define SILC_LOG_DEBUG(fmt)
+#define SILC_LOG_HEXDUMP(fmt, data, len)
+#endif
+
+/* Prototypes */
+char *silc_log_format(char *fmt, ...);
+void silc_log_output_debug(char *file, char *function, 
+                           int line, char *string);
+void silc_log_output(const char *filename, unsigned int maxsize,
+                     SilcLogType type, char *string);
+void silc_log_output_hexdump(char *file, char *function, 
+                            int line, void *data_in,
+                             unsigned int len, char *string);
+void silc_log_set_files(char *info, unsigned int info_size, 
+                       char *warning, unsigned int warning_size,
+                       char *error, unsigned int error_size,
+                        char *fatal, unsigned int fatal_size);
+
+#endif
diff --git a/lib/silccore/silcmemory.c b/lib/silccore/silcmemory.c
new file mode 100644 (file)
index 0000000..e385cd4
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+
+  silcmemory.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+void *silc_malloc(size_t size)
+{
+#ifdef HAVE_MLOCK
+  void *addr = malloc(size);
+  mlock(addr, size);
+  return addr;
+#else
+  return malloc(size);
+#endif
+}
+
+void *silc_calloc(size_t items, size_t size)
+{
+#ifdef HAVE_MLOCK
+  void *addr = calloc(items, size);
+  mlock(addr, size);
+  return addr;
+#else
+  return calloc(items, size);
+#endif
+}
+
+void *silc_realloc(void *ptr, size_t size)
+{
+#ifdef HAVE_MLOCK
+  void *addr = realloc(ptr, size);
+  mlock(addr, size);
+  return addr;
+#else
+  return realloc(ptr, size);
+#endif
+}
+
+void silc_free(void *ptr)
+{
+  free(ptr);
+}
+
+
+
+
+
+
+
diff --git a/lib/silccore/silcmemory.h b/lib/silccore/silcmemory.h
new file mode 100644 (file)
index 0000000..cafba4f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+
+  silcmemory.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCMEMORY_H
+#define SILCMEMORY_H
+
+/* Prototypes */
+void *silc_malloc(size_t size);
+void *silc_calloc(size_t items, size_t size);
+void *silc_realloc(void *ptr, size_t size);
+void silc_free(void *ptr);
+
+#endif
+
+
+
+
+
+
diff --git a/lib/silccore/silcnet.c b/lib/silccore/silcnet.c
new file mode 100644 (file)
index 0000000..79aa3cc
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+
+  silcnet.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcnet.h"
+
+/* This function creates server or daemon or listener or what ever. This
+   does not fork a new process, it must be done by the caller if caller
+   wants to create a child process. This is used by the SILC server. 
+   If argument `ip_addr' is NULL `any' address will be used. Returns 
+   the created socket or -1 on error. */
+
+int silc_net_create_server(int port, char *ip_addr)
+{
+  int sock, rval;
+  struct sockaddr_in server;
+
+  SILC_LOG_DEBUG(("Creating a new server listener"));
+
+  /* Create the socket */
+  sock = socket(PF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+    return -1;
+  }
+
+  /* Set the socket options */
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+    return -1;
+  }
+
+  /* Set the socket information for bind() */
+  memset(&server, 0, sizeof(server));
+  server.sin_family = PF_INET;
+  server.sin_port = htons(port);
+
+  /* Convert IP address to network byte order */
+  if (ip_addr)
+    inet_aton(ip_addr, &server.sin_addr);
+  else
+    server.sin_addr.s_addr = INADDR_ANY;
+
+  /* Bind the server socket */
+  rval = bind(sock, (struct sockaddr *)&server, sizeof(server));
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno)));
+    return -1;
+  }
+
+  /* Specify that we are listenning */
+  rval = listen(sock, 5);
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
+    return -1;
+  }
+
+  /* Set the server socket to non-blocking mode */
+  silc_net_set_socket_nonblock(sock);
+
+  SILC_LOG_DEBUG(("Server listener created, fd=%d", sock));
+
+  return sock;
+}
+
+void silc_net_close_server(int sock)
+{
+  shutdown(sock, 2);
+  close(sock);
+
+  SILC_LOG_DEBUG(("Server socket closed"));
+}
+
+/* Creates a connection (TCP/IP) to a remote host. Returns the connection
+   socket or -1 on error. This blocks the process while trying to create
+   the connection. */
+
+int silc_net_create_connection(int port, char *host)
+{
+  int sock, rval;
+  struct hostent *dest;
+  struct sockaddr_in desthost;
+
+  SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port));
+
+  /* Do host lookup */
+  dest = gethostbyname(host);
+  if (!dest) {
+    SILC_LOG_ERROR(("Network (%s) unreachable", host));
+    return -1;
+  }
+
+  /* Set socket information */
+  memset(&desthost, 0, sizeof(desthost));
+  desthost.sin_port = htons(port);
+  memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
+
+  /* Create the connection socket */
+  sock = socket(PF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+    return -1;
+  }
+
+  /* Connect to the host */
+  rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
+  if (rval < 0) {
+    SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
+    shutdown(sock, 2);
+    close(sock);
+    return -1;
+  }
+
+  /* Set appropriate option */
+  silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+
+  SILC_LOG_DEBUG(("Connection created"));
+
+  return sock;
+}
+
+/* Creates a connection (TCP/IP) to a remote host. Returns the connection
+   socket or -1 on error. This creates non-blocking socket hence the
+   connection returns directly. To get the result of the connect() one
+   must select() the socket and read the result after it's ready. */
+
+int silc_net_create_connection_async(int port, char *host)
+{
+  int sock, rval;
+  struct hostent *dest;
+  struct sockaddr_in desthost;
+
+  SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d", 
+                 host, port));
+
+  /* Do host lookup */
+  dest = gethostbyname(host);
+  if (!dest) {
+    SILC_LOG_ERROR(("Network (%s) unreachable", host));
+    return -1;
+  }
+
+  /* Set socket information */
+  memset(&desthost, 0, sizeof(desthost));
+  desthost.sin_port = htons(port);
+  memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
+
+  /* Create the connection socket */
+  sock = socket(PF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
+    return -1;
+  }
+
+  /* Set the socket to non-blocking mode */
+  silc_net_set_socket_nonblock(sock);
+
+  /* Connect to the host */
+  rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
+  if (rval < 0) {
+    if (errno !=  EINPROGRESS) {
+      SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
+      shutdown(sock, 2);
+      close(sock);
+      return -1;
+    }
+  }
+
+  /* Set appropriate option */
+  silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+
+  SILC_LOG_DEBUG(("Connection operation in progress"));
+
+  return sock;
+}
+
+/* Closes the connection */
+
+void silc_net_close_connection(int sock)
+{
+  close(sock);
+}
+
+/* Accepts a connection from a particular socket */
+
+int silc_net_accept_connection(int sock)
+{
+  return accept(sock, 0, 0);
+}
+
+/* Set's the socket to non-blocking mode. */
+
+int silc_net_set_socket_nonblock(int sock)
+{
+  return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
+}
+
+/* Sets a option for a socket. */
+
+int silc_net_set_socket_opt(int sock, int level, int option, int on)
+{
+  return setsockopt(sock, level, option, (void *)&on, sizeof(on));
+}
+
+/* Checks whether IP address sent as argument is valid IP address. */
+
+int silc_net_is_ip(const char *addr)
+{
+  struct in_addr tmp;
+  return inet_aton(addr, &tmp);
+}
+
+/* Performs lookups for remote name and IP address. */
+
+void silc_net_check_host_by_sock(int sock, char **hostname, char **ip)
+{
+  struct sockaddr_in remote;
+  struct hostent *dest;
+  char *host_ip = NULL;
+  char host_name[1024];
+  int rval, len;
+  int i;
+
+  *hostname = NULL;
+  *ip = NULL;
+
+  SILC_LOG_DEBUG(("Resolving remote hostname and IP address"));
+
+  memset(&remote, 0, sizeof(remote));
+  len = sizeof(remote);
+  rval = getpeername(sock, (struct sockaddr *)&remote, &len);
+  if (rval < 0)
+    return;
+
+  /* Get host by address */
+  dest = gethostbyaddr((char *)&remote.sin_addr, 
+                      sizeof(struct in_addr), AF_INET);
+  if (!dest)
+    return;
+
+  /* Get same hsot by name to see that the remote host really is
+     the who it says it is */
+  memset(host_name, 0, sizeof(host_name));
+  memcpy(host_name, dest->h_name, strlen(dest->h_name));
+  dest = gethostbyname(host_name);
+  if (!dest)
+    return;
+
+  /* Find the address from list */
+  for (i = 0; dest->h_addr_list[i]; i++)
+    if (!memcmp(dest->h_addr_list[i], &remote.sin_addr, 
+              sizeof(struct in_addr)))
+      break;
+  if (!dest->h_addr_list[i])
+    return;
+
+  host_ip = inet_ntoa(remote.sin_addr);
+  if (!host_ip)
+    return;
+
+  *hostname = silc_calloc(strlen(host_name) + 1, sizeof(char));
+  memcpy(*hostname, host_name, strlen(host_name));
+  SILC_LOG_DEBUG(("Resolved hostname `%s'", *hostname));
+  *ip = silc_calloc(strlen(host_ip) + 1, sizeof(char));
+  memcpy(*ip, host_ip, strlen(host_ip));
+  SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
+}
diff --git a/lib/silccore/silcnet.h b/lib/silccore/silcnet.h
new file mode 100644 (file)
index 0000000..d6ef5c0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+
+  silcnet.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCNET_H
+#define SILCNET_H
+
+/* Prototypes */
+int silc_net_create_server(int port, char *ip_addr);
+void silc_net_close_server(int sock);
+int silc_net_create_connection(int port, char *host);
+int silc_net_create_connection_async(int port, char *host);
+void silc_net_close_connection(int sock);
+int silc_net_accept_connection(int sock);
+int silc_net_set_socket_nonblock(int sock);
+int silc_net_set_socket_opt(int sock, int level, int option, int on);
+int silc_net_is_ip(const char *addr);
+void silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
+
+#endif
diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c
new file mode 100644 (file)
index 0000000..d236463
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+
+  silcpacket.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Created: Fri Jul 25 18:52:14 1997
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Writes data from encrypted buffer to the socket connection. If the
+   data cannot be written at once, it will be written later with a timeout. 
+   The data is written from the data section of the buffer, not from head
+   or tail section. This automatically pulls the data section towards end
+   after writing the data. */
+
+int silc_packet_write(int sock, SilcBuffer src)
+{
+  int ret = 0;
+
+  SILC_LOG_DEBUG(("Writing data to socket %d", sock));
+
+  if (src->len > 0) {
+    ret = write(sock, src->data, src->len);
+    if (ret < 0) {
+      if (errno == EAGAIN) {
+       SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
+       return -2;
+      }
+      SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno)));
+      return -1;
+    }
+
+    silc_buffer_pull(src, ret);
+  }
+
+  SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
+
+  return ret;
+}
+
+/* Reads data from the socket connection into the incoming data buffer.
+   However, this does not parse the packet, it only reads some amount from
+   the network. If there are more data available that can be read at a time
+   the rest of the data will be read later with a timeout and only after
+   that the packet is ready to be parsed. 
+
+   The destination buffer sent as argument must be initialized before 
+   calling this function, and, the data section and the start of the tail
+   section must be same. Ie. we add the read data to the tail section of
+   the buffer hence the data section is the start of the buffer.
+
+   This returns amount of bytes read or -1 on error or -2 on case where
+   all of the data could not be read at once. */
+
+int silc_packet_read(int sock, SilcBuffer dest)
+{
+  int len = 0;
+  unsigned char buf[SILC_PACKET_READ_SIZE];
+
+  SILC_LOG_DEBUG(("Reading data from socket %d", sock));
+
+  /* Read the data from the socket. */
+  len = read(sock, buf, sizeof(buf));
+  if (len < 0) {
+    if (errno == EAGAIN) {
+      SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
+      return -2;
+    }
+    SILC_LOG_ERROR(("Cannot read from socket: %d", strerror(errno)));
+    return -1;
+  }
+
+  if (!len)
+    return 0;
+
+  /* Insert the data to the buffer. If the data doesn't fit to the 
+     buffer space is allocated for the buffer.  
+     XXX: I don't like this. -Pekka */
+  if (dest) {
+
+    /* If the data doesn't fit we just have to allocate a whole new 
+       data area */
+    if (dest->truelen <= len) {
+
+      /* Free the old buffer */
+      memset(dest->head, 'F', dest->truelen);
+      silc_free(dest->head);
+
+      /* Allocate new data area */
+      len += SILC_PACKET_DEFAULT_SIZE;
+      dest->data = silc_calloc(len, sizeof(char));
+      dest->truelen = len;
+      dest->len = 0;
+      dest->head = dest->data;
+      dest->data = dest->data;
+      dest->tail = dest->data;
+      dest->end = dest->data + dest->truelen;
+      len -= SILC_PACKET_DEFAULT_SIZE;
+    }
+
+    silc_buffer_put_tail(dest, buf, len);
+    silc_buffer_pull_tail(dest, len);
+  }
+
+  SILC_LOG_DEBUG(("Read %d bytes", len));
+
+  return len;
+}
+
+/* Encrypts a packet. */
+
+void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
+                        unsigned int len)
+{
+  SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", 
+                 cipher->cipher->name, len, len - 2));
+
+  /* Encrypt the data area of the packet. 3 bytes of the packet
+     are not encrypted. */
+  cipher->cipher->encrypt(cipher->context, buffer->data + 2, 
+                         buffer->data + 2, len - 2, cipher->iv);
+
+}
+
+/* Decrypts a packet. */
+
+void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer, 
+                        unsigned int len)
+{
+  SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)", 
+                 cipher->cipher->name, len, len - 2));
+
+  /* Decrypt the data area of the packet. 2 bytes of the packet
+     are not decrypted (they are not encrypted). */
+  cipher->cipher->decrypt(cipher->context, buffer->data + 2, 
+                         buffer->data + 2, len - 2, cipher->iv);
+
+}
+
+/* Parses the packet. This is called when a whole packet is ready to be
+   parsed. The buffer sent must be already decrypted before calling this 
+   function. The len argument must be the true length of the packet. This 
+   function returns the type of the packet. The data section of the 
+   buffer is parsed, not head or tail sections. */
+
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
+{
+  SilcBuffer buffer = ctx->buffer;
+  int len;
+
+  SILC_LOG_DEBUG(("Parsing incoming packet"));
+
+  /* Check the length of the buffer */
+  if (buffer->len < SILC_PACKET_MIN_LEN) {
+    SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
+    return SILC_PACKET_NONE;
+  }
+
+  /* Parse the buffer. This parses the SILC header of the packet. */
+  len = silc_buffer_unformat(buffer, 
+                            SILC_STR_UI_SHORT(&ctx->truelen),
+                            SILC_STR_UI_CHAR(&ctx->flags),
+                            SILC_STR_UI_CHAR(&ctx->type),
+                            SILC_STR_UI_SHORT(&ctx->src_id_len),
+                            SILC_STR_UI_SHORT(&ctx->dst_id_len),
+                            SILC_STR_UI_CHAR(&ctx->src_id_type),
+                            SILC_STR_END);
+
+  if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
+      ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+    SILC_LOG_ERROR(("Bad ID lengths in packet"));
+    return SILC_PACKET_NONE;
+  }
+
+  /* Calculate length of padding in packet */
+  ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+
+  silc_buffer_pull(buffer, len);
+  silc_buffer_unformat(buffer, 
+                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+                                                 ctx->src_id_len),
+                      SILC_STR_UI_CHAR(&ctx->dst_id_type),
+                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+                                                 ctx->dst_id_len),
+                      SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+                      SILC_STR_END);
+  silc_buffer_push(buffer, len);
+
+  SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
+                  ctx->buffer->data, ctx->buffer->len);
+
+  /* Pull SILC header and padding from packet */
+  silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
+                  ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+  SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
+
+  return ctx->type;
+}
+
+/* Perform special SILC Packet header parsing. This is required to some
+   packet types that have the data payload encrypted with different key
+   than the header area plus padding of the packet. Hence, this parses
+   the header in a way that it does not take the data area into account
+   and parses the header and padding area only. */
+
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
+{
+  SilcBuffer buffer = ctx->buffer;
+  int len, tmplen;
+
+  SILC_LOG_DEBUG(("Parsing incoming packet"));
+
+  /* Check the length of the buffer */
+  if (buffer->len < SILC_PACKET_MIN_LEN) {
+    SILC_LOG_ERROR(("Bad packet length: %d, packet dropped", buffer->len));
+    return SILC_PACKET_NONE;
+  }
+
+  /* Parse the buffer. This parses the SILC header of the packet. */
+  len = silc_buffer_unformat(buffer, 
+                            SILC_STR_UI_SHORT(&ctx->truelen),
+                            SILC_STR_UI_CHAR(&ctx->flags),
+                            SILC_STR_UI_CHAR(&ctx->type),
+                            SILC_STR_UI_SHORT(&ctx->src_id_len),
+                            SILC_STR_UI_SHORT(&ctx->dst_id_len),
+                            SILC_STR_UI_CHAR(&ctx->src_id_type),
+                            SILC_STR_END);
+
+  if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
+      ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+    SILC_LOG_ERROR(("Bad ID lengths in packet"));
+    return SILC_PACKET_NONE;
+  }
+
+  /* Calculate length of padding in packet. As this is special packet
+     the data area is not used in the padding calculation as it won't
+     be decrypted by the caller. */
+  tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len;
+  ctx->padlen = SILC_PACKET_PADLEN(tmplen);
+
+  silc_buffer_pull(buffer, len);
+  silc_buffer_unformat(buffer, 
+                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+                                                 ctx->src_id_len),
+                      SILC_STR_UI_CHAR(&ctx->dst_id_type),
+                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+                                                 ctx->dst_id_len),
+                      SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+                      SILC_STR_END);
+  silc_buffer_push(buffer, len);
+
+  SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
+                  ctx->buffer->data, ctx->buffer->len);
+
+  /* Pull SILC header and padding from packet */
+  silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
+                  ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+  SILC_LOG_DEBUG(("Incoming packet type: %d", ctx->type));
+
+  return ctx->type;
+}
+
+/* Assembles a new packet to be ready for send out. The buffer sent as
+   argument must include the data to be sent and it must not be encrypted. 
+   The packet also must have enough free space so that the SILC header
+   and padding maybe added to the packet. The packet is encrypted after 
+   this function has returned.
+
+   The buffer sent as argument should be something like following:
+
+   --------------------------------------------
+   | head             | data           | tail |
+   --------------------------------------------
+   ^                  ^
+   58 bytes           x bytes
+
+   So that the SILC header and 1 - 16 bytes of padding can fit to
+   the buffer. After assembly the buffer might look like this:
+
+   --------------------------------------------
+   | data                              |      |
+   --------------------------------------------
+   ^                                   ^
+   Start of assembled packet
+
+   Packet construct is as follows (* = won't be encrypted):
+
+   x bytes       SILC Header
+      2 bytes     Payload length  (*)
+      1 byte      Flags           (*)
+      1 byte      Packet type
+      1 byte      Source ID Type
+      2 bytes     Source ID Length
+      x bytes     Source ID
+      1 byte      Destination ID Type
+      2 bytes     Destination ID Length
+      x bytes     Destination ID
+
+   1 - 16 bytes    Padding
+
+   x bytes        Data payload
+
+   All fields in the packet will be authenticated by MAC. The MAC is
+   not computed here, it must be computed differently before encrypting
+   the packet.
+
+*/
+
+void silc_packet_assemble(SilcPacketContext *ctx)
+{
+  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
+  int i;
+
+  SILC_LOG_DEBUG(("Assembling outgoing packet"));
+  
+  /* Get the true length of the packet. This is saved as payload length
+     into the packet header. This does not include the length of the
+     padding. */
+  if (!ctx->truelen)
+    ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
+      ctx->src_id_len + ctx->dst_id_len;
+
+  /* Calculate the length of the padding. The padding is calculated from
+     the data that will be encrypted. As protocol states 3 first bytes
+     of the packet are not encrypted they are not included in the
+     padding calculation. */
+  if (!ctx->padlen)
+    ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+
+  /* Put the start of the data section to the right place. */
+  silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
+                  ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+  /* Get random padding */
+#if 1
+  for (i = 0; i < ctx->padlen; i++)
+    tmppad[i] = silc_rng_get_byte(ctx->rng);
+#else
+  /* XXX: For testing - to be removed */
+  memset(tmppad, 65, sizeof(tmppad));
+#endif
+
+  /* Create the packet. This creates the SILC header and adds padding,
+     rest of the buffer remains as it is. */
+  silc_buffer_format(ctx->buffer, 
+                    SILC_STR_UI_SHORT(ctx->truelen),
+                    SILC_STR_UI_CHAR(ctx->flags),
+                    SILC_STR_UI_CHAR(ctx->type),
+                    SILC_STR_UI_SHORT(ctx->src_id_len),
+                    SILC_STR_UI_SHORT(ctx->dst_id_len),
+                    SILC_STR_UI_CHAR(ctx->src_id_type),
+                    SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
+                    SILC_STR_UI_CHAR(ctx->dst_id_type),
+                    SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
+                    SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
+                    SILC_STR_END);
+
+  SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
+                  ctx->buffer->data, ctx->buffer->len);
+
+  SILC_LOG_DEBUG(("Outgoing packet assembled"));
+}
diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h
new file mode 100644 (file)
index 0000000..a264479
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+
+  silcpacket.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPACKET_H
+#define SILCPACKET_H
+
+/* Amount of bytes to be read from the socket connection at once. */
+#define SILC_PACKET_READ_SIZE 16384
+
+/* Default byte size of the packet. This can be set larger if this
+   is not enough, we shall see. */
+#define SILC_PACKET_DEFAULT_SIZE 2048
+
+/* Header length without source and destination ID's. */
+#define SILC_PACKET_HEADER_LEN 8 + 2
+
+/* Minimum length of SILC Packet Header. This much is decrypted always
+   when packet is received to be able to get all the relevant data out
+   from the header. */
+#define SILC_PACKET_MIN_HEADER_LEN 16 + 2
+
+/* Maximum padding length */
+#define SILC_PACKET_MAX_PADLEN 16
+
+/* Minimum packet length */
+#define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
+
+/* Maximum length of ID */
+#define SILC_PACKET_MAX_ID_LEN 16
+
+/* SILC packet type definition. For now, it is defined like this and I don't 
+   expect it to change in any near future. If one byte as a packet type is 
+   not enough we can, then, think something else. */
+typedef unsigned char SilcPacketType;
+
+/* SILC packet version type definition. */
+typedef unsigned char SilcPacketVersion;
+
+/* SILC packet flags type definition. */
+typedef unsigned char SilcPacketFlags;
+
+/* All defined packet flags */
+#define SILC_PACKET_FLAG_NONE             0x00
+#define SILC_PACKET_FLAG_PRIVMSG_KEY      0x01
+#define SILC_PACKET_FLAG_FORWARDED        0x02 /* XXX deprecated 26062000 */
+#define SILC_PACKET_FLAG_BROADCAST        0x04
+/* Rest of flags still available
+#define SILC_PACKET_FLAG_XXX              0x08
+#define SILC_PACKET_FLAG_XXX              0x10
+#define SILC_PACKET_FLAG_XXX              0x20
+#define SILC_PACKET_FLAG_XXX              0x40
+#define SILC_PACKET_FLAG_XXX              0x80
+*/
+
+/* 
+   SILC packet context. 
+
+   In packet sending this is filled and sent to silc_packet_assemble 
+   which then uses it to assemble new packet. In packet reception pointer 
+   to this context is sent to silc_packet_parse which parses the packet 
+   and returns the relevant information to this structure. On packet 
+   reception returned ID's are always the hash values of the ID's from 
+   the packet. 
+
+   Short description of the fields following:
+
+   SilcBuffer buffer
+
+       The data buffer.
+
+   SilcPacketType type
+
+       Type of the packet. Types are defined below.
+
+   SilcPacketFlags flags
+
+       Packet flags. Flags are defined above.
+
+   unsigned char *src_id
+   unsigned int src_id_len
+   SilcIdType src_id_type
+
+       Source ID, its length and type. On packet reception retuned ID's
+       are always the hash values of the ID's from the packet.
+
+   SilcHash hash
+
+       Pointer to allocated hash object. This must be MD5 hash object.
+       This is used to calculate checksum of the packet.
+
+*/
+typedef struct {
+  SilcBuffer buffer;
+  SilcPacketType type;
+  SilcPacketFlags flags;
+
+  unsigned char *src_id;
+  unsigned int src_id_len;
+  SilcIdType src_id_type;
+
+  unsigned char *dst_id;
+  unsigned int dst_id_len;
+  SilcIdType dst_id_type;
+
+  unsigned int truelen;
+  unsigned int padlen;
+
+  /* For padding generation */
+  SilcRng rng;
+} SilcPacketContext;
+
+/* SILC Packet types. */
+#define SILC_PACKET_NONE                0       /* NULL, never sent */
+#define SILC_PACKET_DISCONNECT          1       /* Disconnection */
+#define SILC_PACKET_SUCCESS             2       /* Success */
+#define SILC_PACKET_FAILURE             3       /* Failure */
+#define SILC_PACKET_REJECT              4       /* Rejected */
+#define SILC_PACKET_NOTIFY               5       /* Notify message */
+#define SILC_PACKET_ERROR                6       /* Error message */
+#define SILC_PACKET_CHANNEL_MESSAGE     7       /* Message for channel */
+#define SILC_PACKET_CHANNEL_KEY          8       /* Key of the channel */
+#define SILC_PACKET_PRIVATE_MESSAGE      9       /* Private message */
+#define SILC_PACKET_PRIVATE_MESSAGE_KEY  10      /* Private message key*/
+#define SILC_PACKET_COMMAND              11      /* Command */
+#define SILC_PACKET_COMMAND_REPLY        12      /* Reply to a command */
+#define SILC_PACKET_KEY_EXCHANGE         13      /* Start of KE */
+#define SILC_PACKET_KEY_EXCHANGE_1       14      /* KE1 */
+#define SILC_PACKET_KEY_EXCHANGE_2       15      /* KE2 */
+#define SILC_PACKET_CONNECTION_AUTH_REQUEST 16   /* Request of auth meth */
+#define SILC_PACKET_CONNECTION_AUTH      17      /* Connectinon auth */
+#define SILC_PACKET_NEW_ID               18      /* Sending new ID */
+#define SILC_PACKET_NEW_ID_LIST          19      /* Sending list of them */
+#define SILC_PACKET_NEW_CLIENT           20      /* Registering client */
+#define SILC_PACKET_NEW_SERVER           21      /* Registering server */
+#define SILC_PACKET_NEW_CHANNEL          22      /* Registering channel */
+#define SILC_PACKET_NEW_CHANNEL_USER     23      /*   "" user on channel */
+#define SILC_PACKET_NEW_CHANNEL_LIST     24      /* List of new channels */
+#define SILC_PACKET_NEW_CHANNEL_USER_LIST 25     /* List of users on "" */
+#define SILC_PACKET_REPLACE_ID           26      /* To replace old ID */
+#define SILC_PACKET_REMOVE_ID            27      /* To remove ID */
+/* #define SILC_PACKET_MAX               255 */
+
+/* Macros */
+
+/* Returns true length of the packet and padded length of the packet */
+#define SILC_PACKET_LENGTH(__packet, __ret_truelen, __ret_padlen)           \
+do {                                                                        \
+  SILC_GET16_MSB((__ret_truelen), (__packet)->data);                        \
+  (__ret_padlen) = (((__ret_truelen) - 2) +                                 \
+                   SILC_PACKET_MAX_PADLEN) & ~(SILC_PACKET_MAX_PADLEN - 1); \
+} while(0)
+
+/* Returns pad length of the packet */
+#define SILC_PACKET_PADLEN(__packetlen)                                         \
+  SILC_PACKET_MAX_PADLEN - ((__packetlen) - 2) % SILC_PACKET_MAX_PADLEN;
+
+/* Prototypes */
+int silc_packet_write(int sock, SilcBuffer src);
+int silc_packet_read(int sock, SilcBuffer dest);
+void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
+                        unsigned int len);
+void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer, 
+                        unsigned int len);
+SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
+SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
+void silc_packet_assemble(SilcPacketContext *ctx);
+
+#endif
diff --git a/lib/silccore/silcprotocol.c b/lib/silccore/silcprotocol.c
new file mode 100644 (file)
index 0000000..56a0891
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+
+  silcprotocol.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Created: Tue Nov 25 19:25:33 GMT+0200 1997
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "silcprotocol.h"
+
+/* Allocates a new protocol object. The new allocated and initialized 
+   protocol is returned to the new_protocol argument. The argument context
+   is the context to be sent as argument for the protocol. The callback
+   argument is the function to be called _after_ the protocol has finished. */
+
+void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
+                        void *context, SilcProtocolFinalCallback callback)
+{
+  int i;
+
+  SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
+
+  for (i = 0; silc_protocol_list[i].callback; i++)
+    if (silc_protocol_list[i].type == type)
+      break;
+
+  if (!silc_protocol_list[i].callback) {
+    SILC_LOG_ERROR(("Requested protocol does not exists"));
+    return;
+  }
+
+  *new_protocol = silc_calloc(1, sizeof(**new_protocol));
+  if (*new_protocol == NULL) {
+    SILC_LOG_ERROR(("Cannot allocate new protocol object"));
+    return;
+  }
+
+  (*new_protocol)->protocol = (SilcProtocolObject *)&silc_protocol_list[i];
+  (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
+  (*new_protocol)->context = context;
+  (*new_protocol)->execute = silc_protocol_execute;
+  (*new_protocol)->execute_final = silc_protocol_execute_final;
+  (*new_protocol)->final_callback = callback;
+}
+
+/* Free's a protocol object. */
+
+void silc_protocol_free(SilcProtocol protocol)
+{
+  if (protocol)
+    silc_free(protocol);
+}
+
+/* Executes next state of the protocol. The state must be set before
+   calling this function. */
+
+void silc_protocol_execute(void *qptr, int type,
+                          void *context, int fd,
+                          long secs, long usecs)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (secs + usecs) 
+    silc_task_register(qptr, fd, protocol->protocol->callback, context, 
+                      secs, usecs, 
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_NORMAL);
+  else
+    protocol->protocol->callback(qptr, 0, context, fd);
+}
+
+/* Executes the final callback of the protocol. */
+
+void silc_protocol_execute_final(void *qptr, int type,
+                                void *context, int fd)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SILC_LOG_DEBUG(("Start, state=%d", protocol->state));
+
+  protocol->final_callback(qptr, 0, context, fd);
+}
diff --git a/lib/silccore/silcprotocol.h b/lib/silccore/silcprotocol.h
new file mode 100644 (file)
index 0000000..f04ffd7
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+
+  silcprotocol.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPROTOCOL_H
+#define SILCPROTOCOL_H
+
+/* Protocol type definition. */
+typedef unsigned char SilcProtocolType;
+
+/* Protocol state definition. */
+typedef unsigned char SilcProtocolState;
+
+/* Protocol states. Do NOT change the values of these states, especially
+   the START state or you break every protocol. */
+#define SILC_PROTOCOL_STATE_UNKNOWN 0
+#define SILC_PROTOCOL_STATE_START 1
+#define SILC_PROTOCOL_STATE_END 253
+#define SILC_PROTOCOL_STATE_ERROR 254
+
+/* Connection Authentication protocols' authentication methods */
+#define SILC_PROTOCOL_CONN_AUTH_NONE 0
+#define SILC_PROTOCOL_CONN_AUTH_PASSWORD 1
+#define SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY 2
+
+/* 
+   SILC Protocol Object.
+
+   Short description of the field following:
+   
+   SilcProtocolType type
+
+       Protocol type. This is enumeration.
+  
+   SilcProtocolCallback callback;
+
+       Callback function for the protocol. This is SilcTaskCallback function
+       pointer as the protocols in SILC are executed as timeout tasks.
+
+   The object expands to another structure as well. Short description of 
+   these fields following:
+
+   SilcProtocolObject *protocol
+
+       This is the pointer to the protocol object defined above.
+
+   SilcProtocolState state
+
+       Protocol state. This is enumeration. The state of the protocol can
+       be changed in the callback function.
+
+   void *context
+
+       Context to be sent for the callback function. This is usually 
+       object for either SILC client or server. However, this abstraction 
+       makes it possible that this pointer could be some other object as well. 
+
+   SilcProtocolExecute execute;
+
+       Executes the protocol and its states. The correct state must be set
+       before calling this function. The state is usually set in the protocol
+       specific routines.
+
+   SilcProtocolExecute execute_final;
+
+       Executes the final callback function of the protocol. Read on.
+
+   SilcProtocolFinalCallback final_callback;
+
+       This is a callback function that is called with timeout _after_ the
+       protocol has finished or error occurs. If this is NULL, naturally 
+       nothing will be executed. Protocol should call this function only at 
+       SILC_PROTOCOL_STATE_END and SILC_PROTOCOL_STATE_ERROR states.
+
+*/
+typedef SilcTaskCallback SilcProtocolCallback;
+
+typedef struct {
+  SilcProtocolType type;
+  SilcProtocolCallback callback;
+} SilcProtocolObject;
+
+typedef SilcTaskCallback SilcProtocolFinalCallback;
+typedef SilcTaskCallback SilcProtocolExecute;
+
+typedef struct SilcProtocolObjectStruct {
+  SilcProtocolObject *protocol;
+  SilcProtocolState state;
+  void *context;
+
+  //  SilcProtocolExecute execute;
+  void (*execute)(void *, int, void *, int, long, long);
+  SilcProtocolExecute execute_final;
+  SilcProtocolFinalCallback final_callback;
+} *SilcProtocol;
+
+/* Definition for SILC protocol list. This list includes all the
+   protocols in the SILC. SILC server and client defined own list of
+   protocols. */
+extern const SilcProtocolObject silc_protocol_list[];
+
+/* Prototypes */
+void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
+                        void *context, SilcProtocolFinalCallback callback);
+void silc_protocol_free(SilcProtocol protocol);
+void silc_protocol_execute(void *qptr, int type,
+                          void *context, int fd,
+                          long secs, long usecs);
+void silc_protocol_execute_final(void *qptr, int type, 
+                                void *context, int fd);
+
+#endif
diff --git a/lib/silccore/silcschedule.c b/lib/silccore/silcschedule.c
new file mode 100644 (file)
index 0000000..5ae44e6
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+
+  silcschedule.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1998 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* The actual schedule object. */
+static SilcSchedule schedule;
+
+/* Initializes the schedule. Sets the non-timeout task queue hook and
+   the timeout task queue hook. This must be called before the schedule
+   is able to work. */
+
+void silc_schedule_init(SilcTaskQueue fd_queue,
+                       SilcTaskQueue timeout_queue,
+                       SilcTaskQueue generic_queue,
+                       int max_fd)
+{
+  int i;
+
+  SILC_LOG_DEBUG(("Initializing scheduler"));
+
+  /* Initialize the schedule */
+  memset(&schedule, 0, sizeof(schedule));
+  schedule.fd_queue = fd_queue;
+  schedule.timeout_queue = timeout_queue;
+  schedule.generic_queue = generic_queue;
+  schedule.fd_list.fd = silc_calloc(max_fd, sizeof(int));
+  schedule.fd_list.last_fd = 0;
+  schedule.fd_list.max_fd = max_fd;
+  schedule.timeout = NULL;
+  schedule.valid = TRUE;
+  FD_ZERO(&schedule.in);
+  FD_ZERO(&schedule.out);
+  schedule.max_fd = -1;
+  for (i = 0; i < max_fd; i++)
+    schedule.fd_list.fd[i] = -1;
+}
+
+/* Uninitializes the schedule. This is called when the program is ready
+   to end. This removes all tasks and task queues. */
+
+int silc_schedule_uninit()
+{
+
+  SILC_LOG_DEBUG(("Uninitializing scheduler"));
+
+  if (schedule.valid == TRUE)
+    return FALSE;
+
+  /* Unregister all tasks */
+  if (schedule.fd_queue)
+    silc_task_remove(schedule.fd_queue, SILC_ALL_TASKS);
+  if (schedule.timeout_queue)
+    silc_task_remove(schedule.timeout_queue, SILC_ALL_TASKS);
+  if (schedule.generic_queue)
+    silc_task_remove(schedule.generic_queue, SILC_ALL_TASKS);
+
+  /* Unregister all task queues */
+  if (schedule.fd_queue)
+    silc_task_queue_free(schedule.fd_queue);
+  if (schedule.timeout_queue)
+    silc_task_queue_free(schedule.timeout_queue);
+  if (schedule.generic_queue)
+    silc_task_queue_free(schedule.generic_queue);
+
+  /* Clear the fd list */
+  if (schedule.fd_list.fd) {
+    memset(schedule.fd_list.fd, -1, schedule.fd_list.max_fd);
+    silc_free(schedule.fd_list.fd);
+  }
+
+  memset(&schedule, 'F', sizeof(schedule));
+  return TRUE;
+}
+
+/* Stops the schedule even if it is not supposed to be stopped yet. 
+   After calling this, one should call silc_schedule_uninit (after the 
+   silc_schedule has returned). */
+
+void silc_schedule_stop()
+{
+  SILC_LOG_DEBUG(("Stopping scheduler"));
+
+  if (schedule.valid == TRUE)
+    schedule.valid = FALSE;
+}
+
+/* Sets a file descriptor to be listened by select() in scheduler. One can
+   call this directly if wanted. This can be called multiple times for
+   one file descriptor to set different iomasks. */
+
+void silc_schedule_set_listen_fd(int fd, unsigned int iomask)
+{
+  assert(schedule.valid != FALSE);
+  assert(fd < schedule.fd_list.max_fd);
+
+  schedule.fd_list.fd[fd] = iomask;
+  
+  if (fd > schedule.fd_list.last_fd)
+    schedule.fd_list.last_fd = fd;
+}
+
+/* Removes a file descriptor from listen list. */
+
+void silc_schedule_unset_listen_fd(int fd)
+{
+  assert(schedule.valid != FALSE);
+  assert(fd < schedule.fd_list.max_fd);
+
+  schedule.fd_list.fd[fd] = -1;
+  
+  if (fd == schedule.fd_list.last_fd) {
+    int i;
+
+    for (i = fd; i >= 0; i--)
+      if (schedule.fd_list.fd[i] != -1)
+       break;
+
+    schedule.fd_list.last_fd = i;
+  }
+}
+
+/* Executes tasks matching the file descriptor set by select(). The task
+   remains on the task queue after execution. Invalid tasks are removed 
+   here from the task queue. This macro is used by silc_schedule function. 
+   We don't have to care about the tasks priority here because the tasks
+   are sorted in their priority order already at the registration phase. */
+
+#define SILC_SCHEDULE_RUN_TASKS                                                   \
+do {                                                                      \
+  queue = schedule.fd_queue;                                              \
+  if (queue && queue->valid == TRUE && queue->task) {                     \
+    task = queue->task;                                                           \
+                                                                          \
+    /* Walk thorugh all tasks in the particular task queue and            \
+       execute the callback functions of those tasks matching the         \
+       fd set by select(). */                                             \
+    while(1) {                                                            \
+      /* Validity of the task is checked always before and after          \
+        execution beacuse the task might have been unregistered           \
+        in the callback function, ie. it is not valid anymore. */         \
+                                                                          \
+      if (task->valid) {                                                  \
+       /* Task ready for reading */                                       \
+       if ((FD_ISSET(task->fd, &schedule.in)) &&                          \
+           (task->iomask & (1L << SILC_TASK_READ))) {                     \
+         task->callback(queue, SILC_TASK_READ, task->context, task->fd);  \
+          is_run = TRUE;                                                  \
+       }                                                                  \
+      }                                                                   \
+                                                                          \
+      if (task->valid) {                                                  \
+       /* Task ready for writing */                                       \
+       if ((FD_ISSET(task->fd, &schedule.out)) &&                         \
+           (task->iomask & (1L << SILC_TASK_WRITE))) {                    \
+         task->callback(queue, SILC_TASK_WRITE, task->context, task->fd); \
+          is_run = TRUE;                                                  \
+       }                                                                  \
+      }                                                                           \
+                                                                          \
+      if (!task->valid) {                                                 \
+       /* Invalid (unregistered) tasks are removed from the               \
+          task queue. */                                                  \
+       if (queue->task == task->next) {                                   \
+         silc_task_remove(queue, task);                                   \
+          break;                                                          \
+        }                                                                 \
+                                                                          \
+        task = task->next;                                                \
+        silc_task_remove(queue, task->prev);                              \
+        continue;                                                         \
+      }                                                                           \
+                                                                          \
+      /* Break if there isn't more tasks in the queue */                  \
+      if (queue->task == task->next)                                      \
+        break;                                                            \
+                                                                          \
+      task = task->next;                                                  \
+    }                                                                     \
+  }                                                                       \
+} while(0)
+
+/* Selects tasks to be listened by select(). These are the non-timeout
+   tasks. This checks the scheduler's fd list. This macro is used by 
+   silc_schedule function. */
+
+#define SILC_SCHEDULE_SELECT_TASKS                             \
+do {                                                           \
+  for (i = 0; i <= schedule.fd_list.last_fd; i++) {            \
+    if (schedule.fd_list.fd[i] != -1) {                                \
+                                                               \
+      /* Set the max fd value for select() to listen */                \
+      if (i > schedule.max_fd)                                 \
+       schedule.max_fd = i;                                    \
+                                                               \
+      /* Add tasks for reading */                              \
+      if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_READ)))   \
+       FD_SET(i, &schedule.in);                                \
+                                                               \
+      /* Add tasks for writing */                              \
+      if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_WRITE)))  \
+       FD_SET(i, &schedule.out);                               \
+    }                                                          \
+  }                                                             \
+} while(0)
+
+/* Executes all tasks whose timeout has expired. The task is removed from
+   the task queue after the callback function has returned. Also, invalid
+   tasks are removed here. The current time must be get before calling this
+   macro. This macro is used by silc_schedule function. We don't have to
+   care about priorities because tasks are already sorted in their priority
+   order at the registration phase. */
+
+#define SILC_SCHEDULE_RUN_TIMEOUT_TASKS                                        \
+do {                                                                   \
+  queue = schedule.timeout_queue;                                      \
+  if (queue && queue->valid == TRUE && queue->task) {                  \
+    task = queue->task;                                                        \
+                                                                       \
+    /* Walk thorugh all tasks in the particular task queue             \
+       and run all the expired tasks. */                               \
+    while(1) {                                                         \
+      /* Execute the task if the timeout has expired */                        \
+      if (silc_task_timeout_compare(&task->timeout, &curtime)) {       \
+                                                                       \
+        /* Task ready for reading */                                   \
+        if (task->valid) {                                             \
+          if ((task->iomask & (1L << SILC_TASK_READ)))                 \
+           task->callback(queue, SILC_TASK_READ,                       \
+                          task->context, task->fd);                    \
+       }                                                               \
+                                                                       \
+        /* Task ready for writing */                                   \
+        if (task->valid) {                                             \
+          if ((task->iomask & (1L << SILC_TASK_WRITE)))                        \
+            task->callback(queue, SILC_TASK_WRITE,                     \
+                          task->context, task->fd);                    \
+        }                                                              \
+                                                                       \
+        /* Break if there isn't more tasks in the queue */             \
+       if (queue->task == task->next) {                                \
+         /* Remove the task from queue */                              \
+         silc_task_remove(queue, task);                                \
+         break;                                                        \
+        }                                                              \
+                                                                       \
+        task = task->next;                                             \
+                                                                       \
+        /* Remove the task from queue */                               \
+        silc_task_remove(queue, task->prev);                           \
+      } else {                                                         \
+        /* The timeout hasn't expired, check for next one */           \
+                                                                       \
+        /* Break if there isn't more tasks in the queue */             \
+        if (queue->task == task->next)                                 \
+          break;                                                       \
+                                                                       \
+        task = task->next;                                             \
+      }                                                                        \
+    }                                                                  \
+  }                                                                    \
+} while(0)
+
+/* Calculates next timeout for select(). This is the timeout value
+   when at earliest some of the timeout tasks expire. If this is in the
+   past, they will be run now. This macro is used by the silc_schedule
+   function. */
+
+#define SILC_SCHEDULE_SELECT_TIMEOUT                                       \
+do {                                                                       \
+  if (schedule.timeout_queue && schedule.timeout_queue->valid == TRUE) {    \
+    queue = schedule.timeout_queue;                                        \
+    task = NULL;                                                           \
+                                                                           \
+    /* Get the current time */                                             \
+    gettimeofday(&curtime, NULL);                                          \
+    schedule.timeout = NULL;                                               \
+                                                                           \
+    /* First task in the task queue has always the smallest timeout. */            \
+    task = queue->task;                                                            \
+    while(1) {                                                             \
+      if (task && task->valid == TRUE) {                                   \
+                                                                           \
+       /* If the timeout is in past, we will run the task and all other    \
+          timeout tasks from the past. */                                  \
+       if (silc_task_timeout_compare(&task->timeout, &curtime)) {          \
+         SILC_SCHEDULE_RUN_TIMEOUT_TASKS;                                  \
+                                                                           \
+         /* The task(s) has expired and doesn't exist on the task queue    \
+            anymore. We continue with new timeout. */                      \
+          queue = schedule.timeout_queue;                                  \
+          task = queue->task;                                              \
+          if (task == NULL || task->valid == FALSE)                        \
+            break;                                                         \
+         goto cont;                                                        \
+        } else {                                                           \
+ cont:                                                                     \
+          /* Calculate the next timeout for select() */                            \
+          queue->timeout.tv_sec = task->timeout.tv_sec - curtime.tv_sec;    \
+          queue->timeout.tv_usec = task->timeout.tv_usec - curtime.tv_usec; \
+                                                                           \
+          /* We wouldn't want to go under zero, check for it. */           \
+          if (queue->timeout.tv_usec < 0) {                                \
+            queue->timeout.tv_sec -= 1;                                            \
+            queue->timeout.tv_usec += 1000000L;                                    \
+          }                                                                \
+        }                                                                  \
+        /* We've got the timeout value */                                  \
+       break;                                                              \
+      }        else {                                                              \
+        /* Task is not valid, remove it and try next one. */               \
+       silc_task_remove(queue, task);                                      \
+        task = queue->task;                                                \
+        if (queue->task == NULL)                                           \
+          break;                                                           \
+      }                                                                            \
+    }                                                                      \
+    /* Save the timeout */                                                 \
+    if (task)                                                              \
+      schedule.timeout = &queue->timeout;                                  \
+  }                                                                        \
+} while(0)
+
+/* Execute generic tasks. These are executed only and only if for the
+   specific fd there wasn't other non-timeout tasks. This checks the earlier
+   set fd list, thus the generic tasks apply to all specified fd's. All the
+   generic tasks are executed at once. */
+
+#define SILC_SCHEDULE_RUN_GENERIC_TASKS                                             \
+do {                                                                        \
+  if (is_run == FALSE) {                                                    \
+    SILC_LOG_DEBUG(("Running generic tasks"));                              \
+    for (i = 0; i <= schedule.fd_list.last_fd; i++)                         \
+      if (schedule.fd_list.fd[i] != -1) {                                   \
+                                                                            \
+       /* Check whether this fd is select()ed. */                           \
+       if ((FD_ISSET(i, &schedule.in)) || (FD_ISSET(i, &schedule.out))) {   \
+                                                                            \
+         /* It was selected. Now find the tasks from task queue and execute \
+            all generic tasks. */                                           \
+         if (schedule.generic_queue && schedule.generic_queue->valid) {     \
+           queue = schedule.generic_queue;                                  \
+                                                                            \
+           if (!queue->task)                                                \
+             break;                                                         \
+                                                                            \
+           task = queue->task;                                              \
+                                                                            \
+           while(1) {                                                       \
+             /* Validity of the task is checked always before and after     \
+                execution beacuse the task might have been unregistered     \
+                in the callback function, ie. it is not valid anymore. */   \
+                                                                            \
+             if (task->valid && schedule.fd_list.fd[i] != -1) {             \
+               /* Task ready for reading */                                 \
+               if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_READ)))       \
+                 task->callback(queue, SILC_TASK_READ,                      \
+                                task->context, i);                          \
+             }                                                              \
+                                                                            \
+             if (task->valid && schedule.fd_list.fd[i] != -1) {             \
+               /* Task ready for writing */                                 \
+               if ((schedule.fd_list.fd[i] & (1L << SILC_TASK_WRITE)))      \
+                 task->callback(queue, SILC_TASK_WRITE,                     \
+                                task->context, i);                          \
+             }                                                              \
+                                                                            \
+             if (!task->valid) {                                            \
+               /* Invalid (unregistered) tasks are removed from the         \
+                  task queue. */                                            \
+               if (queue->task == task->next) {                             \
+                 silc_task_remove(queue, task);                             \
+                 break;                                                     \
+               }                                                            \
+                                                                            \
+               task = task->next;                                           \
+               silc_task_remove(queue, task->prev);                         \
+               continue;                                                    \
+             }                                                              \
+                                                                            \
+             /* Break if there isn't more tasks in the queue */             \
+             if (queue->task == task->next)                                 \
+               break;                                                       \
+                                                                            \
+             task = task->next;                                             \
+           }                                                                \
+         }                                                                  \
+       }                                                                    \
+      }                                                                             \
+  }                                                                         \
+} while(0)
+
+/* The SILC scheduler. This is actually the main routine in SILC programs.
+   When this returns the program is to be ended. Before this function can
+   be called, one must call silc_schedule_init function. */
+
+void silc_schedule()
+{
+  int is_run, i;
+  SilcTask task;
+  SilcTaskQueue queue;
+  struct timeval curtime;
+
+  SILC_LOG_DEBUG(("Running scheduler"));
+
+  if (schedule.valid == FALSE) {
+    SILC_LOG_ERROR(("Scheduler is not valid, stopping"));
+    return;
+  }
+
+  /* Start the scheduler loop */
+  while(1) {
+
+    SILC_LOG_DEBUG(("In scheduler loop"));
+
+    /* If the task queues aren't initialized or we aren't valid anymore
+       we will return */
+    if ((!schedule.fd_queue && !schedule.timeout_queue 
+        && !schedule.generic_queue) || schedule.valid == FALSE) {
+      SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+      break;
+    }
+
+    /* Clear everything */
+    FD_ZERO(&schedule.in);
+    FD_ZERO(&schedule.out);
+    schedule.max_fd = -1;
+    is_run = FALSE;
+
+    /* Calculate next timeout for select(). This is the timeout value
+       when at earliest some of the timeout tasks expire. */
+    SILC_SCHEDULE_SELECT_TIMEOUT;
+
+    /* Add the file descriptors to the fd sets. These are the non-timeout
+       tasks. The select() listens to these file descriptors. */
+    SILC_SCHEDULE_SELECT_TASKS;
+
+    if (schedule.max_fd == -1) {
+      SILC_LOG_ERROR(("Nothing to listen, exiting"));
+      break;
+    }
+
+    if (schedule.timeout)
+      SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule.timeout->tv_sec,
+                     schedule.timeout->tv_usec));
+
+    /* This is the main select(). The program blocks here until some
+       of the selected file descriptors change status or the selected
+       timeout expires. */
+    SILC_LOG_DEBUG(("Select"));
+    switch(select(schedule.max_fd + 1, &schedule.in, 
+                 &schedule.out, 0, schedule.timeout)) {
+    case -1:
+      /* Error */
+      SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
+      break;
+    case 0:
+      /* Timeout */
+      SILC_LOG_DEBUG(("Running timeout tasks"));
+      gettimeofday(&curtime, NULL);
+      SILC_SCHEDULE_RUN_TIMEOUT_TASKS;
+      break;
+    default:
+      /* There is some data available now */
+      SILC_LOG_DEBUG(("Running non-timeout tasks"));
+      SILC_SCHEDULE_RUN_TASKS;
+
+      SILC_SCHEDULE_RUN_GENERIC_TASKS;
+      break;
+    }
+  }
+}
diff --git a/lib/silccore/silcschedule.h b/lib/silccore/silcschedule.h
new file mode 100644 (file)
index 0000000..87af2d1
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+
+  silcschedule.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1998 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSCHEDULE_H
+#define SILCSCHEDULE_H
+
+/* Structure holding list of file descriptors, scheduler is supposed to
+   be listenning. The max_fd field is the maximum number of possible file
+   descriptors in the list. This value is set at the initialization
+   of the scheduler and it usually is the maximum number of connections 
+   allowed. */
+typedef struct {
+  int *fd;
+  unsigned int last_fd;
+  unsigned int max_fd;
+} SilcScheduleFdList;
+
+/* 
+   Silc Schedule object. 
+
+   This is the actual schedule object in Silc. Both Silc client and server 
+   uses this same scheduler. Actually, this scheduler could be used by any
+   program needing scheduling.
+
+   Following short description of the fields:
+
+   SilcTaskQueue fd_queue
+
+       Task queue hook for non-timeout tasks. Usually this means that these
+       tasks perform different kind of I/O on file descriptors. File 
+       descriptors are usually network sockets but they actually can be
+       any file descriptors. This hook is initialized in silc_schedule_init
+       function. Timeout tasks should not be added to this queue because
+       they will never expire.
+
+   SilcTaskQueue timeout_queue
+
+       Task queue hook for timeout tasks. This hook is reserved specificly
+       for tasks with timeout. Non-timeout tasks should not be added to this
+       queue because they will never get scheduled. This hook is also
+       initialized in silc_schedule_init function.
+
+   SilcTaskQueue generic_queue
+
+       Task queue hook for generic tasks. This hook is reserved specificly
+       for generic tasks, tasks that apply to all file descriptors, except
+       to those that have specificly registered a non-timeout task. This hook
+       is also initialized in silc_schedule_init function.
+
+   SilcScheduleFdList fd_list
+
+       List of file descriptors the scheduler is supposed to be listenning.
+       This is updated internally.
+
+   struct timeval *timeout;
+
+       Pointer to the schedules next timeout. Value of this timeout is
+       automatically updated in the silc_schedule function.
+
+   int valid
+
+       Marks validity of the scheduler. This is a boolean value. When this
+       is false the scheduler is terminated and the program will end. This
+       set to true when the scheduler is initialized with silc_schedule_init
+       function.
+
+   fd_set in
+   fd_set out
+
+       File descriptor sets for select(). These are automatically managed
+       by the scheduler and should not be touched otherwise.
+
+   int max_fd
+
+       Number of maximum file descriptors for select(). This, as well, is
+       managed automatically by the scheduler and should be considered to 
+       be read-only field otherwise.
+
+*/
+
+typedef struct {
+  SilcTaskQueue fd_queue;
+  SilcTaskQueue timeout_queue;
+  SilcTaskQueue generic_queue;
+  SilcScheduleFdList fd_list;
+  struct timeval *timeout;
+  int valid;
+  fd_set in;
+  fd_set out;
+  int max_fd;
+} SilcScheduleObject;
+
+typedef SilcScheduleObject SilcSchedule;
+
+/* Prototypes */
+void silc_schedule_init(SilcTaskQueue fd_queue,
+                       SilcTaskQueue timeout_queue,
+                       SilcTaskQueue generic_queue,
+                       int max_fd);
+int silc_schedule_uninit();
+void silc_schedule_stop();
+void silc_schedule_set_listen_fd(int fd, unsigned int iomask);
+void silc_schedule_unset_listen_fd(int fd);
+void silc_schedule();
+
+#endif
diff --git a/lib/silccore/silcsockconn.c b/lib/silccore/silcsockconn.c
new file mode 100644 (file)
index 0000000..f6de8aa
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+
+  silcsockconn.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Allocates a new socket connection object. The allocated object is 
+   returned to the new_socket argument. */
+
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data, 
+                      SilcSocketConnection *new_socket)
+{
+  SILC_LOG_DEBUG(("Allocating new socket connection object"));
+
+  *new_socket = silc_calloc(1, sizeof(**new_socket));
+  if (*new_socket == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new socket connection object"));
+    return;
+  }
+
+  /* Set the pointers. Incoming and outgoing data buffers
+     are allocated by the server when they are first used. */
+  (*new_socket)->sock = sock;
+  (*new_socket)->type = type;
+  (*new_socket)->user_data = user_data;
+  (*new_socket)->protocol = NULL;
+  (*new_socket)->flags = 0;
+  (*new_socket)->inbuf = NULL;
+  (*new_socket)->outbuf = NULL;
+}
+
+/* Free's the Socket connection object. */
+
+void silc_socket_free(SilcSocketConnection sock)
+{
+  if (sock) {
+    //    silc_protocol_free(sock->protocol);
+    silc_buffer_free(sock->inbuf);
+    silc_buffer_free(sock->outbuf);
+    silc_free(sock);
+  }
+}
diff --git a/lib/silccore/silcsockconn.h b/lib/silccore/silcsockconn.h
new file mode 100644 (file)
index 0000000..5706b68
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+
+  silcsockconn.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSOCKCONN_H
+#define SILCSOCKCONN_H
+
+/* Socket types. These identifies the socket connection. */
+typedef enum {
+  SILC_SOCKET_TYPE_UNKNOWN = 0,
+  SILC_SOCKET_TYPE_CLIENT = 1,
+  SILC_SOCKET_TYPE_SERVER = 2,
+  SILC_SOCKET_TYPE_ROUTER = 3
+} SilcSocketType;
+
+/* Socket flags */
+#define SILC_SF_NONE 0
+#define SILC_SF_INBUF_PENDING 1
+#define SILC_SF_OUTBUF_PENDING 2
+#define SILC_SF_DISCONNECTING 3
+#define SILC_SF_DISCONNECTED 4
+
+/* 
+   SILC Socket Connection object.
+
+   This object holds information about the connected sockets to the server.
+   This is quite important object since this is referenced by the server all
+   the time when figuring out what the connection is supposed to be doing
+   and to whom we should send a message.
+
+   Following short description of the fields:
+
+   int sock
+
+       The actual connected socket. This is usually saved when accepting
+       new connection to the server.
+
+   SilcSocketType type
+
+       Type of the socket. This identifies the type of the connection. This
+       is mainly used to identify whether the connection is a client or a
+       server connection.
+
+   void *user_data
+
+       This is a pointer to a data that is is saved here at the same
+       time a new connection object is allocated. Usually this is a 
+       back-pointer to some important data for fast referencing. For
+       SILC server this is a pointer to the ID list and for SILC client
+       to object holding active connections (windows).
+
+   SilcProtocol protocol
+
+       Protocol object for the socket. Currently only one protocol can be
+       executing at a time for a particular socket.
+
+   unsigned int flags
+
+       Socket flags that indicate the status of the socket. This can
+       indicate several different status that can affect the use of the
+       socket object.
+
+   SilcBuffer inbuf
+   SilcBuffer outbuf
+
+       Incoming and outgoing buffers for the particular socket connection.
+       Incoming data from the socket is put after decryption in to the
+       inbuf buffer and outgoing data after encryption is put to the outbuf
+       buffer.
+
+*/
+typedef struct {
+  int sock;
+  SilcSocketType type;
+  void *user_data;
+  SilcProtocol protocol;
+  unsigned int flags;
+
+  char *hostname;
+  char *ip;
+  unsigned short port;
+
+  SilcBuffer inbuf;
+  SilcBuffer outbuf;
+} SilcSocketConnectionObject;
+
+typedef SilcSocketConnectionObject *SilcSocketConnection;
+
+/* Macros */
+
+/* Generic manipulation of flags */
+#define SF_SET(x, f) (x)->flags |= (1L << (f))
+#define SF_UNSET(x, f) (x)->flags &= ~(1L << (f))
+#define SF_IS(x, f) (x)->flags & (1L << (f))
+
+/* Setting/Unsetting flags */
+#define SILC_SET_OUTBUF_PENDING(x) SF_SET((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_SET_INBUF_PENDING(x) SF_SET((x), SILC_SF_INBUF_PENDING)
+#define SILC_SET_DISCONNECTING(x) SF_SET((x), SILC_SF_DISCONNECTING)
+#define SILC_SET_DISCONNECTED(x) SF_SET((x), SILC_SF_DISCONNECTED)
+#define SILC_UNSET_OUTBUF_PENDING(x) SF_UNSET((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_UNSET_INBUF_PENDING(x) SF_UNSET((x), SILC_SF_INBUF_PENDING)
+#define SILC_UNSET_DISCONNECTING(x) SF_UNSET((x), SILC_SF_DISCONNECTING)
+#define SILC_UNSET_DISCONNECTED(x) SF_UNSET((x), SILC_SF_DISCONNECTED)
+
+/* Checking for flags */
+#define SILC_IS_OUTBUF_PENDING(x) SF_IS((x), SILC_SF_OUTBUF_PENDING)
+#define SILC_IS_INBUF_PENDING(x) SF_IS((x), SILC_SF_INBUF_PENDING)
+#define SILC_IS_DISCONNECTING(x) SF_IS((x), SILC_SF_DISCONNECTING)
+#define SILC_IS_DISCONNECTED(x) SF_IS((x), SILC_SF_DISCONNECTED)
+
+/* Prototypes */
+void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
+                      SilcSocketConnection *new_socket);
+void silc_socket_free(SilcSocketConnection sock);
+
+#endif
diff --git a/lib/silccore/silctask.c b/lib/silccore/silctask.c
new file mode 100644 (file)
index 0000000..33a0551
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+
+  silctask.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1998 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Allocates a new task queue into the Silc. If 'valid' is TRUE the
+   queue becomes valid task queue. If it is FALSE scheduler will skip
+   the queue. */
+
+void silc_task_queue_alloc(SilcTaskQueue *new, int valid)
+{
+
+  SILC_LOG_DEBUG(("Allocating new task queue"));
+
+  *new = silc_calloc(1, sizeof(**new));
+  if (*new == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new task queue object: %s", 
+                   strerror(errno)));
+    return;
+  }
+
+  /* Set the pointers */
+  (*new)->valid = valid;
+  (*new)->task = NULL;
+  (*new)->register_task = silc_task_register;
+  (*new)->unregister_task = silc_task_unregister;
+  (*new)->set_iotype = silc_task_set_iotype;
+  (*new)->reset_iotype = silc_task_reset_iotype;
+}
+
+/* Free's a task queue. */
+
+void silc_task_queue_free(SilcTaskQueue old)
+{
+  if (old)
+    silc_free(old);
+}
+
+/* Adds a non-timeout task into the task queue. This function is used
+   by silc_task_register function. Returns a pointer to the registered 
+   task. */
+
+SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new, 
+                      SilcTaskPriority priority)
+{
+  SilcTask task, next, prev;
+
+  /* Take the first task in the queue */
+  task = queue->task;
+
+  switch(priority) {
+  case SILC_TASK_PRI_LOW:
+    /* Lowest priority. The task is added at the end of the list. */
+    prev = task->prev;
+    new->prev = prev;
+    new->next = task;
+    prev->next = new;
+    task->prev = new;
+    break;
+  case SILC_TASK_PRI_NORMAL:
+    /* Normal priority. The task is added before lower priority tasks
+       but after tasks with higher priority. */
+    prev = task->prev;
+    while(prev != task) {
+      if (prev->priority > SILC_TASK_PRI_LOW &&
+         prev->priority <= SILC_TASK_PRI_REALTIME)
+       break;
+      prev = prev->prev;
+    }
+    if (prev == task) {
+      /* There are only lower priorities in the list, we will
+        sit before them and become the first task in the queue. */
+      prev = task->prev;
+      new->prev = prev;
+      new->next = task;
+      task->prev = new;
+      prev->next = new;
+
+      /* We are now the first task in queue */
+      queue->task = new;
+    } else {
+      /* Found a spot from the list, add the task to the list. */
+      next = prev->next;
+      new->prev = prev;
+      new->next = next;
+      prev->next = new;
+      next->prev = new;
+    }
+    break;
+  case SILC_TASK_PRI_HIGH:
+    /* High priority. The task is added before lower priority tasks
+       but after tasks with higher priority. */
+    prev = task->prev;
+    while(prev != task) {
+      if (prev->priority > SILC_TASK_PRI_NORMAL &&
+         prev->priority <= SILC_TASK_PRI_REALTIME)
+       break;
+      prev = prev->prev;
+    }
+    if (prev == task) {
+      /* There are only lower priorities in the list, we will
+        sit before them and become the first task in the queue. */
+      prev = task->prev;
+      new->prev = prev;
+      new->next = task;
+      task->prev = new;
+      prev->next = new;
+
+      /* We are now the first task in queue */
+      queue->task = new;
+    } else {
+      /* Found a spot from the list, add the task to the list. */
+      next = prev->next;
+      new->prev = prev;
+      new->next = next;
+      prev->next = new;
+      next->prev = new;
+    }
+    break;
+  case SILC_TASK_PRI_REALTIME:
+    /* Highest priority. The task is added at the head of the list. 
+       The last registered task is added to the very head of the list
+       thus we get the LIFO (Last-In-First-Out) order. */
+    prev = task->prev;
+    new->prev = prev;
+    new->next = task;
+    prev->next = new;
+    task->prev = new;
+
+    /* We are the first task in the queue */
+    queue->task = new;
+    break;
+  default:
+    silc_free(new);
+    return NULL;
+  }
+
+  return new;
+}
+
+/* Adds a timeout task into the task queue. This function is used by
+   silc_task_register function. Returns a pointer to the registered 
+   task. Timeout tasks are sorted by their timeout value in ascending
+   order. The priority matters if there are more than one task with
+   same timeout. */
+
+SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
+                              SilcTaskPriority priority)
+{
+  SilcTask task, prev, next;
+
+  /* Take the first task in the queue */
+  task = queue->task;
+
+  /* Take last task from the list */
+  prev = task->prev;
+    
+  switch(priority) {
+  case SILC_TASK_PRI_LOW:
+    /* Lowest priority. The task is added at the end of the list. */
+    while(prev != task) {
+
+      /* If we have longer timeout than with the task head of us
+        we have found our spot. */
+      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+       break;
+
+      /* If we are equal size of timeout we will be after it. */
+      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+       break;
+
+      /* We have shorter timeout, compare to next one. */
+      prev = prev->prev;
+    }
+    /* Found a spot from the list, add the task to the list. */
+    next = prev->next;
+    new->prev = prev;
+    new->next = next;
+    prev->next = new;
+    next->prev = new;
+    
+    if (prev == task) {
+      /* Check if we are going to be the first task in the queue */
+      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+       break;
+      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+       break;
+
+      /* We are now the first task in queue */
+      queue->task = new;
+    }
+    break;
+  case SILC_TASK_PRI_NORMAL:
+    /* Normal priority. The task is added before lower priority tasks
+       but after tasks with higher priority. */
+    while(prev != task) {
+
+      /* If we have longer timeout than with the task head of us
+        we have found our spot. */
+      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+       break;
+
+      /* If we are equal size of timeout, priority kicks in place. */
+      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+       if (prev->priority >= SILC_TASK_PRI_NORMAL)
+         break;
+
+      /* We have shorter timeout or higher priority, compare to next one. */
+      prev = prev->prev;
+    }
+    /* Found a spot from the list, add the task to the list. */
+    next = prev->next;
+    new->prev = prev;
+    new->next = next;
+    prev->next = new;
+    next->prev = new;
+    
+    if (prev == task) {
+      /* Check if we are going to be the first task in the queue */
+      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+       break;
+      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+       if (prev->priority >= SILC_TASK_PRI_NORMAL)
+         break;
+
+      /* We are now the first task in queue */
+      queue->task = new;
+    }
+    break;
+  case SILC_TASK_PRI_HIGH:
+    /* High priority. The task is added before lower priority tasks
+       but after tasks with higher priority. */
+    while(prev != task) {
+
+      /* If we have longer timeout than with the task head of us
+        we have found our spot. */
+      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+       break;
+
+      /* If we are equal size of timeout, priority kicks in place. */
+      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+       if (prev->priority >= SILC_TASK_PRI_HIGH)
+         break;
+
+      /* We have shorter timeout or higher priority, compare to next one. */
+      prev = prev->prev;
+    }
+    /* Found a spot from the list, add the task to the list. */
+    next = prev->next;
+    new->prev = prev;
+    new->next = next;
+    prev->next = new;
+    next->prev = new;
+    
+    if (prev == task) {
+      /* Check if we are going to be the first task in the queue */
+      if (silc_task_timeout_compare(&prev->timeout, &new->timeout))
+       break;
+      if (!silc_task_timeout_compare(&new->timeout, &prev->timeout))
+       if (prev->priority >= SILC_TASK_PRI_HIGH)
+         break;
+
+      /* We are now the first task in queue */
+      queue->task = new;
+    }
+    break;
+  case SILC_TASK_PRI_REALTIME:
+    /* Highest priority. The task is added at the head of the list. 
+       The last registered task is added to the very head of the list
+       thus we get the LIFO (Last-In-First-Out) order. */
+    next = task->next;
+    while(next != task) {
+
+      /* If we have shorter timeout than the next task we've found
+        our spot. */
+      if (silc_task_timeout_compare(&new->timeout, &next->timeout))
+       break;
+
+      /* If we are equal size of timeout we will be first. */
+      if (!silc_task_timeout_compare(&next->timeout, &new->timeout))
+       break;
+
+      /* We have longer timeout, compare to next one. */
+      next = next->next;
+    }
+    /* Found a spot from the list, add the task to the list. */
+    prev = next->prev;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+    next->prev = new;
+    
+    if (next == task) {
+      /* Check if we are going to be the first task in the queue */
+      if (silc_task_timeout_compare(&next->timeout, &new->timeout))
+       break;
+
+      /* We are now the first task in queue */
+      queue->task = new;
+    }
+  default:
+    silc_free(new);
+    return NULL;
+  }
+
+  return new;
+}
+
+/* Registers a new task into the task queue. The task becomes valid
+   automatically when it is registered. Returns a pointer to the 
+   registered task. */
+
+SilcTask silc_task_register(SilcTaskQueue queue, int fd, 
+                           SilcTaskCallback cb, void *context, 
+                           long seconds, long useconds, 
+                           SilcTaskType type, SilcTaskPriority priority)
+{
+  SilcTask new;
+  int timeout = 0;
+
+  SILC_LOG_DEBUG(("Registering new task, fd=%d type=%d priority=%d", 
+                 fd, type, priority));
+
+  /* If the task is generic task, we check whether this task has already
+     been registered. Generic tasks are registered only once and after that
+     the same task applies to all file descriptors to be registered. */
+  if ((type == SILC_TASK_GENERIC) && queue->task) {
+    SilcTask task;
+
+    task = queue->task;
+    while(1) {
+      if ((task->callback == cb) && (task->context == context)) {
+       SILC_LOG_DEBUG(("Found matching generic task, using the match"));
+
+       /* Add the fd to be listened, the task found now applies to this
+          fd as well. */
+       silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
+       return task;
+      }
+
+      if (queue->task == task->next)
+       break;
+      
+      task = task->next;
+    }
+  }
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new task object"));
+    return NULL;
+  }
+
+  new->fd = fd;
+  new->context = context;
+  new->callback = cb;
+  new->valid = TRUE;
+  new->priority = priority;
+  new->iomask = (1L << SILC_TASK_READ);
+  new->next = new;
+  new->prev = new;
+
+  /* If the task is non-timeout task we have to tell the scheduler that we
+     would like to have these tasks scheduled at some odd distant future. */
+  if (type != SILC_TASK_TIMEOUT)
+    silc_schedule_set_listen_fd(fd, (1L << SILC_TASK_READ));
+
+  /* Create timeout if marked to be timeout task */
+  if (((seconds + useconds) > 0) && (type == SILC_TASK_TIMEOUT)) {
+    gettimeofday(&new->timeout, NULL);
+    new->timeout.tv_sec += seconds + (useconds / 1000000L);
+    new->timeout.tv_usec += (useconds % 1000000L);
+    if (new->timeout.tv_usec > 999999L) {
+      new->timeout.tv_sec += 1;
+      new->timeout.tv_usec -= 1000000L;
+    }
+    timeout = 1;
+  }
+
+  /* Is this first task of the queue? */
+  if (queue->task == NULL) {
+    queue->task = new;
+    return new;
+  }
+
+  if (timeout)
+    return silc_task_add_timeout(queue, new, priority);
+  else
+    return silc_task_add(queue, new, priority);
+}
+
+/* Removes (unregisters) a task from particular task queue. This function
+   is used internally by scheduler. One should not call this function
+   to unregister tasks, instead silc_task_unregister_task function
+   should be used. */
+
+int silc_task_remove(SilcTaskQueue queue, SilcTask task)
+{
+  SilcTask first, old, next;
+
+  if (!queue || !queue->task)
+    return FALSE;
+
+  first = queue->task;
+
+  /* Unregister all tasks in queue */
+  if (task == SILC_ALL_TASKS) {
+    SILC_LOG_DEBUG(("Removing all tasks at once"));
+    next = first;
+
+    while(1) {
+      next = next->next;
+      silc_free(next->prev);
+      if (next == first)
+       break;
+    }
+
+    queue->task = NULL;
+    return TRUE;
+  }
+
+  SILC_LOG_DEBUG(("Removing task"));
+
+  /* Unregister the task */
+  old = first;
+  while(1) {
+    if (old == task) {
+      SilcTask prev, next;
+
+      prev = old->prev;
+      next = old->next;
+      prev->next = next;
+      next->prev = prev;
+
+      if (prev == old && next == old)
+       queue->task = NULL;
+      if (queue->task == old)
+       queue->task = next;
+
+      silc_free(old);
+      return TRUE;
+    }
+    old = old->next;
+
+    if (old == first)
+      return FALSE;
+  }
+}
+
+/* Unregisters a task from the task queue. This is the unregister_task
+   function pointer in task queue object. One should use this function
+   to unregister tasks. This function invalidates the task. */
+
+void silc_task_unregister(SilcTaskQueue queue, SilcTask task)
+{
+
+  /* Unregister all tasks */
+  if (task == SILC_ALL_TASKS) {
+    SilcTask next;
+    SILC_LOG_DEBUG(("Unregistering all tasks at once"));
+
+    if (queue->task == NULL)
+      return;
+
+    next = queue->task;
+    
+    while(1) {
+      if (next->valid)
+       next->valid = FALSE;
+      if (queue->task == next->next)
+       break;
+      next = next->next;
+    }
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Unregistering task"));
+
+  /* Unregister the specific task */
+  if (task->valid)
+    task->valid = FALSE;
+}
+
+/* Unregister a task by file descriptor. This invalidates the task. */
+
+void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd)
+{
+  SilcTask next;
+
+  SILC_LOG_DEBUG(("Unregister task by fd"));
+
+  if (queue->task == NULL)
+    return;
+
+  next = queue->task;
+
+  while(1) {
+    if (next->fd == fd)
+      next->valid = FALSE;
+    if (queue->task == next->next)
+      break;
+    next = next->next;
+  }
+}
+
+/* Sets the I/O mask for the task. Only one I/O type can be set at a
+   time. */
+
+void silc_task_set_iotype(SilcTask task, int type)
+{
+  task->iomask |= (1L << type);
+}
+
+/* Resets the I/O mask to the type sent as argument. */
+
+void silc_task_reset_iotype(SilcTask task, int type)
+{
+  task->iomask = (1L << type);
+}
+
+/* Compare two time values. If the first argument is smaller than the
+   second this function returns TRUE. */
+
+int silc_task_timeout_compare(struct timeval *smaller, 
+                             struct timeval *bigger)
+{
+  if ((smaller->tv_sec < bigger->tv_sec) ||
+      ((smaller->tv_sec == bigger->tv_sec) &&
+       (smaller->tv_usec < bigger->tv_usec)))
+    return TRUE;
+
+  return FALSE;
+}
diff --git a/lib/silccore/silctask.h b/lib/silccore/silctask.h
new file mode 100644 (file)
index 0000000..e07e6e9
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+
+  silctask.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1998 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCTASK_H
+#define SILCTASK_H
+
+/* 
+   SILC Task object. 
+
+   int fd
+
+       File descriptor. This usually is a network socket but can be
+       any file descriptor. On generic tasks, that applies to all file
+       descriptors, this is set to -1.
+
+   struct timeval timeout
+  
+       The timeout when this task is supposed to be run. This is defined
+       only if the task is a timeout task.
+
+   void *context;
+
+       Context structure passed to callback function as argument.
+
+   SilcTaskCallback callback
+
+       The callback function Silc scheduler calls when this task is scheduled
+       to be run. First argument is the task queue this task belongs to. This
+       is a void pointer and the task queue has to casted out of it. Second
+       argument is the type of the event just occured inside the scheduler 
+       (SILC_TASK_READ or SILC_TASK_WRITE). Third argument is the context 
+       structure of the task. Last argument is the file descriptor of the
+       task.
+
+   int valid
+
+       Marks for validity of the task. Task that is not valid scheduler 
+       will skip. This is boolean value.
+
+   int priority
+
+       Priority of the task. This field is used internally only and it
+       should not be touched otherwise.
+
+   int iomask
+
+       I/O mask which tells to the scheduler for what kind of I/O this 
+       task is ready. If the task is ready for both reading and writing
+       SILC_TASK_READ and SILC_TASK_WRITE are masked into this variable.
+       Masking is done by OR'ing (1 << SILC_TASK_*) values. One can check
+       the mask by AND'ing (1L << SILC_TASK_*) against the mask. At the
+       registering of a new task this mask is set to SILC_TASK_READ by
+       default. If a task doesn't perform reading this value must be
+       reset to SILC_TASK_WRITE. If it performs both reading and writing
+       SILC_TASK_WRITE must be added to the mask. A task must always be 
+       ready for at least for one I/O type.
+
+   struct SilcTaskStruct *next
+   struct SilcTaskStruct *prev
+
+       Next and previous task. If the task is first in the list, prev is
+       set to the last task in the list. If the task is last in the list, 
+       next is set to the first task in the list (forms a circular list).
+
+*/
+
+typedef void (*SilcTaskCallback)(void *, int, void *, int);
+
+typedef struct SilcTaskStruct {
+  int fd;
+  struct timeval timeout;
+  void *context;
+  SilcTaskCallback callback;
+  int valid;
+  int priority;
+  int iomask;
+
+  struct SilcTaskStruct *next;
+  struct SilcTaskStruct *prev;
+} SilcTaskObject;
+
+typedef SilcTaskObject *SilcTask;
+
+/* 
+   SILC Task types.
+
+   SILC has three types of tasks, non-timeout tasks (tasks that perform
+   over file descriptors), timeout tasks and generic tasks (tasks that apply
+   to every file descriptor). This type is sent as argument for the 
+   task registering function.
+
+*/
+typedef enum {
+  SILC_TASK_FD,
+  SILC_TASK_TIMEOUT,
+  SILC_TASK_GENERIC,
+} SilcTaskType;
+
+/* 
+   SILC Task priorities.
+
+   Following description of the priorities uses timeout tasks as example
+   how the priority behaves. However, non-timeout tasks behaves same as
+   timeout tasks with following priorities.
+
+   SILC_TASK_PRI_LOW
+
+       Lowest priority. The task is scheduled to run after its timeout
+       has expired only and only when every other task with higher priority 
+       has already been run. For non-timeout tasks this priority behaves
+       same way. Life is not fair for tasks with this priority.
+
+   SILC_TASK_PRI_NORMAL
+
+       Normal priority that is used mostly in Silc. This is priority that
+       should always be used unless you specificly need some other priority.
+       The scheduler will run this task as soon as its timeout has expired.
+       For non-timeout tasks this priority behaves same way. Tasks are run 
+       in FIFO (First-In-First-Out) order.
+
+   SILC_TASK_PRI_HIGH
+   
+       High priority for important tasks. This priority should be used only
+       for important tasks. Life is very fair for tasks with this priority.
+       These tasks are run as soon as its timeout has expired. They are run 
+       before normal or lower tasks, respectively. For non-timeout tasks
+       this priority behaves same way. Tasks are run in FIFO order.
+
+   SILC_TASK_PRI_REALTIME
+
+       Highest priority. This priority should be used very carefully because
+       it can make the scheduler extremely unfair to other tasks. The task
+       will be run as soon as its timeout has expired. The task is run before
+       any other task. It is also quaranteed that the last registered task
+       with this priority is the first task to be run when its timeout
+       expires. Tasks are run in LIFO (Last-In-First-Out) order. To make
+       scheduler fair there should never be more than one task in the queue
+       with this priority. Currently none of the tasks in SILC are important
+       enough to use this priority. For non-timeout tasks this priority
+       behaves same way.
+
+*/
+typedef enum {
+  SILC_TASK_PRI_LOW,
+  SILC_TASK_PRI_NORMAL,
+  SILC_TASK_PRI_HIGH,
+  SILC_TASK_PRI_REALTIME,
+} SilcTaskPriority;
+
+/* 
+   SILC Task Queue object. 
+   
+   Usually there are three task queues in SILC. Tasks with timeouts
+   has their own queue, tasks without timeout has one as well and generic
+   tasks has their own also. Scheduler has timeout queue hooks and 
+   non-timeout queue hooks in the scheduler and it does not check for 
+   timeouts in non-timeout hooks and vice versa, respectively. Ie. Register 
+   timeout queues to their own SilcTaskQueue pointer and non-timeout queues 
+   to their own pointer. 
+
+   Generic tasks, mentioned earlier, has their own task queue. These tasks 
+   are non-timeout tasks and they apply to all file descriptors, except to 
+   those that have explicitly registered a non-timeout task. These tasks
+   are there to make it simpler and faster to execute common code that
+   applies to all connections. These are, for example, receiving packets
+   from network and sending packets to network. It doesn't make much sense
+   to register a task that receives a packet from network to every connection
+   when you can have one task that applies to all connections. This is what
+   generic tasks are for. Generic tasks are not bound to any specific file
+   descriptor, however, the correct file descriptor must be passed as
+   argument to task registering function.
+
+   Short description of the field following:
+
+   SilcTask task
+
+       Pointer to the tasks in the queue.
+
+   int valid
+
+       Marks for validity of the queue. If the task queue is not valid 
+       scheduler will skip it. This is boolean value.
+
+   struct timeval timeout
+
+       Timeout when earliest some tasks in this queue should expire. The
+       value of this timeout is updated automatically by schedule. This 
+       is used only and only if this queue is a timeout queue. For normal
+       task queue this is not defined. This is meant only for internal
+       use and it should be considered to be read-only field.
+
+   SilcTask (*register_task)(SilcTaskQueue, int, 
+                             SilcTaskCallback, void *, 
+                            long, long, 
+                            SilcTaskType,
+                            SilcTaskPriority)
+
+       Registers a new task to the task queue. Arguments are as follows:
+
+       SilcTaskQueue queue        Queue where the task is to be registered
+       int fd                     File descriptor
+       SilcTaskCallback cb        Callback function to call
+       void *context              Context to be passed to callback function
+       long seconds               Seconds to timeout
+       long useconds              Microseconds to timeout
+       SilcTaskType type          Type of the task
+       SilcTaskPriority priority  Priority of the task
+
+       The same function is used to register all types of tasks. The type
+       argument tells what type of the task is. Note that when registering
+       non-timeout tasks one should also pass 0 as timeout as timeout will
+       be ignored anyway. Also, note, that one cannot register timeout task
+       with 0 timeout. There cannot be zero timeouts, passing zero means
+       no timeout is used for the task and SILC_TASK_FD_TASK is used as
+       default task type in this case.
+
+       One should be careful not to register timeout tasks to the non-timeout
+       task queue, because they will never expire. As one should not register
+       non-timeout tasks to timeout task queue because they will never get
+       scheduled.
+
+       There is a one distinct difference between timeout and non-timeout
+       tasks when they are executed. Non-timeout tasks remain on the task
+       queue after execution. Timeout tasks, however, are removed from the
+       task queue after they have expired. It is safe to re-register a task 
+       in its own callback function. It is also safe to unregister a task 
+       in a callback function.
+
+       Generic tasks apply to all file descriptors, however, one still must
+       pass the correct file descriptor to the function when registering
+       generic tasks.
+
+   void (*unregister_task)(SilcTaskQueue, SilcTask)
+
+       Unregisters a task already in the queue. Arguments are as follows:
+
+       SilcTaskQueue queue      Queue where from the task is unregistered
+       SilcTask task            Task to be unregistered
+
+       The same function is used to unregister timeout and non-timeout 
+       tasks. One can also unregister all tasks from the queue by passing
+       SILC_ALL_TASKS as task to the function. It is safe to unregister
+       a task in a callback function.
+
+   void (*set_iotype)(SilcTask, int type)
+
+       Sets the I/O type of the task. The scheduler checks for this value
+       and a task must always have at least one of the I/O types set at 
+       all time. When registering new task the type is set by default to
+       SILC_TASK_READ. If the task doesn't perform reading one must reset
+       the value to SILC_TASK_WRITE.
+
+       The type sent as argumenet is masked into the task. If the tasks 
+       I/O mask already includes this type this function has no effect. 
+       Only one I/O type can be added at once. If the task must perform
+       both reading and writing one must call this function for value
+       SILC_TASK_WRITE as well.
+
+   void (*reset_iotype)(SilcTask, int type)
+
+       Resets the mask to the type sent as argument. Note that this resets
+       the previous values to zero and then adds the type sent as argument.
+       This function can be used to remove one of the types masked earlier
+       to the task.
+
+*/
+
+typedef struct SilcTaskQueueStruct {
+  SilcTask task;
+  int valid;
+  struct timeval timeout;
+
+  /* Method functions */
+  SilcTask (*register_task)(struct SilcTaskQueueStruct *, int, 
+                           SilcTaskCallback, void *, long, long, 
+                           SilcTaskType, SilcTaskPriority);
+  void (*unregister_task)(struct SilcTaskQueueStruct *, SilcTask);
+  void (*set_iotype)(SilcTask, int type);
+  void (*reset_iotype)(SilcTask, int type);
+} SilcTaskQueueObject;
+
+typedef SilcTaskQueueObject *SilcTaskQueue;
+
+/* Marks for all tasks in a task queue. This can be passed to 
+   unregister_task function to cancel all tasks at once. */
+#define SILC_ALL_TASKS ((SilcTask)1)
+
+/* Marks for all task queues. This can be passed to 
+   silc_task_queue_unregister function to cancel all task queues at once. */
+#define SILC_ALL_TASK_QUEUES ((SilcTaskQueue)1)
+
+/* Silc Task event types. One of these are passed to the task callback
+   function from the schedule. These values are also masked into a task
+   so that scheduler knows for what kind of I/O it needs to perform
+   for that task. */
+#define SILC_TASK_READ 0
+#define SILC_TASK_WRITE 1
+
+/* Macros */
+
+/* These can be used instead of calling directly the registering function. 
+   XXX: These are not used currently, maybe they should be :) */
+#define SILC_REGISTER_FD_TASK(queue, fd, cb, ctx, pri) \
+  (silc_task_register((queue), (fd), (cb), (ctx), 0, 0, \
+                     SILC_TASK_FD, (pri)))
+#define SILC_REGISTER_TIMEOUT_TASK(queue, fd, cb, ctx, sec, usec, pri) \
+  (silc_task_register((queue), (fd), (cb), (ctx), (sec), (usec), \
+                     SILC_TASK_TIMEOUT, (pri)))
+#define SILC_REGISTER_GENERIC_TASK(queue, fd, cb, ctx, pri) \
+  (silc_task_register((queue), (fd), (cb), (ctx), 0, 0, \
+                     SILC_TASK_GENERIC, (pri)))
+
+/* Generic macro to define task callback functions. This defines a function
+   with name 'func' as a task callback function. */
+#define SILC_TASK_CALLBACK(func) \
+static void func(void *qptr, int type, void *context, int fd)
+
+
+/* Prototypes */
+void silc_task_queue_alloc(SilcTaskQueue *new, int valid);
+void silc_task_queue_free(SilcTaskQueue old);
+SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new, 
+                      SilcTaskPriority priority);
+SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new,
+                              SilcTaskPriority priority);
+SilcTask silc_task_register(SilcTaskQueue queue, int fd, 
+                           SilcTaskCallback cb, void *context, 
+                           long seconds, long useconds, 
+                           SilcTaskType type, 
+                           SilcTaskPriority priority);
+int silc_task_remove(SilcTaskQueue queue, SilcTask task);
+void silc_task_unregister(SilcTaskQueue queue, SilcTask task);
+void silc_task_unregister_by_fd(SilcTaskQueue queue, int fd);
+void silc_task_set_iotype(SilcTask task, int type);
+void silc_task_reset_iotype(SilcTask task, int type);
+int silc_task_timeout_compare(struct timeval *smaller, 
+                             struct timeval *bigger);
+
+#endif
diff --git a/lib/silccore/silcutil.c b/lib/silccore/silcutil.c
new file mode 100644 (file)
index 0000000..d5611c4
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+
+  silcutil.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * These are general utility functions that doesn't belong to any specific
+ * group of routines.
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Reads a file to a buffer. The allocated buffer is returned. Length of
+   the file read is returned to the return_len argument. */
+
+char *silc_file_read(const char *filename, int *return_len)
+{
+  int fd;
+  char *buffer;
+  int filelen;
+
+  fd = open(filename, O_RDONLY);
+  if (fd < 0) {
+    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
+    return NULL;
+  }
+
+  filelen = lseek(fd, (off_t)0L, SEEK_END);
+  lseek(fd, (off_t)0L, SEEK_SET);  
+
+  if (filelen < 0) {
+    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
+    return NULL;
+  }
+  
+  buffer = silc_calloc(filelen + 1, sizeof(char));
+  
+  if ((read(fd, buffer, filelen)) == -1) {
+    memset(buffer, 0, sizeof(buffer));
+    close(fd);
+    SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
+                    strerror(errno)));
+    return NULL;
+  }
+
+  close(fd);
+  buffer[filelen] = EOF;
+  
+  *return_len = filelen;
+  return buffer;
+}
+
+/* Writes a buffer to the file. */
+
+int silc_file_write(const char *filename, const char *buffer, int len)
+{
+  int fd;
+        
+  if ((fd = creat(filename, 0644)) == -1) {
+    SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
+    return -1;
+  }
+  
+  if ((write(fd, buffer, len)) == -1) {
+    SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
+    return -1;
+  }
+
+  close(fd);
+  
+  return 0;
+}
+
+/* Gets line from a buffer. Stops reading when a newline or EOF occurs.
+   This doesn't remove the newline sign from the destination buffer. The
+   argument begin is returned and should be passed again for the function. */
+
+int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
+{
+  static int start = 0;
+  int i;
+  
+  memset(dest, 0, destlen);
+  
+  if (begin != start)
+    start = 0;
+  
+  i = 0;
+  for ( ; start <= srclen; i++, start++) {
+    if (i > destlen)
+      return -1;
+    
+    dest[i] = src[start];
+    
+    if (dest[i] == EOF) 
+      return EOF;
+    
+    if (dest[i] == '\n') 
+      break;
+  }
+  start++;
+  
+  return start;
+}
+
+/* Checks line for illegal characters. Return -1 when illegal character
+   were found. This is used to check for bad lines when reading data from
+   for example a configuration file. */
+
+int silc_check_line(char *buf) 
+{
+  /* Illegal characters in line */
+  if (strchr(buf, '#')) return -1;
+  if (strchr(buf, '\'')) return -1;
+  if (strchr(buf, '\\')) return -1;
+  if (strchr(buf, '\r')) return -1;
+  if (strchr(buf, '\a')) return -1;
+  if (strchr(buf, '\b')) return -1;
+  if (strchr(buf, '\f')) return -1;
+  
+  /* Empty line */
+  if (buf[0] == '\n')
+    return -1;
+  
+  return 0;
+}
+
+/* Returns current time as string. */
+
+char *silc_get_time()
+{
+  time_t curtime;
+  char *return_time;
+
+  curtime = time(NULL);
+  return_time = ctime(&curtime);
+  return_time[strlen(return_time) - 1] = '\0';
+
+  return return_time;
+}
+
+/* Converts string to capital characters */
+
+char *silc_to_upper(char *string)
+{
+  int i;
+  char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
+
+  for (i = 0; i < strlen(string); i++)
+    ret[i] = toupper(string[i]);
+
+  return ret;
+}
+
+/* Compares two strings. Strings may include wildcards * and ?.
+   Returns TRUE if strings match. */
+
+int silc_string_compare(char *string1, char *string2)
+{
+  int i;
+  int slen1 = strlen(string1);
+  int slen2 = strlen(string2);
+  char *tmpstr1, *tmpstr2;
+
+  if (!string1 || !string2)
+    return FALSE;
+
+  /* See if they are same already */
+  if (!strncmp(string1, string2, strlen(string2)))
+    return TRUE;
+
+  if (slen2 < slen1)
+    if (!strchr(string1, '*'))
+      return FALSE;
+  
+  /* Take copies of the original strings as we will change them */
+  tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
+  memcpy(tmpstr1, string1, slen1);
+  tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
+  memcpy(tmpstr2, string2, slen2);
+  
+  for (i = 0; i < slen2; i++) {
+    
+    /* * wildcard. Only one * wildcard is possible. */
+    if (tmpstr1[i] == '*')
+      if (!strncmp(tmpstr1, tmpstr2, i)) {
+       memset(tmpstr2, 0, slen2);
+       strncpy(tmpstr2, tmpstr1, i);
+       break;
+      }
+    
+    /* ? wildcard */
+    if (tmpstr1[i] == '?') {
+      if (!strncmp(tmpstr1, tmpstr2, i)) {
+       if (!(slen1 < i + 1))
+         if (tmpstr1[i + 1] != '?' &&
+             tmpstr1[i + 1] != tmpstr2[i + 1])
+           continue;
+       
+       if (!(slen1 < slen2))
+         tmpstr2[i] = '?';
+      }
+#if 0
+    } else {
+      if (strncmp(tmpstr1, tmpstr2, i))
+       strncpy(tmpstr2, string2, slen2);
+#endif
+    }
+  }
+  
+  /* if using *, remove it */
+  if (strchr(tmpstr1, '*'))
+    *strchr(tmpstr1, '*') = 0;
+  
+  if (!strcmp(tmpstr1, tmpstr2)) {
+    memset(tmpstr1, 0, slen1);
+    memset(tmpstr2, 0, slen2);
+    silc_free(tmpstr1);
+    silc_free(tmpstr2);
+    return TRUE;
+  }
+  
+  memset(tmpstr1, 0, slen1);
+  memset(tmpstr2, 0, slen2);
+  silc_free(tmpstr1);
+  silc_free(tmpstr2);
+  return FALSE;
+}
diff --git a/lib/silccore/silcutil.h b/lib/silccore/silcutil.h
new file mode 100644 (file)
index 0000000..dc57eeb
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+
+  silcutil.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCUTIL_H
+#define SILCUTIL_H
+
+/* Prototypes */
+char *silc_file_read(const char *filename, int *return_len);
+int silc_file_write(const char *filename, const char *buffer, int len);
+int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin);
+int silc_check_line(char *buf);
+char *silc_get_time();
+char *silc_to_upper(char *string);
+int silc_string_compare(char *string1, char *string2);
+
+#endif
diff --git a/lib/silccrypt/Makefile.am b/lib/silccrypt/Makefile.am
new file mode 100644 (file)
index 0000000..b0d7d81
--- /dev/null
@@ -0,0 +1,44 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilccrypt.a
+
+libsilccrypt_a_SOURCES = \
+       none.c \
+       blowfish.c \
+       rc5.c \
+       rc6.c \
+       mars.c \
+       md5.c \
+       rijndael.c \
+       rsa.c \
+       sha1.c \
+       twofish.c \
+       silccipher.c \
+       silchash.c \
+       silchmac.c \
+       silcrng.c \
+       silcpkcs.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccore -I../silcmath -I../silcske \
+       -I../silcsim -I../.. -I../../includes \
+       -I../silcmath/gmp-3.0.1
diff --git a/lib/silccrypt/blowfish.c b/lib/silccrypt/blowfish.c
new file mode 100644 (file)
index 0000000..03ff471
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * This implementation was taken from the International Kernel (kerneli)
+ * patch for Linux kernel. The author is unknown to me. This
+ * implementation is under the same license as it is in the kerneli patch.
+ * I've modified it a bit to fit to SILC. -Pekka
+ */
+/*
+ * blowfish.c
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, dis-
+ * tribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the fol-
+ * lowing conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
+ * SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABIL-
+ * ITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the authors shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * the authors.
+ *
+ */
+
+#include "silcincludes.h"
+#include "blowfish.h"
+
+static u32 bf_pbox[16 + 2] =
+{
+    0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+    0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+    0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+    0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+    0x9216d5d9, 0x8979fb1b,
+};
+
+static u32 bf_sbox[256 * 4] =
+{
+    0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+    0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+    0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+    0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+    0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+    0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+    0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+    0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+    0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+    0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+    0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+    0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+    0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+    0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+    0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+    0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+    0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+    0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+    0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+    0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+    0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+    0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+    0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+    0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+    0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+    0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+    0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+    0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+    0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+    0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+    0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+    0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+    0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+    0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+    0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+    0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+    0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+    0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+    0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+    0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+    0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+    0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+    0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+    0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+    0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+    0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+    0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+    0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+    0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+    0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+    0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+    0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+    0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+    0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+    0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+    0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+    0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+    0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+    0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+    0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+    0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+    0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+    0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+    0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+    0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+    0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+    0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+    0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+    0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+    0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+    0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+    0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+    0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+    0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+    0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+    0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+    0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+    0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+    0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+    0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+    0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+    0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+    0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+    0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+    0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+    0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+    0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+    0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+    0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+    0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+    0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+    0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+    0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+    0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+    0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+    0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+    0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+    0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+    0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+    0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+    0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+    0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+    0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+    0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+    0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+    0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+    0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+    0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+    0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+    0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+    0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+    0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+    0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+    0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+    0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+    0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+    0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+    0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+    0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+    0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+    0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+    0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+    0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+    0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+    0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+    0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+    0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+    0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+    0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+    0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+    0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+    0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+    0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+    0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+    0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+    0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+    0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+    0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+    0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+    0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+    0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+    0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+    0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+    0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+    0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+    0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+    0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+    0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+    0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+    0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+    0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+    0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+    0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+    0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+    0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+    0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+    0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+    0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+    0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+    0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+    0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+    0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+    0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+    0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+    0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+    0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+    0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+    0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+    0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+    0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+    0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+    0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+    0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+    0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+    0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+    0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+    0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+    0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+    0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+    0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+    0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+    0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+    0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+    0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+    0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+    0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+    0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+    0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+    0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+    0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+    0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+    0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+    0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+    0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+    0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+    0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+    0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+    0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+    0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+    0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+    0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+    0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+    0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+    0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+    0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+    0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+    0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+    0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+    0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+    0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+    0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+    0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+    0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+    0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+    0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+    0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+    0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+    0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+    0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+    0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+    0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+    0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+    0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+    0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+    0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+    0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+    0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+    0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+    0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+    0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+    0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+    0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+    0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+    0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+    0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+    0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+    0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+    0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+    0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+    0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+    0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+    0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+    0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+    0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+    0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+    0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+    0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+    0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+    0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+    0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+    0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+    0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+    0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+    0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+    0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+    0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+};
+
+/* 
+ * Round loop unrolling macros, S is a pointer to a S-Box array
+ * organized in 4 unsigned longs at a row.
+ */
+
+#define GET32_3(x) (((x) & 0xff))
+#define GET32_2(x) (((x) >> (8)) & (0xff))
+#define GET32_1(x) (((x) >> (16)) & (0xff))
+#define GET32_0(x) (((x) >> (24)) & (0xff))
+
+#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
+          S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
+
+#define ROUND(a, b, n) b^=P[n];a ^= bf_F(b)
+
+/*
+ * The blowfish encipher, processes 64-bit blocks.
+ * NOTE: This function MUSTN'T respect endianess 
+ */
+
+int blowfish_encrypt(BlowfishContext *ctx,
+                    u32 *in_blk, u32 *out_blk, int size)
+{
+    u32 yl,yr;
+
+    u32 *P = ctx->P;
+    u32 *S = ctx->S;
+
+    for (; size >= 8; size -= 8) {
+        yl = *(in_blk++);
+        yr = *(in_blk++);
+
+        ROUND(yr, yl, 0);
+        ROUND(yl, yr, 1);
+        ROUND(yr, yl, 2);
+        ROUND(yl, yr, 3);
+        ROUND(yr, yl, 4);
+        ROUND(yl, yr, 5);
+        ROUND(yr, yl, 6);
+        ROUND(yl, yr, 7);
+        ROUND(yr, yl, 8);
+        ROUND(yl, yr, 9);
+        ROUND(yr, yl, 10);
+        ROUND(yl, yr, 11);
+        ROUND(yr, yl, 12);
+        ROUND(yl, yr, 13);
+        ROUND(yr, yl, 14);
+        ROUND(yl, yr, 15);
+
+       /* yl and yr are switched */
+       yl ^= P[16];
+       yr ^= P[17];
+
+        *(out_blk++) = yr;
+        *(out_blk++) = yl;
+    }
+
+    return 0;
+}
+
+int blowfish_decrypt(BlowfishContext *ctx,
+                    u32 *in_blk, u32 *out_blk, int size)
+{
+    u32 yl,yr;
+
+    u32 *P = ctx->P;
+    u32 *S = ctx->S;
+
+    for (; size >= 8; size -= 8) {
+        yl = *(in_blk++);
+        yr = *(in_blk++);
+
+        ROUND(yr, yl, 17);
+        ROUND(yl, yr, 16);
+        ROUND(yr, yl, 15);
+        ROUND(yl, yr, 14);
+        ROUND(yr, yl, 13);
+        ROUND(yl, yr, 12);
+        ROUND(yr, yl, 11);
+        ROUND(yl, yr, 10);
+        ROUND(yr, yl, 9);
+        ROUND(yl, yr, 8);
+        ROUND(yr, yl, 7);
+        ROUND(yl, yr, 6);
+        ROUND(yr, yl, 5);
+        ROUND(yl, yr, 4);
+        ROUND(yr, yl, 3);
+        ROUND(yl, yr, 2);
+
+       /* yl and yr are switched */
+       yl ^= P[1];
+       yr ^= P[0];
+
+        *(out_blk++) = yr;
+        *(out_blk++) = yl;
+    }
+
+    return 0;
+}
+
+/* Sets the blowfish S and P boxes for encryption and decryption. */
+
+int blowfish_set_key(BlowfishContext *ctx,
+                    unsigned char *key, int keybytes)
+{
+    short i;
+    short j;
+    short count;
+    u32 data[2];
+    u32 temp;
+    u32 *P = ctx->P;
+    u32 *S = ctx->S;
+
+    /* Copy the initialization s-boxes */
+
+    for (i = 0, count = 0; i < 256; i++)
+        for (j = 0; j < 4; j++, count++)
+            S[count] = bf_sbox[count];
+
+    /* Set the p-boxes */
+
+    for (i = 0; i < 16 + 2; i++)
+        P[i] = bf_pbox[i];
+
+    /* Actual subkey generation */
+
+    for (j = 0, i = 0; i < 16 + 2; i++)
+    {
+        temp = (((u32) key[j] << 24) |
+                ((u32) key[(j + 1) % keybytes] << 16) |
+                ((u32) key[(j + 2) % keybytes] << 8) |
+                ((u32) key[(j + 3) % keybytes] ));
+
+        P[i] = P[i] ^ temp;
+        j = (j + 4) % keybytes;
+    }
+
+    data[0] = 0x00000000;
+    data[1] = 0x00000000;
+
+    for (i = 0; i < 16 + 2; i += 2)
+    {
+        blowfish_encrypt(ctx, data, data, 8);
+        
+        P[i] = data[0];
+        P[i + 1] = data[1];
+    }
+
+    for (i = 0; i < 4; i++)
+    {
+        for (j = 0, count = i * 256; j < 256; j += 2, count += 2)
+        {
+            blowfish_encrypt(ctx, data, data, 8);
+
+            S[count] = data[0];
+            S[count + 1] = data[1];
+        }
+    }
+    return 0;
+}
diff --git a/lib/silccrypt/blowfish.h b/lib/silccrypt/blowfish.h
new file mode 100644 (file)
index 0000000..a199247
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+
+  blowfish.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef BLOWFISH_H
+#define BLOWFISH_H
+
+#include "blowfish_internal.h"
+
+/* 
+ * SILC Crypto API for Blowfish
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(blowfish)
+{
+  blowfish_set_key((BlowfishContext *)context, 
+                  (unsigned char *)key, keylen);
+  return TRUE;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(blowfish)
+{
+  SilcHash hash;
+  unsigned char key[16];
+
+  silc_hash_alloc("md5", &hash);
+  hash->make_hash(hash, string, stringlen, key);
+
+  blowfish_set_key((BlowfishContext *)context, key, sizeof(key));
+
+  silc_hash_free(hash);
+  memset(&key, 'F', sizeof(key));
+  
+  return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(blowfish)
+{
+  return sizeof(BlowfishContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(blowfish)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];  
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  blowfish_encrypt((BlowfishContext *)context, tmp, out, 16);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    blowfish_encrypt((BlowfishContext *)context, tmp, out, 16);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_DECRYPT_CBC(blowfish)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  blowfish_decrypt((BlowfishContext *)context, in, out, 16);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    blowfish_decrypt((BlowfishContext *)context, in, out, 16);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/blowfish_internal.h b/lib/silccrypt/blowfish_internal.h
new file mode 100644 (file)
index 0000000..19126f0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+
+  blowfish_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef BLOWFISH_INTERNAL_H
+#define BLOWFISH_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct blow_key
+{
+    u32 P[18];
+    u32 S[1024];
+} BlowfishContext;
+
+/* Prototypes */
+int blowfish_encrypt(BlowfishContext *ctx, 
+                    u32 *in_blk, u32 *out_blk, int size);
+int blowfish_decrypt(BlowfishContext *ctx, 
+                    u32 *in_blk, u32 *out_blk, int size);
+int blowfish_set_key(BlowfishContext *ctx,
+                    unsigned char *key, int keybytes);
+
+#endif
diff --git a/lib/silccrypt/cast.c b/lib/silccrypt/cast.c
new file mode 100644 (file)
index 0000000..1f066df
--- /dev/null
@@ -0,0 +1,381 @@
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         CAST-256 by Carlisle Adams of Entrust Tecnhologies           */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+\r
+/* Timing data for CAST-256 (cast.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    4333 cycles\r
+Encrypt:       633 cycles =    40.4 mbits/sec\r
+Decrypt:       634 cycles =    40.4 mbits/sec\r
+Mean:          634 cycles =    40.4 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    4342 cycles\r
+Encrypt:       633 cycles =    40.4 mbits/sec\r
+Decrypt:       633 cycles =    40.4 mbits/sec\r
+Mean:          633 cycles =    40.4 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    4325 cycles\r
+Encrypt:       639 cycles =    40.1 mbits/sec\r
+Decrypt:       638 cycles =    40.1 mbits/sec\r
+Mean:          639 cycles =    40.1 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    4294 cycles\r
+Encrypt:       678 cycles =    37.8 mbits/sec\r
+Decrypt:       669 cycles =    38.3 mbits/sec\r
+Mean:          674 cycles =    38.0 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    4314 cycles\r
+Encrypt:       678 cycles =    37.8 mbits/sec\r
+Decrypt:       670 cycles =    38.2 mbits/sec\r
+Mean:          674 cycles =    38.0 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    4313 cycles\r
+Encrypt:       678 cycles =    37.8 mbits/sec\r
+Decrypt:       669 cycles =    38.3 mbits/sec\r
+Mean:          674 cycles =    38.0 mbits/sec\r
+\r
+*/\r
+\r
+#include "silcincludes.h"\r
+#include "cast.h"\r
+    \r
+u4byte s_box[4][256] = \r
+{ {\r
+    0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9C004dd3, \r
+    0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675,\r
+    0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, \r
+    0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,\r
+    0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, \r
+    0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, \r
+    0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159, \r
+    0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,\r
+    0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f,\r
+    0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,\r
+    0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0C50, 0x882240f2, 0x0c6e4f38, \r
+    0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,\r
+    0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, \r
+    0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, \r
+    0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb, \r
+    0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,\r
+    0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, \r
+    0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6,\r
+    0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6C2, 0x81383f05, 0x6963c5c8,\r
+    0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,\r
+    0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, \r
+    0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e,\r
+    0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426, \r
+    0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, \r
+    0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, \r
+    0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f,\r
+    0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, 0x7b5a41f0, 0xd37cfbad, \r
+    0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, \r
+    0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, \r
+    0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,\r
+    0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f, 0x6188b153, \r
+    0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, \r
+    0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, \r
+    0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755,\r
+    0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1, \r
+    0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,\r
+    0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, \r
+    0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79,\r
+    0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814C, 0x474d6ad7, 0x7c0c5e5c, \r
+    0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,\r
+    0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, \r
+    0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, \r
+    0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf\r
+  },\r
+  {\r
+    0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a,\r
+    0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, \r
+    0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, \r
+    0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,\r
+    0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, \r
+    0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, \r
+    0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083, \r
+    0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,\r
+    0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, \r
+    0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, \r
+    0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e, \r
+    0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,\r
+    0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, \r
+    0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, \r
+    0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064, \r
+    0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,\r
+    0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, \r
+    0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, \r
+    0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, \r
+    0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,\r
+    0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, \r
+    0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, \r
+    0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c, \r
+    0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,\r
+    0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, \r
+    0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, \r
+    0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b, \r
+    0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,\r
+    0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, \r
+    0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, \r
+    0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028, \r
+    0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,\r
+    0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6,\r
+    0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, \r
+    0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1, \r
+    0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,\r
+    0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, \r
+    0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, \r
+    0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, \r
+    0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,\r
+    0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, \r
+    0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, \r
+    0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1\r
+  },\r
+  {\r
+    0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b,\r
+    0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, \r
+    0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9,\r
+    0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,\r
+    0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd,\r
+    0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e,\r
+    0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264,\r
+    0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,\r
+    0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, \r
+    0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, \r
+    0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e, \r
+    0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,\r
+    0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, \r
+    0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, \r
+    0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e, \r
+    0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,\r
+    0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, \r
+    0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, \r
+    0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, \r
+    0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,\r
+    0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, \r
+    0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15,\r
+    0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788, \r
+    0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,\r
+    0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, \r
+    0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, \r
+    0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f, \r
+    0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,\r
+    0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, \r
+    0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, \r
+    0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9, \r
+    0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,\r
+    0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, \r
+    0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, \r
+    0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2, \r
+    0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,\r
+    0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, \r
+    0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, \r
+    0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, \r
+    0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,\r
+    0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, \r
+    0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, \r
+    0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783\r
+  },\r
+  { \r
+    0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, \r
+    0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, \r
+    0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, \r
+    0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,\r
+    0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, \r
+    0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, \r
+    0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801, \r
+    0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,\r
+    0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, \r
+    0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,\r
+    0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3, \r
+    0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,\r
+    0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c,\r
+    0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c,\r
+    0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16, \r
+    0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,\r
+    0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7,\r
+    0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, \r
+    0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, \r
+    0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,\r
+    0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, \r
+    0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, \r
+    0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff, \r
+    0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,\r
+    0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, \r
+    0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, \r
+    0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec, \r
+    0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,\r
+    0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, \r
+    0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, \r
+    0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6,\r
+    0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,\r
+    0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, \r
+    0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, \r
+    0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6, \r
+    0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,\r
+    0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2,\r
+    0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, \r
+    0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda,\r
+    0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,\r
+    0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6,\r
+    0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e,\r
+    0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2\r
+  }\r
+};\r
+\r
+#define f1(y,x,kr,km)           \\r
+    t  = rotl(km + x, kr);      \\r
+    u  = s_box[0][byte(t,3)];   \\r
+    u ^= s_box[1][byte(t,2)];   \\r
+    u -= s_box[2][byte(t,1)];   \\r
+    u += s_box[3][byte(t,0)];   \\r
+    y ^= u\r
+\r
+#define f2(y,x,kr,km)           \\r
+    t  = rotl(km ^ x, kr);      \\r
+    u  = s_box[0][byte(t,3)];   \\r
+    u -= s_box[1][byte(t,2)];   \\r
+    u += s_box[2][byte(t,1)];   \\r
+    u ^= s_box[3][byte(t,0)];   \\r
+    y ^= u\r
+\r
+#define f3(y,x,kr,km)           \\r
+    t  = rotl(km - x, kr);      \\r
+    u  = s_box[0][byte(t,3)];   \\r
+    u += s_box[1][byte(t,2)];   \\r
+    u ^= s_box[2][byte(t,1)];   \\r
+    u -= s_box[3][byte(t,0)];   \\r
+    y ^= u\r
+\r
+#define f_rnd(x,n)                              \\r
+    f1(x[2],x[3],l_key[n],    l_key[n + 4]);    \\r
+    f2(x[1],x[2],l_key[n + 1],l_key[n + 5]);    \\r
+    f3(x[0],x[1],l_key[n + 2],l_key[n + 6]);    \\r
+    f1(x[3],x[0],l_key[n + 3],l_key[n + 7])\r
+\r
+#define i_rnd(x, n)                             \\r
+    f1(x[3],x[0],l_key[n + 3],l_key[n + 7]);    \\r
+    f3(x[0],x[1],l_key[n + 2],l_key[n + 6]);    \\r
+    f2(x[1],x[2],l_key[n + 1],l_key[n + 5]);    \\r
+    f1(x[2],x[3],l_key[n],    l_key[n + 4])\r
+\r
+#define k_rnd(k,tr,tm)          \\r
+    f1(k[6],k[7],tr[0],tm[0]);  \\r
+    f2(k[5],k[6],tr[1],tm[1]);  \\r
+    f3(k[4],k[5],tr[2],tm[2]);  \\r
+    f1(k[3],k[4],tr[3],tm[3]);  \\r
+    f2(k[2],k[3],tr[4],tm[4]);  \\r
+    f3(k[1],k[2],tr[5],tm[5]);  \\r
+    f1(k[0],k[1],tr[6],tm[6]);  \\r
+    f2(k[7],k[0],tr[7],tm[7])\r
+\r
+/* initialise the key schedule from the user supplied key   */\r
+\r
+u4byte *cast_set_key(CastContext *ctx,\r
+                    const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u4byte  i, j, t, u, cm, cr, lk[8], tm[8], tr[8];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    for(i = 0; i < key_len / 32; ++i)\r
+\r
+        lk[i] = io_swap(in_key[i]);\r
+\r
+    for(; i < 8; ++i)\r
+\r
+        lk[i] = 0;\r
+\r
+    cm = 0x5a827999; cr = 19;\r
+\r
+    for(i = 0; i < 96; i += 8)\r
+    {\r
+        for(j = 0; j < 8; ++j)\r
+        {\r
+            tm[j] = cm; cm += 0x6ed9eba1;\r
+            tr[j] = cr; cr += 17;\r
+        }\r
+\r
+        k_rnd(lk, tr, tm);\r
+        \r
+        for(j = 0; j < 8; ++j)\r
+        {\r
+            tm[j] = cm; cm += 0x6ed9eba1;\r
+            tr[j] = cr; cr += 17;\r
+        }\r
+\r
+        k_rnd(lk, tr, tm);\r
+\r
+        l_key[i + 0] = lk[0]; l_key[i + 1] = lk[2];\r
+        l_key[i + 2] = lk[4]; l_key[i + 3] = lk[6];\r
+        l_key[i + 4] = lk[7]; l_key[i + 5] = lk[5];\r
+        l_key[i + 6] = lk[3]; l_key[i + 7] = lk[1];\r
+    }\r
+\r
+    return l_key;\r
+};\r
+\r
+/* encrypt a block of text  */\r
+\r
+void cast_encrypt(CastContext *ctx,\r
+                 const u4byte in_blk[4], u4byte out_blk[])\r
+{   \r
+    u4byte  t, u, blk[4];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+    blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+    f_rnd(blk,  0); f_rnd(blk,  8);\r
+    f_rnd(blk, 16); f_rnd(blk, 24);\r
+    f_rnd(blk, 32); f_rnd(blk, 40);\r
+    i_rnd(blk, 48); i_rnd(blk, 56);\r
+    i_rnd(blk, 64); i_rnd(blk, 72);\r
+    i_rnd(blk, 80); i_rnd(blk, 88);\r
+\r
+    out_blk[0] = io_swap(blk[0]); out_blk[1] = io_swap(blk[1]);\r
+    out_blk[2] = io_swap(blk[2]); out_blk[3] = io_swap(blk[3]);\r
+};\r
+\r
+/* decrypt a block of text  */\r
+\r
+void cast_decrypt(CastContext *ctx,\r
+                 const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  t, u, blk[4];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+    blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+    f_rnd(blk, 88); f_rnd(blk, 80);\r
+    f_rnd(blk, 72); f_rnd(blk, 64);\r
+    f_rnd(blk, 56); f_rnd(blk, 48);\r
+    i_rnd(blk, 40); i_rnd(blk, 32);\r
+    i_rnd(blk, 24); i_rnd(blk, 16);\r
+    i_rnd(blk,  8); i_rnd(blk,  0);\r
+\r
+    out_blk[0] = io_swap(blk[0]); out_blk[1] = io_swap(blk[1]);\r
+    out_blk[2] = io_swap(blk[2]); out_blk[3] = io_swap(blk[3]);\r
+};\r
+\r
diff --git a/lib/silccrypt/cast.h b/lib/silccrypt/cast.h
new file mode 100644 (file)
index 0000000..5958140
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+
+  cast.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef CAST_H
+#define CAST_H
+
+#include "cast_internal.h"
+
+/* 
+ * SILC Crypto API for Cast
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_cast_init(void *context, 
+                         const unsigned char *key, 
+                         unsigned int keylen)
+{
+  cast_set_key((CastContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+inline int silc_cast_set_string_as_key(void *context, 
+                                      const unsigned char *string,
+                                      unsigned int stringlen)
+{
+  /*  SilcHash hash;
+  unsigned char key[16];
+
+  silc_hash_alloc("md5", &hash);
+  hash->make_hash(hash, string, stringlen, key);
+
+  cast_set_key((CastContext *)context, (const u4byte *)key, sizeof(key));
+
+  silc_hash_free(hash);
+  memset(&key, 'F', sizeof(key));
+  */
+  return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+inline unsigned int silc_cast_context_len()
+{
+  return sizeof(CastContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_cast_encrypt_cbc(void *context,
+                                const unsigned char *src,
+                                unsigned char *dst,
+                                unsigned int len,
+                                unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  cast_encrypt((CastContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    cast_encrypt((CastContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_cast_decrypt_cbc(void *context,
+                                const unsigned char *src,
+                                unsigned char *dst,
+                                unsigned int len,
+                                unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  cast_decrypt((CastContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    cast_decrypt((CastContext *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/cast_internal.h b/lib/silccrypt/cast_internal.h
new file mode 100644 (file)
index 0000000..9ba8488
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+
+  cast_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CAST_INTERNAL_H
+#define CAST_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+  u4byte l_key[96];
+} CastContext;
+
+/* Prototypes */
+u4byte *cast_set_key(CastContext *ctx,
+                    const u4byte in_key[], const u4byte key_len);
+void cast_encrypt(CastContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[]);
+void cast_decrypt(CastContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/ciphers.h b/lib/silccrypt/ciphers.h
new file mode 100644 (file)
index 0000000..a7b8ece
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+
+  ciphers.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CIPHERS_H
+#define CIPHERS_H
+
+#include "none.h"
+#include "mars.h"
+#include "rc6.h"
+#include "twofish.h"
+
+#endif
diff --git a/lib/silccrypt/ciphers_def.h b/lib/silccrypt/ciphers_def.h
new file mode 100644 (file)
index 0000000..3db9825
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+
+  ciphers_def.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CIPHERS_DEF_H
+#define CIPHERS_DEF_H
+
+/* General definitions for algorithms */
+typedef unsigned char u1byte;
+typedef unsigned int u4byte;
+typedef unsigned int u32;
+
+#define rotr(x, nr) (((x) >> ((int)(nr))) | ((x) << (32 - (int)(nr))))
+#define rotl(x, nr) (((x) << ((int)(nr))) | ((x) >> (32 - (int)(nr))))
+#define byte(x, nr) ((x) >> (nr * 8) & 255)
+
+#endif
diff --git a/lib/silccrypt/crypton.c b/lib/silccrypt/crypton.c
new file mode 100644 (file)
index 0000000..dae0221
--- /dev/null
@@ -0,0 +1,298 @@
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         CRYPTON by Chae Hoon Lim of Future Systms Inc                */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+\r
+/* Timing data for CRYPTON (crypton.c)\r
+\r
+128 bit key:\r
+Key Setup:    531/1369 cycles (encrypt/decrypt)\r
+Encrypt:       474 cycles =    54.0 mbits/sec\r
+Decrypt:       474 cycles =    54.0 mbits/sec\r
+Mean:          474 cycles =    54.0 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    539/1381 cycles (encrypt/decrypt)\r
+Encrypt:       473 cycles =    54.1 mbits/sec\r
+Decrypt:       470 cycles =    54.5 mbits/sec\r
+Mean:          472 cycles =    54.3 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    552/1392 cycles (encrypt/decrypt)\r
+Encrypt:       469 cycles =    54.6 mbits/sec\r
+Decrypt:       483 cycles =    53.0 mbits/sec\r
+Mean:          476 cycles =    53.8 mbits/sec\r
+\r
+*/\r
+\r
+#include "silcincludes.h"\r
+#include "crypton.h"\r
+\r
+#define gamma_tau(x,b,m,p,q) \\r
+    (x) = (((u4byte)s_box[p][byte(b[0],m)]      ) | \\r
+           ((u4byte)s_box[q][byte(b[1],m)] <<  8) | \\r
+           ((u4byte)s_box[p][byte(b[2],m)] << 16) | \\r
+           ((u4byte)s_box[q][byte(b[3],m)] << 24))\r
+\r
+#define ma_0    0x3fcff3fc\r
+#define ma_1    0xfc3fcff3\r
+#define ma_2    0xf3fc3fcf\r
+#define ma_3    0xcff3fc3f\r
+\r
+#define mb_0    0xcffccffc\r
+#define mb_1    0xf33ff33f\r
+#define mb_2    0xfccffccf\r
+#define mb_3    0x3ff33ff3\r
+\r
+#define pi(b,n0,n1,n2,n3)       \\r
+    (((b)[0] & ma_##n0) ^       \\r
+     ((b)[1] & ma_##n1) ^       \\r
+     ((b)[2] & ma_##n2) ^       \\r
+     ((b)[3] & ma_##n3))\r
+\r
+#define phi_n(x,n0,n1,n2,n3)    \\r
+    (     (x)      & mb_##n0) ^ \\r
+    (rotl((x),  8) & mb_##n1) ^ \\r
+    (rotl((x), 16) & mb_##n2) ^ \\r
+    (rotl((x), 24) & mb_##n3)\r
+\r
+#define phi_00(x)   phi_n(x,0,1,2,3)\r
+#define phi_01(x)   phi_n(x,3,0,1,2)\r
+#define phi_02(x)   phi_n(x,2,3,0,1)\r
+#define phi_03(x)   phi_n(x,1,2,3,0)\r
+\r
+#define phi_10(x)   phi_n(x,3,0,1,2)\r
+#define phi_11(x)   phi_n(x,2,3,0,1)\r
+#define phi_12(x)   phi_n(x,1,2,3,0)\r
+#define phi_13(x)   phi_n(x,0,1,2,3)\r
+\r
+#define phi0(x,y)               \\r
+    (y)[0] = phi_00((x)[0]);    \\r
+    (y)[1] = phi_01((x)[1]);    \\r
+    (y)[2] = phi_02((x)[2]);    \\r
+    (y)[3] = phi_03((x)[3])\r
+\r
+#define phi1(x,y)               \\r
+    (y)[0] = phi_10((x)[0]);    \\r
+    (y)[1] = phi_11((x)[1]);    \\r
+    (y)[2] = phi_12((x)[2]);    \\r
+    (y)[3] = phi_13((x)[3])\r
+\r
+u1byte p_box[3][16] = \r
+{   { 15,  9,  6,  8,  9,  9,  4, 12,  6,  2,  6, 10,  1,  3,  5, 15 },\r
+    { 10, 15,  4,  7,  5,  2, 14,  6,  9,  3, 12,  8, 13,  1, 11,  0 },\r
+    {  0,  4,  8,  4,  2, 15,  8, 13,  1,  1, 15,  7,  2, 11, 14, 15 }\r
+};\r
+\r
+u4byte  tab_gen = 0;\r
+u1byte  s_box[2][256];\r
+u4byte  s_tab[4][256];\r
+\r
+void gen_tab(void)\r
+{   u4byte  i, xl, xr, yl, yr;\r
+\r
+    for(i = 0; i < 256; ++i)\r
+    {\r
+        xl = (i & 0xf0) >> 4; xr = i & 15;\r
+\r
+        yr = xr ^ p_box[1][xl ^ p_box[0][xr]];\r
+        yl = xl ^ p_box[0][xr] ^ p_box[2][yr];\r
+\r
+        yr |= (yl << 4); s_box[0][i] = (u1byte)yr; s_box[1][yr] = (u1byte)i;\r
+\r
+        xr = yr * 0x01010101; xl = i * 0x01010101;\r
+\r
+        s_tab[0][ i] = xr & 0x3fcff3fc;\r
+        s_tab[1][yr] = xl & 0xfc3fcff3;\r
+        s_tab[2][ i] = xr & 0xf3fc3fcf;\r
+        s_tab[3][yr] = xl & 0xcff3fc3f;\r
+    }\r
+};\r
+\r
+/* initialise the key schedule from the user supplied key   */\r
+\r
+u4byte  kp[4] = { 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f };\r
+u4byte  kq[4] = { 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 0xcbbb9d5d };\r
+\r
+#define h0_block(n,r0,r1)                           \\r
+    e_key[4 * n +  8] = rotl(e_key[4 * n + 0], r0); \\r
+    e_key[4 * n +  9] = rc ^ e_key[4 * n + 1];      \\r
+    e_key[4 * n + 10] = rotl(e_key[4 * n + 2], r1); \\r
+    e_key[4 * n + 11] = rc ^ e_key[4 * n + 3]\r
+\r
+#define h1_block(n,r0,r1)                           \\r
+    e_key[4 * n +  8] = rc ^ e_key[4 * n + 0];      \\r
+    e_key[4 * n +  9] = rotl(e_key[4 * n + 1], r0); \\r
+    e_key[4 * n + 10] = rc ^ e_key[4 * n + 2];      \\r
+    e_key[4 * n + 11] = rotl(e_key[4 * n + 3], r1)\r
+\r
+u4byte *crypton_set_key(CryptonContext *ctx,\r
+                       const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u4byte  i, rc, t0, t1, tmp[4];\r
+    u4byte *e_key = ctx->l_key + 52;\r
+    u4byte *d_key = ctx->l_key;\r
+\r
+    if(!tab_gen)\r
+    {\r
+        gen_tab(); tab_gen = 1;\r
+    }\r
+\r
+    e_key[2] = e_key[3] = e_key[6] = e_key[7] = 0;\r
+\r
+    switch((key_len + 63) / 64)\r
+    {\r
+    case 4: e_key[3] = in_key[6]; e_key[7] = in_key[7];\r
+    case 3: e_key[2] = in_key[4]; e_key[6] = in_key[5];\r
+    case 2: e_key[0] = in_key[0]; e_key[4] = in_key[1];\r
+            e_key[1] = in_key[2]; e_key[5] = in_key[3];\r
+    }\r
+\r
+    tmp[0] = pi(e_key, 0, 1, 2, 3) ^ kp[0];\r
+    tmp[1] = pi(e_key, 1, 2, 3, 0) ^ kp[1];\r
+    tmp[2] = pi(e_key, 2, 3, 0, 1) ^ kp[2];\r
+    tmp[3] = pi(e_key, 3, 0, 1, 2) ^ kp[3];\r
+    \r
+    gamma_tau(e_key[0], tmp, 0, 0, 1); \r
+    gamma_tau(e_key[1], tmp, 1, 1, 0);\r
+    gamma_tau(e_key[2], tmp, 2, 0, 1); \r
+    gamma_tau(e_key[3], tmp, 3, 1, 0);\r
+\r
+    tmp[0] = pi(e_key + 4, 1, 2, 3, 0) ^ kq[0]; \r
+    tmp[1] = pi(e_key + 4, 2, 3, 0, 1) ^ kq[1];\r
+    tmp[2] = pi(e_key + 4, 3, 0, 1, 2) ^ kq[2]; \r
+    tmp[3] = pi(e_key + 4, 0, 1, 2, 3) ^ kq[3];\r
+\r
+    gamma_tau(e_key[4], tmp, 0, 1, 0); \r
+    gamma_tau(e_key[5], tmp, 1, 0, 1);\r
+    gamma_tau(e_key[6], tmp, 2, 1, 0); \r
+    gamma_tau(e_key[7], tmp, 3, 0, 1);\r
+\r
+    t0 = e_key[0] ^ e_key[1] ^ e_key[2] ^ e_key[3];\r
+    t1 = e_key[4] ^ e_key[5] ^ e_key[6] ^ e_key[7];\r
+    \r
+    e_key[0] ^= t1; e_key[1] ^= t1;\r
+    e_key[2] ^= t1; e_key[3] ^= t1;\r
+    e_key[4] ^= t0; e_key[5] ^= t0;\r
+    e_key[6] ^= t0; e_key[7] ^= t0;\r
+\r
+    rc = 0x01010101; \r
+    h0_block( 0,  8, 16); h1_block(1, 16, 24); rc <<= 1;\r
+    h1_block( 2, 24,  8); h0_block(3,  8, 16); rc <<= 1;\r
+    h0_block( 4, 16, 24); h1_block(5, 24,  8); rc <<= 1;\r
+    h1_block( 6,  8, 16); h0_block(7, 16, 24); rc <<= 1;\r
+    h0_block( 8, 24,  8); h1_block(9,  8, 16); rc <<= 1;\r
+    h1_block(10, 16, 24);\r
+\r
+    for(i = 0; i < 13; ++i)\r
+    {\r
+        if(i & 1)\r
+        {\r
+            phi0(e_key + 4 * i, d_key + 48 - 4 * i);\r
+        }\r
+        else\r
+        {\r
+            phi1(e_key + 4 * i, d_key + 48 - 4 * i);\r
+        }\r
+    }\r
+\r
+    phi1(d_key + 48, d_key + 48);\r
+    phi1(e_key + 48, e_key + 48);\r
+\r
+    return l_key;\r
+};\r
+\r
+/* encrypt a block of text  */\r
+\r
+#define fr0(i,k)                                    \\r
+    b1[i] = s_tab[ (i)         ][byte(b0[0],i)] ^   \\r
+            s_tab[((i) + 1) & 3][byte(b0[1],i)] ^   \\r
+            s_tab[((i) + 2) & 3][byte(b0[2],i)] ^   \\r
+            s_tab[((i) + 3) & 3][byte(b0[3],i)] ^ (k)\r
+\r
+#define fr1(i,k)                                    \\r
+    b0[i] = s_tab[((i) + 1) & 3][byte(b1[0],i)] ^   \\r
+            s_tab[((i) + 2) & 3][byte(b1[1],i)] ^   \\r
+            s_tab[((i) + 3) & 3][byte(b1[2],i)] ^   \\r
+            s_tab[(i)          ][byte(b1[3],i)] ^ (k)\r
+\r
+#define f0_rnd(kp)                  \\r
+    fr0(0,(kp)[0]); fr0(1,(kp)[1]); \\r
+    fr0(2,(kp)[2]); fr0(3,(kp)[3])\r
+\r
+#define f1_rnd(kp)                  \\r
+    fr1(0,(kp)[0]); fr1(1,(kp)[1]); \\r
+    fr1(2,(kp)[2]); fr1(3,(kp)[3])\r
+\r
+void crypton_encrypt(CryptonContext *ctx,\r
+                    const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  b0[4], b1[4];\r
+    u4byte *e_key = ctx->l_key + 52;\r
+    u4byte *d_key = ctx->l_key;\r
+\r
+    b0[0] = in_blk[0] ^ e_key[0];\r
+    b0[1] = in_blk[1] ^ e_key[1];\r
+    b0[2] = in_blk[2] ^ e_key[2];\r
+    b0[3] = in_blk[3] ^ e_key[3];\r
+\r
+    f0_rnd(e_key +  4); f1_rnd(e_key +  8);\r
+    f0_rnd(e_key + 12); f1_rnd(e_key + 16);\r
+    f0_rnd(e_key + 20); f1_rnd(e_key + 24);\r
+    f0_rnd(e_key + 28); f1_rnd(e_key + 32);\r
+    f0_rnd(e_key + 36); f1_rnd(e_key + 40);\r
+    f0_rnd(e_key + 44);\r
+\r
+    gamma_tau(b0[0], b1, 0, 1, 0); \r
+    gamma_tau(b0[1], b1, 1, 0, 1); \r
+    gamma_tau(b0[2], b1, 2, 1, 0); \r
+    gamma_tau(b0[3], b1, 3, 0, 1);\r
+\r
+    out_blk[0] = b0[0] ^ e_key[48]; \r
+    out_blk[1] = b0[1] ^ e_key[49];\r
+    out_blk[2] = b0[2] ^ e_key[50]; \r
+    out_blk[3] = b0[3] ^ e_key[51];\r
+};\r
+\r
+/* decrypt a block of text  */\r
+\r
+void crypton_decrypt(CryptonContext *ctx,\r
+                    const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  b0[4], b1[4];\r
+    u4byte *e_key = ctx->l_key + 52;\r
+    u4byte *d_key = ctx->l_key;\r
+\r
+    b0[0] = in_blk[0] ^ d_key[0];\r
+    b0[1] = in_blk[1] ^ d_key[1];\r
+    b0[2] = in_blk[2] ^ d_key[2];\r
+    b0[3] = in_blk[3] ^ d_key[3];\r
+\r
+    f0_rnd(d_key +  4); f1_rnd(d_key +  8);\r
+    f0_rnd(d_key + 12); f1_rnd(d_key + 16);\r
+    f0_rnd(d_key + 20); f1_rnd(d_key + 24);\r
+    f0_rnd(d_key + 28); f1_rnd(d_key + 32);\r
+    f0_rnd(d_key + 36); f1_rnd(d_key + 40);\r
+    f0_rnd(d_key + 44);\r
+\r
+    gamma_tau(b0[0], b1, 0, 1, 0); \r
+    gamma_tau(b0[1], b1, 1, 0, 1); \r
+    gamma_tau(b0[2], b1, 2, 1, 0); \r
+    gamma_tau(b0[3], b1, 3, 0, 1);\r
+    \r
+    out_blk[0] = b0[0] ^ d_key[48]; \r
+    out_blk[1] = b0[1] ^ d_key[49];\r
+    out_blk[2] = b0[2] ^ d_key[50]; \r
+    out_blk[3] = b0[3] ^ d_key[51];\r
+};\r
diff --git a/lib/silccrypt/crypton.h b/lib/silccrypt/crypton.h
new file mode 100644 (file)
index 0000000..dc5a402
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+
+  crypton.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef CRYPTON_H
+#define CRYPTON_H
+
+#include "crypton_internal.h"
+
+/* 
+ * SILC Crypto API for Crypton
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(crypton)
+{
+  crypton_set_key((CryptonContext *)context, (unsigned int *)key, keylen);
+  return TRUE;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(crypton)
+{
+  SilcHash hash;
+  unsigned char key[16];
+
+  silc_hash_alloc("md5", &hash);
+  hash->make_hash(hash, string, stringlen, key);
+
+  crypton_set_key((CryptonContext *)context, key, sizeof(key));
+
+  silc_hash_free(hash);
+  memset(&key, 'F', sizeof(key));
+
+  return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(crypton)
+{
+  return sizeof(CryptonContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(crypton)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  crypton_encrypt((CryptonContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    crypton_encrypt((CryptonContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_DECRYPT_CBC(crypton)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  crypton_decrypt((CryptonContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    crypton_decrypt((CryptonContext *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return TRUE;
+}
+
+#endif
diff --git a/lib/silccrypt/crypton_internal.h b/lib/silccrypt/crypton_internal.h
new file mode 100644 (file)
index 0000000..3dd7976
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+
+  crypton_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1999 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CRYPTON_INTERNAL_H
+#define CRYPTON_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+  u4byte l_key[104];
+} CryptonContext;
+
+/* Prototypes */
+u4byte *crypton_set_key(CryptonContext *ctx,
+                       const u4byte in_key[], const u4byte key_len);
+void crypton_encrypt(CryptonContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[4]);
+void crypton_decrypt(CryptonContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/dfc.c b/lib/silccrypt/dfc.c
new file mode 100644 (file)
index 0000000..ba1449c
--- /dev/null
@@ -0,0 +1,410 @@
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         DFC designed by a team at CNRS and France Telecom            */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+/*                                                                      */\r
+/* My thanks go to Serge Vaudenay of the Ecole Normale Superieure       */\r
+/* for providing test vectors. This implementation has also been        */\r
+/* tested with an independent implementation by Dr Russell Bradford     */\r
+/* (Department of Mathematical Sciences, University of Bath, Bath,      */\r
+/* UK) and checks out.   My thanks go to Russell for his help in        */\r
+/* comparing our implementations and finding bugs (and for help in      */\r
+/* resolving 'endian' issues before test vectors became available).     */\r
+\r
+/* Timing data for DFC (dfc.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+Algorithm: dfc (dfc.c)\r
+\r
+128 bit key:\r
+Key Setup:    5222 cycles\r
+Encrypt:      1203 cycles =    21.3 mbits/sec\r
+Decrypt:      1244 cycles =    20.6 mbits/sec\r
+Mean:         1224 cycles =    20.9 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    5203 cycles\r
+Encrypt:      1288 cycles =    19.9 mbits/sec\r
+Decrypt:      1235 cycles =    20.7 mbits/sec\r
+Mean:         1262 cycles =    20.3 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    5177 cycles\r
+Encrypt:      1178 cycles =    21.7 mbits/sec\r
+Decrypt:      1226 cycles =    20.9 mbits/sec\r
+Mean:         1202 cycles =    21.3 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    5227 cycles\r
+Encrypt:      1247 cycles =    20.5 mbits/sec\r
+Decrypt:      1222 cycles =    20.9 mbits/sec\r
+Mean:         1235 cycles =    20.7 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    5252 cycles\r
+Encrypt:      1215 cycles =    21.1 mbits/sec\r
+Decrypt:      1265 cycles =    20.2 mbits/sec\r
+Mean:         1240 cycles =    20.6 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    5174 cycles\r
+Encrypt:      1247 cycles =    20.5 mbits/sec\r
+Decrypt:      1206 cycles =    21.2 mbits/sec\r
+Mean:         1227 cycles =    20.9 mbits/sec\r
+\r
+*/\r
+\r
+/* The EES string is as follows (the abstract contains an error in \r
+   the last line of this sequence which changes KC and KD):\r
+\r
+    0xb7e15162, 0x8aed2a6a, 0xbf715880, 0x9cf4f3c7, \r
+    0x62e7160f, 0x38b4da56, 0xa784d904, 0x5190cfef, \r
+    0x324e7738, 0x926cfbe5, 0xf4bf8d8d, 0x8c31d763,\r
+    0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
+\r
+    0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce, \r
+    0xd55c4d79, 0xfd5f24d6, 0x613c31c3, 0x839a2ddf,\r
+    0x8a9a276b, 0xcfbfa1c8, 0x77c56284, 0xdab79cd4, \r
+    0xc2b3293d, 0x20e9e5ea, 0xf02ac60a, 0xcc93ed87, \r
+\r
+    0x4422a52e, 0xcb238fee, 0xe5ab6add, 0x835fd1a0,\r
+    0x753d0a8f, 0x78e537d2, 0xb95bb79d, 0x8dcaec64, \r
+    0x2c1e9f23, 0xb829b5c2, 0x780bf387, 0x37df8bb3, \r
+    0x00d01334, 0xa0d0bd86, 0x45cbfa73, 0xa6160ffe,\r
+\r
+    0x393c48cb, 0xbbca060f, 0x0ff8ec6d, 0x31beb5cc, \r
+    0xeed7f2f0, 0xbb088017, 0x163bc60d, 0xf45a0ecb, \r
+    0x1bcd289b, 0x06cbbfea, 0x21ad08e1, 0x847f3f73,\r
+    0x78d56ced, 0x94640d6e, 0xf0d3d37b, 0xe67008e1, \r
+    \r
+    0x86d1bf27, 0x5b9b241d, 0xeb64749a, 0x47dfdfb9, \r
+\r
+    Where:\r
+\r
+    EES = RT(0) | RT(1) | ... | RT(63) | KD | KC\r
+\r
+    Note that the abstract describing DFC is written \r
+    in big endian notation with the most significant \r
+    digits of a sequence of digits placed at the low\r
+    index positions in arrays. This format is used\r
+    here and is only converted to machine format at\r
+    the point that maths is done on any numbers in \r
+    the round function.\r
+    \r
+    The key input is thus treated as an array of 32 \r
+    bit words numbered from 0..3, 0..5 or 0..7 \r
+    depending on key length.  The first (leftmost) \r
+    bit of this key string as defined in the DFC \r
+    abstract is the most significant bit of word 0 \r
+    and the rightmost bit of this string is the least \r
+    signicant bit of the highest numbered key word.\r
+\r
+    The input and output blocks for the cipher are \r
+    also treated as arrays of 32 bit words numbered\r
+    from 0..3.  The most significant bit of word 0 is\r
+    the 1st (leftmost) bit of the 128 bit input string \r
+    and the least significant bit of word 3 is the \r
+    last (rightmost) bit.\r
+    \r
+    Note that the inputs, the output and the key are\r
+    in Intel little endian format when BYTE_SWAP is \r
+    defined\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "dfc_internal.h"\r
+\r
+/* The following arrays are all stored in big endian    */\r
+/* format with 32 bit words at lower array positions    */\r
+/* being more significant in multi-word values          */\r
+\r
+u4byte rt64[64] = \r
+{\r
+    0xb7e15162, 0x8aed2a6a, 0xbf715880, 0x9cf4f3c7, \r
+    0x62e7160f, 0x38b4da56, 0xa784d904, 0x5190cfef, \r
+    0x324e7738, 0x926cfbe5, 0xf4bf8d8d, 0x8c31d763,\r
+    0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
+\r
+    0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce, \r
+    0xd55c4d79, 0xfd5f24d6, 0x613c31c3, 0x839a2ddf,\r
+    0x8a9a276b, 0xcfbfa1c8, 0x77c56284, 0xdab79cd4, \r
+    0xc2b3293d, 0x20e9e5ea, 0xf02ac60a, 0xcc93ed87, \r
+\r
+    0x4422a52e, 0xcb238fee, 0xe5ab6add, 0x835fd1a0,\r
+    0x753d0a8f, 0x78e537d2, 0xb95bb79d, 0x8dcaec64, \r
+    0x2c1e9f23, 0xb829b5c2, 0x780bf387, 0x37df8bb3, \r
+    0x00d01334, 0xa0d0bd86, 0x45cbfa73, 0xa6160ffe,\r
+\r
+    0x393c48cb, 0xbbca060f, 0x0ff8ec6d, 0x31beb5cc, \r
+    0xeed7f2f0, 0xbb088017, 0x163bc60d, 0xf45a0ecb, \r
+    0x1bcd289b, 0x06cbbfea, 0x21ad08e1, 0x847f3f73,\r
+    0x78d56ced, 0x94640d6e, 0xf0d3d37b, 0xe67008e1, \r
+};\r
+\r
+u4byte  kc = 0xeb64749a;\r
+\r
+u4byte  kd2[2] = \r
+{\r
+    0x86d1bf27, 0x5b9b241d  \r
+};\r
+\r
+u4byte  ka2[6] = \r
+{\r
+    0xb7e15162, 0x8aed2a6a, \r
+    0xbf715880, 0x9cf4f3c7, \r
+    0x62e7160f, 0x38b4da56, \r
+};\r
+\r
+u4byte  kb2[6] =\r
+{\r
+    0xa784d904, 0x5190cfef, \r
+    0x324e7738, 0x926cfbe5, \r
+    0xf4bf8d8d, 0x8c31d763,\r
+};\r
+\r
+u4byte  ks8[8] = \r
+{   0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
+    0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce,\r
+};\r
+\r
+#define lo(x)   ((x) & 0x0000ffff)\r
+#define hi(x)   ((x) >> 16)\r
+\r
+#define mult_64(r,x,y)                                          \\r
+    x0 = lo(x[1]); x1 = hi(x[1]); x2 = lo(x[0]); x3 = hi(x[0]); \\r
+    y0 = lo(y[1]); y1 = hi(y[1]); y2 = lo(y[0]); y3 = hi(y[0]); \\r
+    t0 = x0 * y0; r[0] = lo(t0); c = hi(t0);                    \\r
+    t0 = x0 * y1; t1 = x1 * y0; c += lo(t0) + lo(t1);           \\r
+    r[0] += (c << 16); c = hi(c) + hi(t0) + hi(t1);             \\r
+    t0 = x0 * y2; t1 = x1 * y1; t2 = x2 * y0;                   \\r
+    c += lo(t0) + lo(t1) + lo(t2); r[1] = lo(c);                \\r
+    c = hi(c) + hi(t0) + hi(t1) + hi(t2);                       \\r
+    t0 = x0 * y3; t1 = x1 * y2; t2 = x2 * y1; t3 = x3 * y0;     \\r
+    c += lo(t0) + lo(t1) + lo(t2) + lo(t3); r[1] += (c << 16);  \\r
+    c = hi(c) + hi(t0) + hi(t1) + hi(t2) + hi(t3);              \\r
+    t0 = x1 * y3; t1 = x2 * y2; t2 = x3 * y1;                   \\r
+    c += lo(t0) + lo(t1) + lo(t2); r[2] = lo(c);                \\r
+    c = hi(c) + hi(t0) + hi(t1) + hi(t2);                       \\r
+    t0 = x2 * y3; t1 = x3 * y2; c += lo(t0) + lo(t1);           \\r
+    r[2] += (c << 16); c = hi(c) + hi(t0) + hi(t1);             \\r
+    r[3] = c + x3 * y3\r
+\r
+#define add_64(r,hi,lo)     \\r
+    if((r[0] += lo) < lo)   \\r
+        if(!++r[1])         \\r
+            if(!++r[2])     \\r
+                ++r[3];     \\r
+    if((r[1] += hi) < hi)   \\r
+        if(!++r[2])         \\r
+            ++r[3]\r
+    \r
+#define mult_13(r)                  \\r
+    c = 13 * lo((r)[0]);            \\r
+    d = hi((r)[0]);                 \\r
+    (r)[0] = lo(c);                 \\r
+    c = hi(c) + 13 * d;             \\r
+    (r)[0] += (c << 16);            \\r
+    c = hi(c) + 13 * lo((r)[1]);    \\r
+    d = hi((r)[1]);                 \\r
+    (r)[1] = lo(c);                 \\r
+    c = hi(c) + 13 * d;             \\r
+    (r)[1] += (c << 16);            \\r
+    (r)[2] = hi(c)\r
+\r
+/* Where necessary this is where conversion from big endian to  */\r
+/* little endian format is performed.  Since all the maths is   */\r
+/* little endian care is needed when 64 bit blocks are being    */\r
+/* used to get them in the right order by reversing the order   */\r
+/* in which these are stored. This applies to the key array     */\r
+/* which gives the two values A and B and to the constant KD.   */\r
+/* Since the input and output blocks are big endian we also     */\r
+/* have to invert the order of the 32 bit words in the 64 bit   */\r
+/* blocks being processed.                                      */ \r
+\r
+void r_fun(u4byte outp[2], const u4byte inp[2], const u4byte key[4])\r
+{   u4byte  acc[5], x0, x1, x2, x3, y0, y1, y2, y3, t0, t1, t2, t3, c, d;\r
+\r
+    mult_64(acc, inp, key);  add_64(acc, key[2], key[3]);\r
+\r
+    /* we need the value in the accumulator mod 2^64 + 13 so if */\r
+    /* the accumulator value is hi * 2^64 + lo we need to find  */\r
+    /* a k value such that r = hi * 2^64 + lo - k * (2^64 + 13) */\r
+    /* is 0 <= r < 2^64 + 13.  We can see that k will be close  */\r
+    /* to hi in value - it may equal hi but will not be greater */\r
+    /* and we can let k = hi - e with e >= 0 so that r is given */\r
+    /* by r = e * (2^64 + 13) + lo - 13 * hi. If we compute the */\r
+    /* lo - 13 * hi value, the overflow into the top 64 bits of */\r
+    /* the accumulator has to be 'zeroed' by the e * (2^64 + 13)*/\r
+    /* term and this sets the e value (in fact such an overlow  */\r
+    /* is only removed when the lower word is higher than 12).  */\r
+\r
+    mult_13(acc + 2);   /* multiply top of accumulator by 13    */\r
+\r
+    /* calculate lo - 13 * hi in acc[0] and acc[1] with any     */\r
+    /* overflow into top 64 bits in c                           */\r
+\r
+    d = acc[0]; acc[0] -= acc[2]; c = (acc[0] > d ? 1 : 0);\r
+\r
+    d = acc[1]; acc[1] -= acc[3] + c;\r
+    c = (acc[1] > d ? 1 : (acc[1] == d ? c : 0));\r
+\r
+    c = 13 * (acc[4] + c);  /* overflow into top 64 bits of acc */\r
+\r
+    if(((acc[0] += c) < c) && !(++acc[1]))\r
+    {\r
+        if(acc[0] > 12)\r
+\r
+            acc[0] -= 13;\r
+    }\r
+\r
+    /* do the confusion permutation */\r
+\r
+    d = acc[1] ^ kc; c = acc[0] ^ rt64[acc[1] >> 26];  \r
+    \r
+    c += kd2[0] + ((d += kd2[1]) < kd2[1] ? 1 : 0);\r
+\r
+    outp[0] ^= c; outp[1] ^= d; \r
+};\r
+\r
+u4byte *dfc_set_key(DfcContext *ctx,\r
+                   const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u4byte  i, lk[32], rk[4];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    for(i = 0; i < key_len / 32; ++i)\r
+\r
+        lk[i] = io_swap(in_key[i]);\r
+\r
+    /* pad the key with the KS array            */\r
+\r
+    for(i = 0; i < 8 - key_len / 32; ++i)    /* K|KS */\r
+\r
+        lk[i + key_len / 32] = ks8[i];\r
+\r
+    /* do the reordering of the key parameters  */\r
+    /* the OAP[1]|OBP[1]|OAP[2]... sequence is  */\r
+    /* at lk[0]... and the other at lk[16]...   */\r
+    \r
+    lk[18] = lk[5]; lk[19] = lk[2]; /* EBP */ \r
+    lk[16] = lk[1]; lk[17] = lk[6]; /* EAP */\r
+    lk[ 2] = lk[4]; lk[ 3] = lk[3]; /* OBP */\r
+    lk[ 0] = lk[0]; lk[ 1] = lk[7]; /* OAP */\r
+\r
+    /* create other elements using KA and KB    */\r
+\r
+    for(i = 0; i < 6; i += 2)\r
+    {\r
+        lk[i + i +   4] = lk[ 0] ^ ka2[i];      /* OAP[i] ms */\r
+        lk[i + i +   5] = lk[ 1] ^ ka2[i + 1];  /* OAP[i] ls */\r
+        lk[i + i +   6] = lk[ 2] ^ kb2[i];      /* OBP[i] ms */\r
+        lk[i + i +   7] = lk[ 3] ^ kb2[i + 1];  /* OBP[i] ls */\r
+        lk[i + i +  20] = lk[16] ^ ka2[i];      /* EAP[i] ms */\r
+        lk[i + i +  21] = lk[17] ^ ka2[i + 1];  /* EAP[i] ls */\r
+        lk[i + i +  22] = lk[18] ^ kb2[i];      /* EBP[i] ms */\r
+        lk[i + i +  23] = lk[19] ^ kb2[i + 1];  /* EBP[i] ls */\r
+    }\r
+\r
+    rk[0] = rk[1] = rk[2] = rk[3] = 0;\r
+\r
+    /* do the 4 round key mixing encryption     */\r
+\r
+    for(i = 0; i < 32; i += 8)\r
+    {\r
+        r_fun(rk, rk + 2, lk);      /*  R2|R1   */\r
+        r_fun(rk + 2, rk, lk +  4); /*  R2|R3   */\r
+        r_fun(rk, rk + 2, lk +  8); /*  R4|R3   */\r
+        r_fun(rk + 2, rk, lk + 12); /*  R4|R5   */\r
+\r
+        /* keep key in big endian format with   */\r
+        /* the most significant 32 bit words    */\r
+        /* first (lowest) in the key schedule   */\r
+        /* - note that the upper and lower 64   */\r
+        /* bit blocks are in inverse order at   */\r
+        /* this point in the loop               */\r
+\r
+        l_key[i + 0] = rk[2]; l_key[i + 1] = rk[3]; \r
+        l_key[i + 2] = rk[0]; l_key[i + 3] = rk[1]; \r
+\r
+        r_fun(rk + 2, rk, lk + 16); /*  R1|R2   */\r
+        r_fun(rk, rk + 2, lk + 20); /*  R3|R2   */\r
+        r_fun(rk + 2, rk, lk + 24); /*  R3|R4   */  \r
+        r_fun(rk, rk + 2, lk + 28); /*  R5|R4   */\r
+\r
+        l_key[i + 4] = rk[0]; l_key[i + 5] = rk[1]; \r
+        l_key[i + 6] = rk[2]; l_key[i + 7] = rk[3];\r
+    }\r
+    \r
+    return l_key;\r
+};\r
+\r
+void dfc_encrypt(DfcContext *ctx,\r
+                const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  blk[4];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    /* the input/output format is big endian -  */\r
+    /* any reversals needed are performed when  */\r
+    /* maths is done in the round function      */\r
+\r
+    blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+    blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+    r_fun(blk, blk + 2, l_key +  0); /*  R2|R1  */ \r
+    r_fun(blk + 2, blk, l_key +  4); /*  R2|R3  */\r
+    r_fun(blk, blk + 2, l_key +  8); /*  R4|R3  */\r
+    r_fun(blk + 2, blk, l_key + 12); /*  R4|R5  */\r
+    r_fun(blk, blk + 2, l_key + 16); /*  R6|R5  */\r
+    r_fun(blk + 2, blk, l_key + 20); /*  R6|R7  */\r
+    r_fun(blk, blk + 2, l_key + 24); /*  R8|R7  */\r
+    r_fun(blk + 2, blk, l_key + 28); /*  R8|R9  */\r
+\r
+    /* swap order to obtain the result R9|R8    */\r
+\r
+    out_blk[0] = io_swap(blk[2]); out_blk[1] = io_swap(blk[3]);\r
+    out_blk[2] = io_swap(blk[0]); out_blk[3] = io_swap(blk[1]);\r
+};\r
+\r
+void dfc_decrypt(DfcContext *ctx,\r
+                const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  blk[4];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    /* the input/output format is big endian -  */\r
+    /* any reversals needed are performed when  */\r
+    /* maths is done in the round function      */\r
+\r
+    blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
+    blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
+\r
+    r_fun(blk, blk + 2, l_key + 28); /*  R7|R8  */\r
+    r_fun(blk + 2, blk, l_key + 24); /*  R7|R6  */\r
+    r_fun(blk, blk + 2, l_key + 20); /*  R5|R6  */\r
+    r_fun(blk + 2, blk, l_key + 16); /*  R5|R4  */\r
+    r_fun(blk, blk + 2, l_key + 12); /*  R3|R4  */\r
+    r_fun(blk + 2, blk, l_key +  8); /*  R3|R2  */\r
+    r_fun(blk, blk + 2, l_key +  4); /*  R1|R2  */\r
+    r_fun(blk + 2, blk, l_key     ); /*  R1|R0  */ \r
+\r
+    /* swap order to obtain the result R1|R0    */\r
+\r
+    out_blk[0] = io_swap(blk[2]); out_blk[1] = io_swap(blk[3]);\r
+    out_blk[2] = io_swap(blk[0]); out_blk[3] = io_swap(blk[1]);   \r
+};\r
diff --git a/lib/silccrypt/dfc.h b/lib/silccrypt/dfc.h
new file mode 100644 (file)
index 0000000..97c25d5
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+
+  dfc.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef DFC_H
+#define DFC_H
+
+#include "dfc_internal.h"
+
+/* 
+ * SILC Crypto API for DFC
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_dfc_init(void *context, 
+                        const unsigned char *key, 
+                        unsigned int keylen)
+{
+  dfc_set_key((DfcContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+inline int silc_dfc_set_string_as_key(void *context, 
+                                     const unsigned char *string,
+                                     unsigned int keylen)
+{
+  /*  SilcHash hash;
+  unsigned char key[16];
+
+  silc_hash_alloc("md5", &hash);
+  hash->make_hash(hash, string, stringlen, key);
+
+  dfc_set_key((DfcContext *)context, key, sizeof(key));
+
+  silc_hash_free(hash);
+  memset(&key, 'F', sizeof(key));
+  */
+  return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+inline unsigned int silc_dfc_context_len()
+{
+  return sizeof(DfcContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_dfc_encrypt_cbc(void *context,
+                               const unsigned char *src,
+                               unsigned char *dst,
+                               unsigned int len,
+                               unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  dfc_encrypt((DfcContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    dfc_encrypt((DfcContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_dfc_decrypt_cbc(void *context,
+                               const unsigned char *src,
+                               unsigned char *dst,
+                               unsigned int len,
+                               unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  dfc_decrypt((DfcContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    dfc_decrypt((DfcContext *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/dfc_internal.h b/lib/silccrypt/dfc_internal.h
new file mode 100644 (file)
index 0000000..5ab4e0a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+
+  dfc_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef DFC_INTERNAL_H
+#define DFC_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+  u4byte l_key[32];
+} DfcContext;
+
+/* Prototypes */
+u4byte *dfc_set_key(DfcContext *ctx,
+                   const u4byte in_key[], const u4byte key_len);
+void dfc_encrypt(DfcContext *ctx,
+                const u4byte in_blk[4], u4byte out_blk[4]);
+void dfc_decrypt(DfcContext *ctx,
+                const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/e2.c b/lib/silccrypt/e2.c
new file mode 100644 (file)
index 0000000..8cc8acd
--- /dev/null
@@ -0,0 +1,378 @@
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         E2 by Nippon Telegraph and Telephone (NTT) Japan             */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+/*                                                                      */\r
+/* In accordance with the wishes of NTT this implementation is made     */\r
+/* available for academic and study purposes only.   I gratefully       */\r
+/* acknowledge the contributions made by Kazumaro Aoki of NTT Japan     */\r
+/* for ways to increase the speed of this implementation.               */\r
+\r
+/* Timing data for E2 (e28.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    9473 cycles\r
+Encrypt:       687 cycles =    37.3 mbits/sec\r
+Decrypt:       691 cycles =    37.0 mbits/sec\r
+Mean:          689 cycles =    37.2 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    9540 cycles\r
+Encrypt:       696 cycles =    36.8 mbits/sec\r
+Decrypt:       693 cycles =    36.9 mbits/sec\r
+Mean:          695 cycles =    36.9 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    9913 cycles\r
+Encrypt:       691 cycles =    37.0 mbits/sec\r
+Decrypt:       706 cycles =    36.3 mbits/sec\r
+Mean:          699 cycles =    36.6 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    9598 cycles\r
+Encrypt:       730 cycles =    35.1 mbits/sec\r
+Decrypt:       723 cycles =    35.4 mbits/sec\r
+Mean:          727 cycles =    35.2 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    9393 cycles\r
+Encrypt:       730 cycles =    35.1 mbits/sec\r
+Decrypt:       720 cycles =    35.6 mbits/sec\r
+Mean:          725 cycles =    35.3 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    9720 cycles\r
+Encrypt:       727 cycles =    35.2 mbits/sec\r
+Decrypt:       721 cycles =    35.5 mbits/sec\r
+Mean:          724 cycles =    35.4 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "e2_internal.h"\r
+\r
+u1byte  s_box[] =\r
+{\r
+ 0xe1, 0x42, 0x3e, 0x81, 0x4e, 0x17, 0x9e, 0xfd, 0xb4, 0x3f, 0x2c, 0xda,\r
+ 0x31, 0x1e, 0xe0, 0x41, 0xcc, 0xf3, 0x82, 0x7d, 0x7c, 0x12, 0x8e, 0xbb,\r
+ 0xe4, 0x58, 0x15, 0xd5, 0x6f, 0xe9, 0x4c, 0x4b, 0x35, 0x7b, 0x5a, 0x9a,\r
+ 0x90, 0x45, 0xbc, 0xf8, 0x79, 0xd6, 0x1b, 0x88, 0x02, 0xab, 0xcf, 0x64,\r
+ 0x09, 0x0c, 0xf0, 0x01, 0xa4, 0xb0, 0xf6, 0x93, 0x43, 0x63, 0x86, 0xdc,\r
+ 0x11, 0xa5, 0x83, 0x8b, 0xc9, 0xd0, 0x19, 0x95, 0x6a, 0xa1, 0x5c, 0x24,\r
+ 0x6e, 0x50, 0x21, 0x80, 0x2f, 0xe7, 0x53, 0x0f, 0x91, 0x22, 0x04, 0xed,\r
+ 0xa6, 0x48, 0x49, 0x67, 0xec, 0xf7, 0xc0, 0x39, 0xce, 0xf2, 0x2d, 0xbe,\r
+ 0x5d, 0x1c, 0xe3, 0x87, 0x07, 0x0d, 0x7a, 0xf4, 0xfb, 0x32, 0xf5, 0x8c,\r
+ 0xdb, 0x8f, 0x25, 0x96, 0xa8, 0xea, 0xcd, 0x33, 0x65, 0x54, 0x06, 0x8d,\r
+ 0x89, 0x0a, 0x5e, 0xd9, 0x16, 0x0e, 0x71, 0x6c, 0x0b, 0xff, 0x60, 0xd2,\r
+ 0x2e, 0xd3, 0xc8, 0x55, 0xc2, 0x23, 0xb7, 0x74, 0xe2, 0x9b, 0xdf, 0x77,\r
+ 0x2b, 0xb9, 0x3c, 0x62, 0x13, 0xe5, 0x94, 0x34, 0xb1, 0x27, 0x84, 0x9f,\r
+ 0xd7, 0x51, 0x00, 0x61, 0xad, 0x85, 0x73, 0x03, 0x08, 0x40, 0xef, 0x68,\r
+ 0xfe, 0x97, 0x1f, 0xde, 0xaf, 0x66, 0xe8, 0xb8, 0xae, 0xbd, 0xb3, 0xeb,\r
+ 0xc6, 0x6b, 0x47, 0xa9, 0xd8, 0xa7, 0x72, 0xee, 0x1d, 0x7e, 0xaa, 0xb6,\r
+ 0x75, 0xcb, 0xd4, 0x30, 0x69, 0x20, 0x7f, 0x37, 0x5b, 0x9d, 0x78, 0xa3,\r
+ 0xf1, 0x76, 0xfa, 0x05, 0x3d, 0x3a, 0x44, 0x57, 0x3b, 0xca, 0xc7, 0x8a,\r
+ 0x18, 0x46, 0x9c, 0xbf, 0xba, 0x38, 0x56, 0x1a, 0x92, 0x4d, 0x26, 0x29,\r
+ 0xa2, 0x98, 0x10, 0x99, 0x70, 0xa0, 0xc5, 0x28, 0xc1, 0x6d, 0x14, 0xac,\r
+ 0xf9, 0x5f, 0x4f, 0xc4, 0xc3, 0xd1, 0xfc, 0xdd, 0xb2, 0x59, 0xe6, 0xb5,\r
+ 0x36, 0x52, 0x4a, 0x2a\r
+};\r
+\r
+u4byte  l_box[4][256];\r
+u4byte  lb_init = 0;\r
+\r
+#define v_0     0x67452301\r
+#define v_1     0xefcdab89\r
+\r
+/* s_fun(s_fun(s_fun(v)))           */\r
+\r
+#define k2_0    0x30d32e58\r
+#define k2_1    0xb89e4984\r
+\r
+/* s_fun(s_fun(s_fun(s_fun(v))))    */\r
+\r
+#define k3_0    0x0957cfec\r
+#define k3_1    0xd800502e\r
+\r
+#define bp_fun(a,b,c,d,e,f,g,h)     \\r
+    u = (e ^ g) & 0x00ffff00;       \\r
+    v = (f ^ h) & 0x0000ffff;       \\r
+    a = e ^ u; c = g ^ u;           \\r
+    b = f ^ v; d = h ^ v\r
+\r
+#define ibp_fun(a,b,c,d,e,f,g,h)    \\r
+    u = (e ^ g) & 0xff0000ff;       \\r
+    v = (f ^ h) & 0xffff0000;       \\r
+    a = e ^ u; c = g ^ u;           \\r
+    b = f ^ v; d = h ^ v\r
+\r
+#define bp2_fun(x,y)                \\r
+    w = (x ^ y) & 0x00ff00ff;       \\r
+    x ^= w; y ^= w;                 \\r
+\r
+#define s_fun(x,y)          \\r
+    p = x; q = x >> 8;      \\r
+    r = y; s = y >> 8;      \\r
+    x  = l_box[0][r & 255]; \\r
+    y  = l_box[0][p & 255]; \\r
+    p >>=  16; r >>=  16;   \\r
+    x |= l_box[1][q & 255]; \\r
+    y |= l_box[1][s & 255]; \\r
+    x |= l_box[2][r & 255]; \\r
+    y |= l_box[2][p & 255]; \\r
+    x |= l_box[3][p >> 8];  \\r
+    y |= l_box[3][r >> 8]\r
+\r
+#define sx_fun(x,y)         \\r
+    p = x >>  8;            \\r
+    q = x >> 16;            \\r
+    x  = l_box[0][x & 255]; \\r
+    x |= l_box[1][p & 255]; \\r
+    x |= l_box[2][q & 255]; \\r
+    x |= l_box[3][q >> 8];  \\r
+    p = y >>  8;            \\r
+    q = y >> 16;            \\r
+    y  = l_box[0][y & 255]; \\r
+    y |= l_box[1][p & 255]; \\r
+    y |= l_box[2][q & 255]; \\r
+    y |= l_box[3][q >> 8]\r
+\r
+#define spx_fun(x,y)        \\r
+    sx_fun(x,y);            \\r
+    y ^= x;                 \\r
+    x ^= rotr(y, 16);       \\r
+    y ^= rotr(x, 8);        \\r
+    x ^= y\r
+\r
+#define sp_fun(x,y)         \\r
+    s_fun(x,y);             \\r
+    y ^= x;                 \\r
+    x ^= rotr(y, 16);       \\r
+    y ^= rotr(x, 8);        \\r
+    x ^= y\r
+\r
+#define sr_fun(x,y)         \\r
+    p = x; q = x >> 8;      \\r
+    r = y; s = y >> 8;      \\r
+    y  = l_box[1][p & 255]; \\r
+    x  = l_box[1][r & 255]; \\r
+    p >>= 16; r >>= 16;     \\r
+    x |= l_box[2][q & 255]; \\r
+    y |= l_box[2][s & 255]; \\r
+    y |= l_box[3][p & 255]; \\r
+    x |= l_box[3][r & 255]; \\r
+    x |= l_box[0][r >>  8]; \\r
+    y |= l_box[0][p >>  8]\r
+\r
+#define f_fun(a,b,c,d,k)            \\r
+    u = c ^ *(k); v = d ^ *(k + 1); \\r
+    sp_fun(u, v);                   \\r
+    u ^= *(k + 2); v ^= *(k + 3);   \\r
+    sr_fun(u, v);                   \\r
+    a ^= v;                         \\r
+    b ^= u\r
+\r
+#define byte_adr(x,n)   *(((u1byte*)&x)+n)\r
+\r
+u4byte  mod_inv(u4byte x)\r
+{   u4byte  y1, y2, a, b, q;\r
+\r
+    y1 = ~((-x) / x); y2 = 1;\r
+\r
+    a = x; b = y1 * x;\r
+\r
+    for(;;)\r
+    {\r
+        q = a / b; \r
+        \r
+        if((a -= q * b) == 0)\r
+\r
+            return (x * y1 == 1 ? y1 : -y1);\r
+        \r
+        y2 -= q * y1;\r
+\r
+        q = b / a; \r
+        \r
+        if((b -= q * a) == 0)\r
+        \r
+            return (x * y2 == 1 ? y2 : -y2);\r
+\r
+        y1 -= q * y2;\r
+    }\r
+};\r
+\r
+void g_fun(u4byte y[8], u4byte l[8], u4byte v[2])\r
+{   u4byte  p,q;\r
+\r
+    spx_fun(y[0], y[1]); spx_fun(v[0], v[1]); \r
+    l[0] = v[0] ^= y[0]; l[1] = v[1] ^= y[1];\r
+\r
+    spx_fun(y[2], y[3]); spx_fun(v[0], v[1]); \r
+    l[2] = v[0] ^= y[2]; l[3] = v[1] ^= y[3];\r
+\r
+    spx_fun(y[4], y[5]); spx_fun(v[0], v[1]);  \r
+    l[4] = v[0] ^= y[4]; l[5] = v[1] ^= y[5];\r
+\r
+    spx_fun(y[6], y[7]); spx_fun(v[0], v[1]); \r
+    l[6] = v[0] ^= y[6]; l[7] = v[1] ^= y[7];\r
+};\r
+\r
+u4byte *e2_set_key(E2Context *ctx,\r
+                  const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u4byte  lk[8], v[2], lout[8];\r
+    u4byte  i, j, k, w;\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    if(!lb_init)\r
+    {\r
+        for(i = 0; i < 256; ++i)\r
+        {\r
+            l_box[0][i] = ((u4byte)(s_box[i]));\r
+            l_box[1][i] = ((u4byte)(s_box[i])) <<  8;\r
+            l_box[2][i] = ((u4byte)(s_box[i])) << 16;\r
+            l_box[3][i] = ((u4byte)(s_box[i])) << 24;\r
+        }\r
+\r
+        lb_init = 1;\r
+    }\r
+\r
+    v[0] = bswap(v_0); v[1] = bswap(v_1);\r
+\r
+    lk[0] = io_swap(in_key[0]); lk[1] = io_swap(in_key[1]);\r
+    lk[2] = io_swap(in_key[2]); lk[3] = io_swap(in_key[3]);\r
+\r
+    lk[4] = io_swap(key_len > 128 ? in_key[4] : k2_0);\r
+    lk[5] = io_swap(key_len > 128 ? in_key[5] : k2_1);\r
+\r
+    lk[6] = io_swap(key_len > 192 ? in_key[6] : k3_0);\r
+    lk[7] = io_swap(key_len > 192 ? in_key[7] : k3_1);\r
+\r
+    g_fun(lk, lout, v);\r
+\r
+    for(i = 0; i < 8; ++i)\r
+    {\r
+        g_fun(lk, lout, v);\r
+\r
+        for(j = 0; j < 4; ++j)\r
+        {\r
+            // this is complex because of a byte swap in each 32 bit output word\r
+\r
+            k = 2 * (48 - 16 * j + 2 * (i / 2) - i % 2);\r
+\r
+            ((u1byte*)l_key)[k + 3]   = ((u1byte*)lout)[j];\r
+            ((u1byte*)l_key)[k + 2]   = ((u1byte*)lout)[j + 16];\r
+\r
+            ((u1byte*)l_key)[k + 19]  = ((u1byte*)lout)[j +  8];\r
+            ((u1byte*)l_key)[k + 18]  = ((u1byte*)lout)[j + 24];\r
+\r
+            ((u1byte*)l_key)[k + 131] = ((u1byte*)lout)[j +  4];\r
+            ((u1byte*)l_key)[k + 130] = ((u1byte*)lout)[j + 20];\r
+\r
+            ((u1byte*)l_key)[k + 147] = ((u1byte*)lout)[j + 12];\r
+            ((u1byte*)l_key)[k + 146] = ((u1byte*)lout)[j + 28];\r
+        }\r
+    }\r
+\r
+    for(i = 52; i < 60; ++i)\r
+    {\r
+        l_key[i] |= 1; l_key[i + 12] = mod_inv(l_key[i]);\r
+    }\r
+\r
+    for(i = 0; i < 48; i += 4)\r
+    {\r
+        bp2_fun(l_key[i], l_key[i + 1]);\r
+    }\r
+\r
+    return (u4byte*)&l_key;\r
+};\r
+\r
+void e2_encrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte      a,b,c,d,p,q,r,s,u,v;\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    p = io_swap(in_blk[0]); q = io_swap(in_blk[1]); \r
+    r = io_swap(in_blk[2]); s = io_swap(in_blk[3]);\r
+    \r
+    p ^= l_key[48]; q ^= l_key[49]; r ^= l_key[50]; s ^= l_key[51]; \r
+    p *= l_key[52]; q *= l_key[53]; r *= l_key[54]; s *= l_key[55];\r
+\r
+    bp_fun(a, b, c, d, p, q, r, s);\r
+\r
+    f_fun(a, b, c, d, l_key);\r
+    f_fun(c, d, a, b, l_key +  4);\r
+    f_fun(a, b, c, d, l_key +  8);\r
+    f_fun(c, d, a, b, l_key + 12);\r
+    f_fun(a, b, c, d, l_key + 16);\r
+    f_fun(c, d, a, b, l_key + 20);\r
+    f_fun(a, b, c, d, l_key + 24);\r
+    f_fun(c, d, a, b, l_key + 28);\r
+    f_fun(a, b, c, d, l_key + 32);\r
+    f_fun(c, d, a, b, l_key + 36);\r
+    f_fun(a, b, c, d, l_key + 40);\r
+    f_fun(c, d, a, b, l_key + 44);\r
+\r
+    ibp_fun(p, q, r, s, a, b, c, d);        \r
+    \r
+    p *= l_key[68]; q *= l_key[69]; r *= l_key[70]; s *= l_key[71]; \r
+    p ^= l_key[60]; q ^= l_key[61]; r ^= l_key[62]; s ^= l_key[63];\r
+    \r
+    out_blk[0] = io_swap(p); out_blk[1] = io_swap(q);\r
+    out_blk[2] = io_swap(r); out_blk[3] = io_swap(s);\r
+};\r
+\r
+void e2_decrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte      a,b,c,d,p,q,r,s,u,v;\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    p = io_swap(in_blk[0]); q = io_swap(in_blk[1]); \r
+    r = io_swap(in_blk[2]); s = io_swap(in_blk[3]);\r
+\r
+    p ^= l_key[60]; q ^= l_key[61]; r ^= l_key[62]; s ^= l_key[63];\r
+    p *= l_key[56]; q *= l_key[57]; r *= l_key[58]; s *= l_key[59];\r
+\r
+    bp_fun(a, b, c, d, p, q, r, s);\r
+\r
+    f_fun(a, b, c, d, l_key + 44);\r
+    f_fun(c, d, a, b, l_key + 40);\r
+\r
+    f_fun(a, b, c, d, l_key + 36);\r
+    f_fun(c, d, a, b, l_key + 32);\r
+\r
+    f_fun(a, b, c, d, l_key + 28);\r
+    f_fun(c, d, a, b, l_key + 24);\r
+    \r
+    f_fun(a, b, c, d, l_key + 20);\r
+    f_fun(c, d, a, b, l_key + 16);\r
+\r
+    f_fun(a, b, c, d, l_key + 12);\r
+    f_fun(c, d, a, b, l_key +  8);\r
+    \r
+    f_fun(a, b, c, d, l_key +  4);\r
+    f_fun(c, d, a, b, l_key);\r
+\r
+    ibp_fun(p, q, r, s, a, b, c, d);        \r
+    \r
+    p *= l_key[64]; q *= l_key[65]; r *= l_key[66]; s *= l_key[67]; \r
+    p ^= l_key[48]; q ^= l_key[49]; r ^= l_key[50]; s ^= l_key[51];\r
+\r
+    out_blk[0] = io_swap(p); out_blk[1] = io_swap(q); \r
+    out_blk[2] = io_swap(r); out_blk[3] = io_swap(s);\r
+};\r
diff --git a/lib/silccrypt/e2.h b/lib/silccrypt/e2.h
new file mode 100644 (file)
index 0000000..173af14
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+
+  e2.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef E2_H
+#define E2_H
+
+#include "e2_internal.h"
+
+/* 
+ * SILC Crypto API for E2
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_e2_init(void *context, 
+                       const unsigned char *key, 
+                       size_t keylen)
+{
+  e2_set_key((E2Context *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+inline int silc_e2_set_string_as_key(void *context, 
+                                    const unsigned char *string,
+                                    size_t keylen)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_e2_context_len()
+{
+  return sizeof(E2Context);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_e2_encrypt_cbc(void *context,
+                              const unsigned char *src,
+                              unsigned char *dst,
+                              size_t len,
+                              unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  e2_encrypt((E2Context *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    e2_encrypt((E2Context *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_e2_decrypt_cbc(void *context,
+                              const unsigned char *src,
+                              unsigned char *dst,
+                              size_t len,
+                              unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  e2_decrypt((E2Context *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    e2_decrypt((E2Context *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/e2_internal.h b/lib/silccrypt/e2_internal.h
new file mode 100644 (file)
index 0000000..446b0a1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+
+  e2_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef E2_INTERNAL_H
+#define E2_INTERNAL_H
+
+typedef struct {
+  u4byte l_key[72];
+} E2Context;
+
+/* Prototypes */
+u4byte *e2_set_key(E2Context *ctx,
+                  const u4byte in_key[], const u4byte key_len);
+void e2_encrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4]);
+void e2_decrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/loki.c b/lib/silccrypt/loki.c
new file mode 100644 (file)
index 0000000..c326f27
--- /dev/null
@@ -0,0 +1,287 @@
+/* Modified for SILC. -Pekka */\r
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         LOKI97 by Brown and Pieprzyk                                 */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+\r
+/* Timing data for LOKI97 (loki.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    7430 cycles\r
+Encrypt:      2134 cycles =    12.0 mbits/sec\r
+Decrypt:      2192 cycles =    11.7 mbits/sec\r
+Mean:         2163 cycles =    11.8 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    7303 cycles\r
+Encrypt:      2138 cycles =    12.0 mbits/sec\r
+Decrypt:      2189 cycles =    11.7 mbits/sec\r
+Mean:         2164 cycles =    11.8 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    7166 cycles\r
+Encrypt:      2131 cycles =    12.0 mbits/sec\r
+Decrypt:      2184 cycles =    11.7 mbits/sec\r
+Mean:         2158 cycles =    11.9 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    7582 cycles\r
+Encrypt:      2174 cycles =    11.8 mbits/sec\r
+Decrypt:      2235 cycles =    11.5 mbits/sec\r
+Mean:         2205 cycles =    11.6 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    7477 cycles\r
+Encrypt:      2167 cycles =    11.8 mbits/sec\r
+Decrypt:      2223 cycles =    11.5 mbits/sec\r
+Mean:         2195 cycles =    11.7 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    7365 cycles\r
+Encrypt:      2177 cycles =    11.8 mbits/sec\r
+Decrypt:      2194 cycles =    11.7 mbits/sec\r
+Mean:         2186 cycles =    11.7 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "loki_internal.h"\r
+\r
+#define S1_SIZE     13\r
+#define S1_LEN      (1 << S1_SIZE)\r
+#define S1_MASK     (S1_LEN - 1)\r
+#define S1_HMASK    (S1_MASK & ~0xff)\r
+#define S1_POLY     0x2911\r
+\r
+#define S2_SIZE     11\r
+#define S2_LEN      (1 << S2_SIZE)\r
+#define S2_MASK     (S2_LEN - 1)\r
+#define S2_HMASK    (S2_MASK & ~0xff)\r
+#define S2_POLY     0x0aa7\r
+\r
+#define io_swap(x)  ((x))\r
+\r
+u4byte  delta[2] = { 0x7f4a7c15, 0x9e3779b9 };\r
+\r
+u1byte  sb1[S1_LEN];    // GF(2^11) S box\r
+u1byte  sb2[S2_LEN];    // GF(2^11) S box\r
+u4byte  prm[256][2];\r
+u4byte  init_done = 0;\r
+\r
+#define add_eq(x,y)    (x)[1] += (y)[1] + (((x)[0] += (y)[0]) < (y)[0] ? 1 : x)\r
+#define sub_eq(x,y)    xs = (x)[0]; (x)[1] -= (y)[1] + (((x)[0] -= (y)[0]) > xs ? 1 : 0)   \r
+\r
+u4byte ff_mult(u4byte a, u4byte b, u4byte tpow, u4byte mpol)\r
+{   u4byte  r, s, m;\r
+\r
+    r = s = 0; m = (1 << tpow); \r
+\r
+    while(b)\r
+    {\r
+        if(b & 1)\r
+        \r
+            s ^= a;\r
+            \r
+        b >>= 1; a <<= 1;\r
+        \r
+        if(a & m)\r
+        \r
+            a ^= mpol;\r
+    }\r
+\r
+    return s;\r
+};\r
+\r
+void init_tables(void)\r
+{   u4byte  i, j, v;\r
+\r
+    // initialise S box 1\r
+\r
+    for(i = 0; i < S1_LEN; ++i)\r
+    {\r
+        j = v = i ^ S1_MASK; v = ff_mult(v, j, S1_SIZE, S1_POLY);\r
+        sb1[i] = (u1byte)ff_mult(v, j, S1_SIZE, S1_POLY);\r
+    } \r
+    // initialise S box 2\r
+\r
+    for(i = 0; i < S2_LEN; ++i)\r
+    {\r
+        j = v = i ^ S2_MASK; v = ff_mult(v, j, S2_SIZE, S2_POLY);\r
+        sb2[i] = (u1byte)ff_mult(v, j, S2_SIZE, S2_POLY);\r
+    }\r
+\r
+    // initialise permutation table\r
+\r
+    for(i = 0; i < 256; ++i)\r
+    {\r
+        prm[i][0] = ((i &  1) << 7) | ((i &  2) << 14) | ((i &  4) << 21) | ((i &   8) << 28);\r
+        prm[i][1] = ((i & 16) << 3) | ((i & 32) << 10) | ((i & 64) << 17) | ((i & 128) << 24);\r
+    }\r
+};\r
+\r
+void f_fun(u4byte res[2], const u4byte in[2], const u4byte key[2])\r
+{   u4byte  i, tt[2], pp[2];\r
+\r
+    tt[0] = (in[0] & ~key[0]) | (in[1] & key[0]);\r
+    tt[1] = (in[1] & ~key[0]) | (in[0] & key[0]);\r
+\r
+    i = sb1[((tt[1] >> 24) | (tt[0] << 8)) & S1_MASK];\r
+    pp[0]  = prm[i][0] >> 7; pp[1]  = prm[i][1] >> 7;\r
+    i = sb2[(tt[1] >> 16) & S2_MASK];\r
+    pp[0] |= prm[i][0] >> 6; pp[1] |= prm[i][1] >> 6;\r
+    i = sb1[(tt[1] >>  8) & S1_MASK];\r
+    pp[0] |= prm[i][0] >> 5; pp[1] |= prm[i][1] >> 5;\r
+    i = sb2[tt[1] & S2_MASK]; \r
+    pp[0] |= prm[i][0] >> 4; pp[1] |= prm[i][1] >> 4;\r
+    i = sb2[((tt[0] >> 24) | (tt[1] << 8)) & S2_MASK];\r
+    pp[0] |= prm[i][0] >> 3; pp[1] |= prm[i][1] >> 3;\r
+    i = sb1[(tt[0] >> 16) & S1_MASK]; \r
+    pp[0] |= prm[i][0] >> 2; pp[1] |= prm[i][1] >> 2;\r
+    i = sb2[(tt[0] >>  8) & S2_MASK];      \r
+    pp[0] |= prm[i][0] >> 1; pp[1] |= prm[i][1] >> 1;\r
+    i = sb1[tt[0] & S1_MASK];          \r
+    pp[0] |= prm[i][0];      pp[1] |= prm[i][1];\r
+\r
+    res[0] ^=  sb1[byte(pp[0], 0) | (key[1] <<  8) & S1_HMASK]\r
+            | (sb1[byte(pp[0], 1) | (key[1] <<  3) & S1_HMASK] << 8)\r
+            | (sb2[byte(pp[0], 2) | (key[1] >>  2) & S2_HMASK] << 16)\r
+            | (sb2[byte(pp[0], 3) | (key[1] >>  5) & S2_HMASK] << 24);\r
+    res[1] ^=  sb1[byte(pp[1], 0) | (key[1] >>  8) & S1_HMASK]\r
+            | (sb1[byte(pp[1], 1) | (key[1] >> 13) & S1_HMASK] << 8)\r
+            | (sb2[byte(pp[1], 2) | (key[1] >> 18) & S2_HMASK] << 16)\r
+            | (sb2[byte(pp[1], 3) | (key[1] >> 21) & S2_HMASK] << 24);\r
+};\r
+\r
+u4byte *loki_set_key(LokiContext *ctx,\r
+                    const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u4byte  i, k1[2], k2[2], k3[2], k4[2], del[2], tt[2], sk[2];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    if(!init_done)\r
+    {\r
+        init_tables(); init_done = 1;\r
+    }\r
+\r
+    k4[0] = io_swap(in_key[1]); k4[1] = io_swap(in_key[0]);\r
+    k3[0] = io_swap(in_key[3]); k3[1] = io_swap(in_key[2]);\r
+\r
+    switch ((key_len + 63) / 64)\r
+    {\r
+    case 2:\r
+        k2[0] = 0; k2[1] = 0; f_fun(k2, k3, k4);\r
+        k1[0] = 0; k1[1] = 0; f_fun(k1, k4, k3);\r
+        break;\r
+    case 3:\r
+       k2[0] = io_swap(in_key[5]); k2[1] = io_swap(in_key[4]);\r
+        k1[0] = 0; k1[1] = 0; f_fun(k1, k4, k3);\r
+        break;\r
+    case 4: \r
+        k2[0] = in_key[5]; k2[1] = in_key[4];\r
+        k1[0] = in_key[7]; k1[1] = in_key[6];\r
+       k2[0] = io_swap(in_key[5]); k2[1] = io_swap(in_key[4]);\r
+       k1[0] = io_swap(in_key[7]); k1[1] = io_swap(in_key[6]);\r
+    }\r
+\r
+    del[0] = delta[0]; del[1] = delta[1];\r
+\r
+    for(i = 0; i < 48; ++i)\r
+    {\r
+        tt[0] = k1[0]; tt[1] = k1[1]; \r
+        add_eq(tt, k3); add_eq(tt, del); add_eq(del, delta);\r
+        sk[0] = k4[0]; sk[1] = k4[1];\r
+        k4[0] = k3[0]; k4[1] = k3[1];\r
+        k3[0] = k2[0]; k3[1] = k2[1];\r
+        k2[0] = k1[0]; k2[1] = k1[1];\r
+        k1[0] = sk[0]; k1[1] = sk[1];\r
+        f_fun(k1, tt, k3);\r
+        l_key[i + i] = k1[0]; l_key[i + i + 1] = k1[1];\r
+    }\r
+\r
+    return l_key;\r
+};\r
+\r
+#define r_fun(l,r,k)        \\r
+    add_eq((l),(k));        \\r
+    f_fun((r),(l),(k) + 2); \\r
+    add_eq((l), (k) + 4)\r
+\r
+void loki_encrypt(LokiContext *ctx,\r
+                 const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  blk[4];\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    blk[3] = io_swap(in_blk[0]); blk[2] = io_swap(in_blk[1]);\r
+    blk[1] = io_swap(in_blk[2]); blk[0] = io_swap(in_blk[3]);\r
+\r
+    r_fun(blk, blk + 2, l_key +  0);\r
+    r_fun(blk + 2, blk, l_key +  6);\r
+    r_fun(blk, blk + 2, l_key + 12);\r
+    r_fun(blk + 2, blk, l_key + 18);\r
+    r_fun(blk, blk + 2, l_key + 24);\r
+    r_fun(blk + 2, blk, l_key + 30);\r
+    r_fun(blk, blk + 2, l_key + 36);\r
+    r_fun(blk + 2, blk, l_key + 42);\r
+    r_fun(blk, blk + 2, l_key + 48);\r
+    r_fun(blk + 2, blk, l_key + 54);\r
+    r_fun(blk, blk + 2, l_key + 60);\r
+    r_fun(blk + 2, blk, l_key + 66);\r
+    r_fun(blk, blk + 2, l_key + 72);\r
+    r_fun(blk + 2, blk, l_key + 78);\r
+    r_fun(blk, blk + 2, l_key + 84);\r
+    r_fun(blk + 2, blk, l_key + 90);\r
+\r
+    out_blk[3] = io_swap(blk[2]); out_blk[2] = io_swap(blk[3]);\r
+    out_blk[1] = io_swap(blk[0]); out_blk[0] = io_swap(blk[1]);\r
+};\r
+\r
+#define ir_fun(l,r,k)       \\r
+    sub_eq((l),(k) + 4);    \\r
+    f_fun((r),(l),(k) + 2); \\r
+    sub_eq((l),(k))\r
+\r
+void loki_decrypt(LokiContext *ctx,\r
+                 const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  blk[4], xs;\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    blk[3] = io_swap(in_blk[0]); blk[2] = io_swap(in_blk[1]);\r
+    blk[1] = io_swap(in_blk[2]); blk[0] = io_swap(in_blk[3]);\r
+\r
+    ir_fun(blk, blk + 2, l_key + 90); \r
+    ir_fun(blk + 2, blk, l_key + 84);\r
+    ir_fun(blk, blk + 2, l_key + 78); \r
+    ir_fun(blk + 2, blk, l_key + 72);\r
+    ir_fun(blk, blk + 2, l_key + 66); \r
+    ir_fun(blk + 2, blk, l_key + 60);\r
+    ir_fun(blk, blk + 2, l_key + 54); \r
+    ir_fun(blk + 2, blk, l_key + 48);\r
+    ir_fun(blk, blk + 2, l_key + 42); \r
+    ir_fun(blk + 2, blk, l_key + 36);\r
+    ir_fun(blk, blk + 2, l_key + 30); \r
+    ir_fun(blk + 2, blk, l_key + 24);\r
+    ir_fun(blk, blk + 2, l_key + 18); \r
+    ir_fun(blk + 2, blk, l_key + 12);\r
+    ir_fun(blk, blk + 2, l_key +  6); \r
+    ir_fun(blk + 2, blk, l_key);\r
+\r
+    out_blk[3] = io_swap(blk[2]); out_blk[2] = io_swap(blk[3]);\r
+    out_blk[1] = io_swap(blk[0]); out_blk[0] = io_swap(blk[1]);   \r
+};\r
diff --git a/lib/silccrypt/loki.h b/lib/silccrypt/loki.h
new file mode 100644 (file)
index 0000000..a93b2ce
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+
+  loki.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef LOKI_H
+#define LOKI_H
+
+#include "loki_internal.h"
+
+/* 
+ * SILC Crypto API for Loki
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_loki_init(void *context, 
+                         const unsigned char *key, 
+                         size_t keylen)
+{
+  loki_set_key((LokiContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string
+   is first hashed and then used as a new key. */
+
+inline int silc_loki_set_string_as_key(void *context, 
+                                      const unsigned char *string,
+                                      size_t keylen)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_loki_context_len()
+{
+  return sizeof(LokiContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_loki_encrypt_cbc(void *context,
+                                const unsigned char *src,
+                                unsigned char *dst,
+                                size_t len,
+                                unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  loki_encrypt((LokiContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    loki_encrypt((LokiContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_loki_decrypt_cbc(void *context,
+                                const unsigned char *src,
+                                unsigned char *dst,
+                                size_t len,
+                                unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  loki_decrypt((LokiContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    loki_decrypt((LokiContext *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/loki_internal.h b/lib/silccrypt/loki_internal.h
new file mode 100644 (file)
index 0000000..650f6b4
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+
+  loki_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef LOKI_INTERNAL_H
+#define LOKI_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+  u4byte l_key[96];
+} LokiContext;
+
+/* Prototypes */
+u4byte *loki_set_key(LokiContext *ctx,
+                    const u4byte in_key[], const u4byte key_len);
+void loki_encrypt(LokiContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4]);
+void loki_decrypt(LokiContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/mars.c b/lib/silccrypt/mars.c
new file mode 100644 (file)
index 0000000..31188b7
--- /dev/null
@@ -0,0 +1,525 @@
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm:   */
+/*                                                                      */
+/*         MARS by a team at IBM,                                        */
+/*                                                                      */
+/* which is a candidate algorithm in the Advanced Encryption Standard   */
+/* programme of the US National Institute of Standards and Technology.  */
+/* Copyright in this implementation is held by Dr B R Gladman. The MARS */
+/* algorithm is covered by a pending patent application owned by IBM,   */
+/* who intend to offer a royalty free license under any issued patent   */
+/* that results from such application if MARS is selected as the AES    */
+/* algorithm.  In the interim, you may evaluate the MARS algorithm for  */
+/* your personal, lawful, non-profit purposes as an end user.           */
+/*                                                                      */
+/* The header above modified on June 6th 1999.                          */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */
+
+/* Timing data for MARS (mars.c)
+
+128 bit key:
+Key Setup:    4316 cycles
+Encrypt:       369 cycles =    69.4 mbits/sec
+Decrypt:       376 cycles =    68.1 mbits/sec
+Mean:          373 cycles =    68.7 mbits/sec
+
+192 bit key:
+Key Setup:    4377 cycles
+Encrypt:       373 cycles =    68.6 mbits/sec
+Decrypt:       379 cycles =    67.5 mbits/sec
+Mean:          376 cycles =    68.1 mbits/sec
+
+256 bit key:
+Key Setup:    4340 cycles
+Encrypt:       369 cycles =    69.4 mbits/sec
+Decrypt:       376 cycles =    68.1 mbits/sec
+Mean:          373 cycles =    68.7 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "mars.h"
+
+/* 
+ * SILC Crypto API for MARS 
+ */
+
+/* Sets the key for cipher MARS. */
+
+SILC_CIPHER_API_SET_KEY(mars)
+{
+  mars_set_key((MarsContext *)context, (unsigned int *)key, keylen);
+  return TRUE;
+}
+
+/* Sets the string as a new key for the cipher MARS. The string
+   is first hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(mars)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+  return TRUE;
+}
+
+/* Returns the size of the MARS cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(mars)
+{
+  return sizeof(MarsContext);
+}
+
+/* Encrypts with MARS cipher in CBC mode.  Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(mars)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  mars_encrypt((MarsContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    mars_encrypt((MarsContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = out[0 - 4];
+  tiv[1] = out[1 - 4];
+  tiv[2] = out[2 - 4];
+  tiv[3] = out[3 - 4];
+
+  return TRUE;
+}
+
+/* Decrypts with MARS cipher in CBC mode.  Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(mars)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4], tmp2[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0];
+  tmp[1] = in[1];
+  tmp[2] = in[2];
+  tmp[3] = in[3];
+  mars_decrypt((MarsContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp2[0] = tmp[0];
+    tmp2[1] = tmp[1];
+    tmp2[2] = tmp[2];
+    tmp2[3] = tmp[3];
+    tmp[0] = in[0];
+    tmp[1] = in[1];
+    tmp[2] = in[2];
+    tmp[3] = in[3];
+    mars_decrypt((MarsContext *)context, in, out);
+    out[0] ^= tmp2[0];
+    out[1] ^= tmp2[1];
+    out[2] ^= tmp2[2];
+    out[3] ^= tmp2[3];
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = tmp[0];
+  tiv[1] = tmp[1];
+  tiv[2] = tmp[2];
+  tiv[3] = tmp[3];
+
+  return TRUE;
+}
+
+static u4byte s_box[] = 
+{
+    0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, /* 0x000    */
+    0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93, 
+    0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d, 
+    0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4, 
+    0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, /* 0x010    */
+    0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac, 
+    0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4, 
+    0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26, 
+    0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, /* 0x020    */
+    0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086, 
+    0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c, 
+    0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253, 
+    0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, /* 0x030    */
+    0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e, 
+    0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b, 
+    0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a, 
+    0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, /* 0x040    */
+    0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb, 
+    0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958, 
+    0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215, 
+    0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, /* 0x050    */
+    0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c, 
+    0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462, 
+    0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44, 
+    0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, /* 0x060    */
+    0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df, 
+    0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8, 
+    0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae, 
+    0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, /* 0x070    */ 
+    0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365, 
+    0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3, 
+    0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55, 
+    0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, /* 0x080    */
+    0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7, 
+    0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8, 
+    0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063, 
+    0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, /* 0x090    */
+    0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371, 
+    0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6, 
+    0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b, 
+    0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, /* 0x0a0    */
+    0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1, 
+    0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd, 
+    0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294, 
+    0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, /* 0x0b0    */
+    0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98, 
+    0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f, 
+    0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d, 
+    0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, /* 0x0c0    */
+    0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48,
+    0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149, 
+    0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9, 
+    0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, /* 0x0d0    */ 
+    0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e,
+    0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3, 
+    0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52, 
+    0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, /* 0x0e0    */ 
+    0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f,
+    0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59, 
+    0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8, 
+    0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, /* 0x0f0    */ 
+    0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca, 
+    0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3, 
+    0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030,
+
+    0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, /* 0x100    */
+    0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734, 
+    0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b, 
+    0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03, 
+    0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, /* 0x110    */ 
+    0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3, 
+    0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf, 
+    0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568, 
+    0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, /* 0x120    */
+    0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10, 
+    0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce, 
+    0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047, 
+    0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, /* 0x130    */
+    0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158, 
+    0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969, 
+    0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f, 
+    0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, /* 0x140    */
+    0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05, 
+    0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3, 
+    0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33, 
+    0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, /* 0x150    */
+    0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd, 
+    0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e, 
+    0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246, 
+    0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, /* 0x160    */
+    0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e, 
+    0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2, 
+    0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b, 
+    0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, /* 0x170    */
+    0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba, 
+    0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c, 
+    0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5, 
+    0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, /* 0x180    */
+    0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47, 
+    0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54, 
+    0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72, 
+    0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, /* 0x190    */
+    0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6, 
+    0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9, 
+    0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68, 
+    0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, /* 0x1a0    */
+    0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f,
+    0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4, 
+    0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7, 
+    0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, /* 0x1b0    */ 
+    0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038, 
+    0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c, 
+    0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53, 
+    0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, /* 0x1c0    */
+    0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336, 
+    0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235, 
+    0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185, 
+    0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, /* 0x1d0    */
+    0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558, 
+    0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830, 
+    0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85, 
+    0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, /* 0x1e0    */
+    0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6, 
+    0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319, 
+    0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469, 
+    0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, /* 0x1f0    */
+    0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b, 
+    0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0, 
+    0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee
+};
+
+static u4byte vk[47] =
+{ 
+    0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, 0x7dff9be3, 0xd4268361,
+    0xc96da1d4
+};
+
+#define f_mix(a,b,c,d)                  \
+        r = rotr(a, 8);                 \
+        b ^= s_box[a & 255];            \
+        b += s_box[(r & 255) + 256];    \
+        r = rotr(a, 16);                \
+        a  = rotr(a, 24);               \
+        c += s_box[r & 255];            \
+        d ^= s_box[(a & 255) + 256]
+
+#define b_mix(a,b,c,d)                  \
+        r = rotl(a, 8);                 \
+        b ^= s_box[(a & 255) + 256];    \
+        c -= s_box[r & 255];            \
+        r = rotl(a, 16);                \
+        a  = rotl(a, 24);               \
+        d -= s_box[(r & 255) + 256];    \
+        d ^= s_box[a & 255]
+
+#define f_ktr(a,b,c,d,i)    \
+    m = a + l_key[i];  \
+    a = rotl(a, 13);        \
+    r = a * l_key[i + 1];   \
+    l = s_box[m & 511];     \
+    r = rotl(r, 5);         \
+    c += rotl(m, r);        \
+    l ^= r;                 \
+    r = rotl(r, 5);         \
+    l ^= r;                 \
+    d ^= r;                 \
+    b += rotl(l, r)
+
+#define r_ktr(a,b,c,d,i)    \
+    r = a * l_key[i + 1];   \
+    a = rotr(a, 13);        \
+    m = a + l_key[i];  \
+    l = s_box[m & 511];     \
+    r = rotl(r, 5);         \
+    l ^= r;                 \
+    c -= rotl(m, r);        \
+    r = rotl(r, 5);         \
+    l ^= r;                 \
+    d ^= r;                 \
+    b -= rotl(l, r)
+
+/* For a 32 bit word (x) generate a mask (m) such that a bit in */
+/* m is set to 1 if and only if the corresponding bit in x is:  */
+/*                                                              */
+/* 1. in a sequence of 10 or more adjacent '0' bits             */
+/* 2. in a sequence of 10 or more adjacent '1' bits             */
+/* 3. but is not either endpoint of such a sequence unless such */
+/*    an endpoint is at the top bit (bit 31) of a word and is   */
+/*    in a sequence of '0' bits.                                */
+/*                                                              */
+/* The only situation in which a sequence endpoint is included  */
+/* in the mask is hence when the endpoint is at bit 31 and is   */
+/* the endpoint of a sequence of '0' bits. My thanks go to Shai */
+/* Halevi of IBM for the neat trick (which I missed) of finding */
+/* the '0' and '1' sequences at the same time.                  */
+
+u4byte gen_mask(u4byte x)
+{   u4byte  m;
+
+    /* if m{bn} stands for bit number bn of m, set m{bn} = 1 if */
+    /* x{bn} == x{bn+1} for 0 <= bn <= 30.  That is, set a bit  */
+    /* in m if the corresponding bit and the next higher bit in */
+    /* x are equal in value (set m{31} = 0).                    */
+
+    m = (~x ^ (x >> 1)) & 0x7fffffff;
+
+    /* Sequences of 9 '1' bits in m now correspond to sequences */
+    /* of 10 '0's or 10 '1' bits in x.  Shift and 'and' bits in */
+    /* m to find sequences of 9 or more '1' bits.   As a result */
+    /* bits in m are set if they are at the bottom of sequences */
+    /* of 10 adjacent '0's or 10 adjacent '1's in x.            */
+
+    m &= (m >> 1) & (m >> 2); m &= (m >> 3) & (m >> 6); 
+    
+    if(!m)  /* return if mask is empty - no key fixing needed   */
+            /* is this early return worthwhile?                 */
+        return 0;
+    
+    /* We need the internal bits in each continuous sequence of */
+    /* matching bits (that is the bits less the two endpoints). */
+    /* We thus propagate each set bit into the 8 internal bits  */
+    /* that it represents, starting 1 left and finsihing 8 left */
+    /* of its position.                                         */
+
+    m <<= 1; m |= (m << 1); m |= (m << 2); m |= (m << 4);
+
+    /* m is now correct except for the odd behaviour of bit 31, */
+    /* that is, it will be set if it is in a sequence of 10 or  */
+    /* more '0's and clear otherwise.                           */
+
+    m |= (m << 1) & ~x & 0x80000000;
+
+    return m & 0xfffffffc;
+};
+
+/* My thanks to Louis Granboulan for spotting an error in the   */
+/* previous version of set_key.                                 */
+
+u4byte *mars_set_key(MarsContext *ctx,
+                    const u4byte in_key[], const u4byte key_len)
+{   
+    u4byte  i, j, m, w; 
+    u4byte *l_key = ctx->l_key;
+    m = key_len / 32 - 1;
+
+    for(i = j = 0; i < 39; ++i)
+    {
+      vk[i + 7] = rotl(vk[i] ^ vk[i + 5], 3) ^ in_key[j] ^ i;
+
+      j = (j == m ? 0 : j + 1);
+    }
+
+    vk[46] = key_len / 32;
+
+    for(j = 0; j < 7; ++j)
+    {
+         for(i = 1; i < 40; ++i)
+         
+            vk[i + 7] = rotl(vk[i + 7] + s_box[vk[i + 6] & 511], 9);
+
+        vk[7] = rotl(vk[7] + s_box[vk[46] & 511], 9);
+    }
+
+    for(i = j = 0; i < 40; ++i)
+    {
+        l_key[j] = vk[i + 7];
+
+        j = (j < 33 ? j + 7 : j - 33);
+    }
+
+    for(i = 5; i < 37; i += 2)
+    {
+        w = l_key[i] | 3; 
+
+        if((m = gen_mask(w)))
+        
+            w ^= (rotl(s_box[265 + (l_key[i] & 3)], l_key[i + 3] & 31) & m);
+
+        l_key[i] = w;
+    }
+
+    return l_key;
+};
+
+void mars_encrypt(MarsContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  a, b, c, d, l, m, r;
+    u4byte *l_key = ctx->l_key;
+
+    a = in_blk[0] + l_key[0]; b = in_blk[1] + l_key[1];
+    c = in_blk[2] + l_key[2]; d = in_blk[3] + l_key[3];
+
+    f_mix(a,b,c,d); a += d;
+    f_mix(b,c,d,a); b += c;
+    f_mix(c,d,a,b);
+    f_mix(d,a,b,c);
+    f_mix(a,b,c,d); a += d;
+    f_mix(b,c,d,a); b += c;
+    f_mix(c,d,a,b);
+    f_mix(d,a,b,c);
+
+    f_ktr(a,b,c,d, 4); f_ktr(b,c,d,a, 6); f_ktr(c,d,a,b, 8); f_ktr(d,a,b,c,10); 
+    f_ktr(a,b,c,d,12); f_ktr(b,c,d,a,14); f_ktr(c,d,a,b,16); f_ktr(d,a,b,c,18); 
+    f_ktr(a,d,c,b,20); f_ktr(b,a,d,c,22); f_ktr(c,b,a,d,24); f_ktr(d,c,b,a,26); 
+    f_ktr(a,d,c,b,28); f_ktr(b,a,d,c,30); f_ktr(c,b,a,d,32); f_ktr(d,c,b,a,34); 
+
+    b_mix(a,b,c,d);
+    b_mix(b,c,d,a); c -= b;
+    b_mix(c,d,a,b); d -= a;
+    b_mix(d,a,b,c);
+    b_mix(a,b,c,d);
+    b_mix(b,c,d,a); c -= b;
+    b_mix(c,d,a,b); d -= a;
+    b_mix(d,a,b,c);
+
+    out_blk[0] = a - l_key[36]; out_blk[1] = b - l_key[37];
+    out_blk[2] = c - l_key[38]; out_blk[3] = d - l_key[39];
+};
+
+void mars_decrypt(MarsContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  a, b, c, d, l, m, r;
+    u4byte *l_key = ctx->l_key;
+
+    d = in_blk[0] + l_key[36]; c = in_blk[1] + l_key[37];
+    b = in_blk[2] + l_key[38]; a = in_blk[3] + l_key[39];
+
+    f_mix(a,b,c,d); a += d;
+    f_mix(b,c,d,a); b += c;
+    f_mix(c,d,a,b); 
+    f_mix(d,a,b,c);
+    f_mix(a,b,c,d); a += d;
+    f_mix(b,c,d,a); b += c;
+    f_mix(c,d,a,b);
+    f_mix(d,a,b,c);
+
+    r_ktr(a,b,c,d,34); r_ktr(b,c,d,a,32); r_ktr(c,d,a,b,30); r_ktr(d,a,b,c,28);
+    r_ktr(a,b,c,d,26); r_ktr(b,c,d,a,24); r_ktr(c,d,a,b,22); r_ktr(d,a,b,c,20);
+    r_ktr(a,d,c,b,18); r_ktr(b,a,d,c,16); r_ktr(c,b,a,d,14); r_ktr(d,c,b,a,12);
+    r_ktr(a,d,c,b,10); r_ktr(b,a,d,c, 8); r_ktr(c,b,a,d, 6); r_ktr(d,c,b,a, 4);
+
+    b_mix(a,b,c,d);
+    b_mix(b,c,d,a); c -= b;
+    b_mix(c,d,a,b); d -= a;
+    b_mix(d,a,b,c);
+    b_mix(a,b,c,d);
+    b_mix(b,c,d,a); c -= b;
+    b_mix(c,d,a,b); d -= a;
+    b_mix(d,a,b,c);
+
+    out_blk[0] = d - l_key[0]; out_blk[1] = c - l_key[1];
+    out_blk[2] = b - l_key[2]; out_blk[3] = a - l_key[3];
+}
diff --git a/lib/silccrypt/mars.h b/lib/silccrypt/mars.h
new file mode 100644 (file)
index 0000000..33dd826
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+  mars.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef MARS_H
+#define MARS_H
+
+#include "mars_internal.h"
+
+/* 
+ * SILC Crypto API for MARS 
+ */
+
+SILC_CIPHER_API_SET_KEY(mars);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(mars);
+SILC_CIPHER_API_CONTEXT_LEN(mars);
+SILC_CIPHER_API_ENCRYPT_CBC(mars);
+SILC_CIPHER_API_DECRYPT_CBC(mars);
+
+#endif
diff --git a/lib/silccrypt/mars_internal.h b/lib/silccrypt/mars_internal.h
new file mode 100644 (file)
index 0000000..43895d7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+
+  mars_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef MARS_INTERNAL_H
+#define MARS_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher context */
+typedef struct {
+  u4byte l_key[40];
+} MarsContext;
+
+/* Prototypes */
+u4byte *mars_set_key(MarsContext *ctx,
+                    const u4byte in_key[], const u4byte key_len);
+void mars_encrypt(MarsContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4]);
+void mars_decrypt(MarsContext *ctx,
+                 const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/md5.c b/lib/silccrypt/md5.c
new file mode 100644 (file)
index 0000000..20cf9c9
--- /dev/null
@@ -0,0 +1,293 @@
+/* File ripped from noiz-0.5 */
+/* Modified by Pekka Riikonen (priikone@poseidon.pspt.fi) */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "silcincludes.h"
+#include "md5.h"
+
+/* 
+ * SILC Hash API for MD5
+ */
+
+SILC_HASH_API_INIT(md5)
+{
+  MD5Init((struct MD5Context *)context);
+}
+
+SILC_HASH_API_UPDATE(md5)
+{
+  MD5Update((struct MD5Context *)context, data, len);
+}
+
+SILC_HASH_API_FINAL(md5)
+{
+  MD5Final(digest, (struct MD5Context *)context);
+}
+
+SILC_HASH_API_TRANSFORM(md5)
+{
+  MD5Transform(state, buffer);
+}
+
+SILC_HASH_API_CONTEXT_LEN(md5)
+{
+  return sizeof(struct MD5Context);
+}
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len)  /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+       uint32 t;
+       do {
+               t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
+                           ((unsigned)buf[1]<<8 | buf[0]);
+               *(uint32 *)buf = t;
+               buf += 4;
+       } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+
+       ctx->bits[0] = 0;
+       ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+       uint32 t;
+
+       /* Update bitcount */
+
+       t = ctx->bits[0];
+       if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
+               ctx->bits[1]++; /* Carry from low to high */
+       ctx->bits[1] += len >> 29;
+
+       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+       /* Handle any leading odd-sized chunks */
+
+       if ( t ) {
+               unsigned char *p = (unsigned char *)ctx->in + t;
+
+               t = 64-t;
+               if (len < t) {
+                       memcpy(p, buf, len);
+                       return;
+               }
+               memcpy(p, buf, t);
+               byteReverse(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               buf += t;
+               len -= t;
+       }
+
+       /* Process data in 64-byte chunks */
+
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               byteReverse(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+
+       memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+       unsigned count;
+       unsigned char *p;
+
+       /* Compute number of bytes mod 64 */
+       count = (ctx->bits[0] >> 3) & 0x3F;
+
+       /* Set the first char of padding to 0x80.  This is safe since there is
+          always at least one byte free */
+       p = ctx->in + count;
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 64 bytes */
+       count = 64 - 1 - count;
+
+       /* Pad out to 56 mod 64 */
+       if (count < 8) {
+               /* Two lots of padding:  Pad the first block to 64 bytes */
+               memset(p, 0, count);
+               byteReverse(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+
+               /* Now fill the next block with 56 bytes */
+               memset(ctx->in, 0, 56);
+       } else {
+               /* Pad block to 56 bytes */
+               memset(p, 0, count-8);
+       }
+       byteReverse(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
+       ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
+
+       MD5Transform(ctx->buf, ctx->in);
+       byteReverse((unsigned char *)ctx->buf, 4);
+       memcpy(digest, ctx->buf, 16);
+       memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32 buf[4], const unsigned char kbuf[64])
+{
+       register uint32 a, b, c, d, i;
+       uint32 in[16];
+
+       for (i = 0; i < 16; i++)
+           SILC_GET32_MSB(in[i], kbuf + 4 * i);
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
+       MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
+       MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
+       MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
+       MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
+       MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
+       MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
+       MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
+       MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
+       MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
+       MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
+       MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
+       MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
+       MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
+       MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
+       MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
+       MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
+       MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
+       MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
+       MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
+       MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+#endif
diff --git a/lib/silccrypt/md5.h b/lib/silccrypt/md5.h
new file mode 100644 (file)
index 0000000..c80f4a3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+  md5.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#include "md5_internal.h"
+
+/* 
+ * SILC Hash API for MD5
+ */
+
+SILC_HASH_API_INIT(md5);
+SILC_HASH_API_UPDATE(md5);
+SILC_HASH_API_FINAL(md5);
+SILC_HASH_API_TRANSFORM(md5);
+SILC_HASH_API_CONTEXT_LEN(md5);
+
+#endif
diff --git a/lib/silccrypt/md5_internal.h b/lib/silccrypt/md5_internal.h
new file mode 100644 (file)
index 0000000..ef1bddb
--- /dev/null
@@ -0,0 +1,24 @@
+/* file ripped from noiz-0.5. -Pekka */
+
+#ifndef MD5_INTERNAL_H
+#define MD5_INTERNAL_H
+
+typedef unsigned long uint32;
+
+struct MD5Context {
+       uint32 buf[4];
+       uint32 bits[2];
+       unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], const unsigned char kbuf[64]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif
diff --git a/lib/silccrypt/none.c b/lib/silccrypt/none.c
new file mode 100644 (file)
index 0000000..239be91
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+
+  none.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "none.h"
+
+/* 
+ * SILC Crypto API for None cipher (ie. no cipher) :)
+ */
+
+SILC_CIPHER_API_SET_KEY(none)
+{
+  return TRUE;
+}
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(none)
+{
+  return TRUE;
+}
+
+SILC_CIPHER_API_CONTEXT_LEN(none)
+{
+  return 1;
+}
+
+SILC_CIPHER_API_ENCRYPT_CBC(none)
+{
+  memcpy(dst, src, len);
+  return TRUE;
+}
+
+SILC_CIPHER_API_DECRYPT_CBC(none)
+{
+  memcpy(dst, src, len);
+  return TRUE;
+}
diff --git a/lib/silccrypt/none.h b/lib/silccrypt/none.h
new file mode 100644 (file)
index 0000000..316ea87
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+  none.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef NONE_H
+#define NONE_H
+
+/* 
+ * SILC Crypto API for None cipher (ie. no cipher) :)
+ */
+
+SILC_CIPHER_API_SET_KEY(none);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(none);
+SILC_CIPHER_API_CONTEXT_LEN(none);
+SILC_CIPHER_API_ENCRYPT_CBC(none);
+SILC_CIPHER_API_DECRYPT_CBC(none);
+
+#endif
diff --git a/lib/silccrypt/rc5.c b/lib/silccrypt/rc5.c
new file mode 100644 (file)
index 0000000..c0db8e9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * rc5.c                               RC5-32/16/b
+ *
+ * Copyright (c) 1999 Pekka Riikonen <priikone@poseidon.pspt.fi>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish, dis-
+ * tribute, sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do so, subject to the fol-
+ * lowing conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
+ * SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABIL-
+ * ITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the authors shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * the authors.
+ *
+ */
+
+/*
+ * Based on RC5 reference code and on description of Bruce Schneier's 
+ * Applied Cryptography.
+ *
+ * This implementation has a word size of 32 bits, a rounds of 16 and 
+ * variable key length from 128 and 192 up to 256 bits.
+ *
+ */
+
+#include "silcincludes.h"
+#include "rc5.h"
+
+/* RC5 encryption */
+#define RC5E(i, A, B)                          \
+               A = A ^ B;                      \
+               A = rotl(A, B) + S[i];          \
+               B = B ^ A;                      \
+               B = rotl(B, A) + S[i + 1];
+
+/* RC5 decryption */
+#define RC5D(i, A, B)                          \
+               B = B - S[i + 1];               \
+               B = rotr(B, A) ^ A;             \
+               A = A - S[i];                   \
+               A = rotr(A, B) ^ B;
+
+/* Sets RC5 key */
+
+int rc5_set_key(RC5Context *ctx, char *key, int key_len)
+{
+       u32 *in_key = (u32 *)key;
+       u32 i, j, k, A, B, L[c];
+       u32 *out_key = ctx->out_key;
+
+       if (key_len < b || key_len > (2 * b))
+               return -1;
+
+       //      key_len *= 8;
+
+       /* init L */
+       for (i = 0; i < key_len / w; i++)
+               L[i] = in_key[i];
+
+       /* init key array (S) */
+       out_key[0] = 0xb7e15163;
+       for (i = 1; i < t; i++)
+               out_key[i] = out_key[i - 1] + 0x9e3779b9;
+
+       /* mix L and key array (S) */
+       A = B = 0;
+       for (k = i = j = 0; k < (3 * t); k++) {
+               A = rotl(out_key[i] + (A + B), 3);
+               B += A;
+               B = rotl(L[j] + B, B);
+               out_key[i] = A;
+               L[j] = B;
+               i = (i + 1) % t;
+               j = (j + 1) % c;
+       }
+
+       return 0;
+}
+
+/* Encrypts *one* block at a time. */
+
+int rc5_encrypt(RC5Context *ctx, u32 *in, u32 *out)
+{
+       u32 A, B;
+       u32 *S = ctx->out_key;
+
+       A = in[0] + S[0];
+       B = in[1] + S[1];
+
+       RC5E(2, A, B); RC5E(4, A, B);
+       RC5E(6, A, B); RC5E(8, A, B);
+       RC5E(10, A, B); RC5E(12, A, B);
+       RC5E(14, A, B); RC5E(16, A, B);
+       RC5E(18, A, B); RC5E(20, A, B);
+       RC5E(22, A, B); RC5E(24, A, B);
+       RC5E(26, A, B); RC5E(28, A, B);
+       RC5E(30, A, B); RC5E(32, A, B);
+
+       out[0] = A;
+       out[1] = B;
+
+       return 0;
+}
+
+/* Decrypts *one* block at a time. */
+
+int rc5_decrypt(RC5Context *ctx, u32 *in, u32 *out)
+{
+       u32 A, B;
+       u32 *S = ctx->out_key;
+
+       A = in[0];
+       B = in[1];
+
+       RC5D(32, A, B); RC5D(30, A, B); 
+       RC5D(28, A, B); RC5D(26, A, B); 
+       RC5D(24, A, B); RC5D(22, A, B); 
+       RC5D(20, A, B); RC5D(18, A, B);
+       RC5D(16, A, B); RC5D(14, A, B);
+       RC5D(12, A, B); RC5D(10, A, B);
+       RC5D(8, A, B); RC5D(6, A, B);
+       RC5D(4, A, B); RC5D(2, A, B);
+
+       out[0] = A - S[0];
+       out[1] = B - S[1];
+
+       return 0;
+}   
diff --git a/lib/silccrypt/rc5.h b/lib/silccrypt/rc5.h
new file mode 100644 (file)
index 0000000..7d5a23e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+
+  rc5.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef RC5_H
+#define RC5_H
+
+#include "rc5_internal.h"
+
+/* 
+ * SILC Crypto API for RC5
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rc5)
+{
+  rc5_set_key((RC5Context *)context, (unsigned char *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc5)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rc5)
+{
+  return sizeof(RC5Context);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rc5)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[2];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  rc5_encrypt((RC5Context *)context, tmp, out);
+  in += 2;
+  out += 2;
+
+  for (i = 8; i < len; i += 8) {
+    tmp[0] = in[0] ^ out[0 - 2];
+    tmp[1] = in[1] ^ out[1 - 2];
+    rc5_encrypt((RC5Context *)context, tmp, out);
+    in += 2;
+    out += 2;
+  }
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rc5)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[2], tmp2[2];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0];
+  tmp[1] = in[1];
+  tmp[3] = in[3];
+  rc5_decrypt((RC5Context *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  in += 2;
+  out += 2;
+
+  for (i = 8; i < len; i += 8) {
+    tmp2[0] = tmp[0];
+    tmp2[1] = tmp[1];
+    tmp[0] = in[0];
+    tmp[1] = in[1];
+    rc5_decrypt((RC5Context *)context, in, out);
+    out[0] ^= tmp2[0];
+    out[1] ^= tmp2[1];
+    in += 2;
+    out += 2;
+  }
+
+  return TRUE;
+}
+
+#endif
diff --git a/lib/silccrypt/rc5_internal.h b/lib/silccrypt/rc5_internal.h
new file mode 100644 (file)
index 0000000..9400567
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+
+  rc5_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef RC5_INTERNAL_H
+#define RC5_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* RC5 definitions */
+#define w      32      /* word size, in bits */
+#define r      16      /* rounds */
+#define b      16      /* minimum key size in bytes */
+#define c      8       /* same for 128,  192 and 256 bits key */
+#define t      34      /* size of table S, t = 2 * (r + 1) */
+
+/* Cipher's context */
+typedef struct {
+  u32 out_key[t];
+} RC5Context;
+
+/* Prototypes */
+int rc5_set_key(RC5Context *ctx, char *key, int key_len);
+int rc5_encrypt(RC5Context *ctx, u32 *in, u32 *out);
+int rc5_decrypt(RC5Context *ctx, u32 *in, u32 *out);
+
+#endif
diff --git a/lib/silccrypt/rc6.c b/lib/silccrypt/rc6.c
new file mode 100644 (file)
index 0000000..e2cc97c
--- /dev/null
@@ -0,0 +1,255 @@
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm:   */
+/*                                                                      */
+/*         RC6 by Ron Rivest and RSA Labs                               */
+/*                                                                      */
+/* which is a candidate algorithm in the Advanced Encryption Standard   */
+/* programme of the US National Institute of Standards and Technology.  */
+/*                                                                      */
+/* Copyright in this implementation is held by Dr B R Gladman but I     */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions   */
+/* that the originators of the algorithm place on its exploitation.     */
+/*                                                                      */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */
+
+/* Timing data for RC6 (rc6.c)
+
+128 bit key:
+Key Setup:    1632 cycles
+Encrypt:       270 cycles =    94.8 mbits/sec
+Decrypt:       226 cycles =   113.3 mbits/sec
+Mean:          248 cycles =   103.2 mbits/sec
+
+192 bit key:
+Key Setup:    1885 cycles
+Encrypt:       267 cycles =    95.9 mbits/sec
+Decrypt:       235 cycles =   108.9 mbits/sec
+Mean:          251 cycles =   102.0 mbits/sec
+
+256 bit key:
+Key Setup:    1877 cycles
+Encrypt:       270 cycles =    94.8 mbits/sec
+Decrypt:       227 cycles =   112.8 mbits/sec
+Mean:          249 cycles =   103.0 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "rc6.h"
+
+/* 
+ * SILC Crypto API for RC6
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rc6)
+{
+  rc6_set_key((RC6Context *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc6)
+{
+  return 1;
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rc6)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  rc6_encrypt((RC6Context *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    rc6_encrypt((RC6Context *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = out[0 - 4];
+  tiv[1] = out[1 - 4];
+  tiv[2] = out[2 - 4];
+  tiv[3] = out[3 - 4];
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rc6)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4], tmp2[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0];
+  tmp[1] = in[1];
+  tmp[2] = in[2];
+  tmp[3] = in[3];
+  rc6_decrypt((RC6Context *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp2[0] = tmp[0];
+    tmp2[1] = tmp[1];
+    tmp2[2] = tmp[2];
+    tmp2[3] = tmp[3];
+    tmp[0] = in[0];
+    tmp[1] = in[1];
+    tmp[2] = in[2];
+    tmp[3] = in[3];
+    rc6_decrypt((RC6Context *)context, in, out);
+    out[0] ^= tmp2[0];
+    out[1] ^= tmp2[1];
+    out[2] ^= tmp2[2];
+    out[3] ^= tmp2[3];
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = tmp[0];
+  tiv[1] = tmp[1];
+  tiv[2] = tmp[2];
+  tiv[3] = tmp[3];
+
+  return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rc6)
+{
+  return sizeof(RC6Context);
+}
+
+
+#define f_rnd(i,a,b,c,d)                    \
+        u = rotl(d * (d + d + 1), 5);       \
+        t = rotl(b * (b + b + 1), 5);       \
+        a = rotl(a ^ t, u) + l_key[i];      \
+        c = rotl(c ^ u, t) + l_key[i + 1]
+
+#define i_rnd(i,a,b,c,d)                    \
+        u = rotl(d * (d + d + 1), 5);       \
+        t = rotl(b * (b + b + 1), 5);       \
+        c = rotr(c - l_key[i + 1], t) ^ u;  \
+        a = rotr(a - l_key[i], u) ^ t
+
+/* initialise the key schedule from the user supplied key   */
+
+u4byte *rc6_set_key(RC6Context *ctx, 
+                   const u4byte in_key[], const u4byte key_len)
+{   
+    u4byte  i, j, k, a, b, l[8], t;
+    u4byte *l_key = ctx->l_key;
+
+    l_key[0] = 0xb7e15163;
+
+    for(k = 1; k < 44; ++k)
+        
+        l_key[k] = l_key[k - 1] + 0x9e3779b9;
+
+    for(k = 0; k < key_len / 32; ++k)
+
+        l[k] = in_key[k];
+
+    t = (key_len / 32) - 1; // t = (key_len / 32);
+
+    a = b = i = j = 0;
+
+    for(k = 0; k < 132; ++k)
+    {   a = rotl(l_key[i] + a + b, 3); b += a;
+        b = rotl(l[j] + b, b);
+        l_key[i] = a; l[j] = b;
+        i = (i == 43 ? 0 : i + 1); // i = (i + 1) % 44;  
+        j = (j == t ? 0 : j + 1);  // j = (j + 1) % t;
+    }
+
+    return l_key;
+};
+
+/* encrypt a block of text  */
+
+void rc6_encrypt(RC6Context *ctx,
+                const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  a,b,c,d,t,u;
+    u4byte *l_key = ctx->l_key;
+
+    a = in_blk[0]; b = in_blk[1] + l_key[0];
+    c = in_blk[2]; d = in_blk[3] + l_key[1];
+
+    f_rnd( 2,a,b,c,d); f_rnd( 4,b,c,d,a);
+    f_rnd( 6,c,d,a,b); f_rnd( 8,d,a,b,c);
+    f_rnd(10,a,b,c,d); f_rnd(12,b,c,d,a);
+    f_rnd(14,c,d,a,b); f_rnd(16,d,a,b,c);
+    f_rnd(18,a,b,c,d); f_rnd(20,b,c,d,a);
+    f_rnd(22,c,d,a,b); f_rnd(24,d,a,b,c);
+    f_rnd(26,a,b,c,d); f_rnd(28,b,c,d,a);
+    f_rnd(30,c,d,a,b); f_rnd(32,d,a,b,c);
+    f_rnd(34,a,b,c,d); f_rnd(36,b,c,d,a);
+    f_rnd(38,c,d,a,b); f_rnd(40,d,a,b,c);
+
+    out_blk[0] = a + l_key[42]; out_blk[1] = b;
+    out_blk[2] = c + l_key[43]; out_blk[3] = d;
+};
+
+/* decrypt a block of text  */
+
+void rc6_decrypt(RC6Context *ctx,
+                const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  a,b,c,d,t,u;
+    u4byte *l_key = ctx->l_key;
+
+    d = in_blk[3]; c = in_blk[2] - l_key[43]; 
+    b = in_blk[1]; a = in_blk[0] - l_key[42];
+
+    i_rnd(40,d,a,b,c); i_rnd(38,c,d,a,b);
+    i_rnd(36,b,c,d,a); i_rnd(34,a,b,c,d);
+    i_rnd(32,d,a,b,c); i_rnd(30,c,d,a,b);
+    i_rnd(28,b,c,d,a); i_rnd(26,a,b,c,d);
+    i_rnd(24,d,a,b,c); i_rnd(22,c,d,a,b);
+    i_rnd(20,b,c,d,a); i_rnd(18,a,b,c,d);
+    i_rnd(16,d,a,b,c); i_rnd(14,c,d,a,b);
+    i_rnd(12,b,c,d,a); i_rnd(10,a,b,c,d);
+    i_rnd( 8,d,a,b,c); i_rnd( 6,c,d,a,b);
+    i_rnd( 4,b,c,d,a); i_rnd( 2,a,b,c,d);
+
+    out_blk[3] = d - l_key[1]; out_blk[2] = c; 
+    out_blk[1] = b - l_key[0]; out_blk[0] = a; 
+};
diff --git a/lib/silccrypt/rc6.h b/lib/silccrypt/rc6.h
new file mode 100644 (file)
index 0000000..ee85979
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+  rc6.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef RC6_H
+#define RC6_H
+
+#include "rc6_internal.h"
+
+/* 
+ * SILC Crypto API for RC6
+ */
+
+SILC_CIPHER_API_SET_KEY(rc6);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rc6);
+SILC_CIPHER_API_CONTEXT_LEN(rc6);
+SILC_CIPHER_API_ENCRYPT_CBC(rc6);
+SILC_CIPHER_API_DECRYPT_CBC(rc6);
+
+#endif
diff --git a/lib/silccrypt/rc6_internal.h b/lib/silccrypt/rc6_internal.h
new file mode 100644 (file)
index 0000000..1b69306
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+
+  rc6_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef RC6_INTERNAL_H
+#define RC6_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+  u4byte l_key[44];
+} RC6Context;
+
+/* Prototypes */
+u4byte *rc6_set_key(RC6Context *ctx, 
+                   const u4byte in_key[], const u4byte key_len);
+void rc6_encrypt(RC6Context *ctx,
+                const u4byte in_blk[4], u4byte out_blk[4]);
+void rc6_decrypt(RC6Context *ctx,
+                const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/rijndael.c b/lib/silccrypt/rijndael.c
new file mode 100644 (file)
index 0000000..f6d5b1d
--- /dev/null
@@ -0,0 +1,384 @@
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm:   */
+/*                                                                      */
+/*         RIJNDAEL by Joan Daemen and Vincent Rijmen                   */
+/*                                                                      */
+/* which is a candidate algorithm in the Advanced Encryption Standard   */
+/* programme of the US National Institute of Standards and Technology.  */
+/*                                                                      */
+/* Copyright in this implementation is held by Dr B R Gladman but I     */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions   */
+/* that the originators of the algorithm place on its exploitation.     */
+/*                                                                      */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */
+
+/* Timing data for Rijndael (rijndael.c)
+
+Algorithm: rijndael (rijndael.c)
+
+128 bit key:
+Key Setup:    305/1389 cycles (encrypt/decrypt)
+Encrypt:       374 cycles =    68.4 mbits/sec
+Decrypt:       352 cycles =    72.7 mbits/sec
+Mean:          363 cycles =    70.5 mbits/sec
+
+192 bit key:
+Key Setup:    277/1595 cycles (encrypt/decrypt)
+Encrypt:       439 cycles =    58.3 mbits/sec
+Decrypt:       425 cycles =    60.2 mbits/sec
+Mean:          432 cycles =    59.3 mbits/sec
+
+256 bit key:
+Key Setup:    374/1960 cycles (encrypt/decrypt)
+Encrypt:       502 cycles =    51.0 mbits/sec
+Decrypt:       498 cycles =    51.4 mbits/sec
+Mean:          500 cycles =    51.2 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "rijndael.h"
+
+#define LARGE_TABLES
+
+u1byte  pow_tab[256];
+u1byte  log_tab[256];
+u1byte  sbx_tab[256];
+u1byte  isb_tab[256];
+u4byte  rco_tab[ 10];
+u4byte  ft_tab[4][256];
+u4byte  it_tab[4][256];
+
+u4byte  fl_tab[4][256];
+u4byte  il_tab[4][256];
+
+u4byte  tab_gen = 0;
+
+#define ff_mult(a,b)    (a && b ? pow_tab[(log_tab[a] + log_tab[b]) % 255] : 0)
+
+#define f_rn(bo, bi, n, k)                          \
+    bo[n] =  ft_tab[0][byte(bi[n],0)] ^             \
+             ft_tab[1][byte(bi[(n + 1) & 3],1)] ^   \
+             ft_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
+
+#define i_rn(bo, bi, n, k)                          \
+    bo[n] =  it_tab[0][byte(bi[n],0)] ^             \
+             it_tab[1][byte(bi[(n + 3) & 3],1)] ^   \
+             it_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
+
+#ifdef LARGE_TABLES
+
+#define ls_box(x)                \
+    ( fl_tab[0][byte(x, 0)] ^    \
+      fl_tab[1][byte(x, 1)] ^    \
+      fl_tab[2][byte(x, 2)] ^    \
+      fl_tab[3][byte(x, 3)] )
+
+#define f_rl(bo, bi, n, k)                          \
+    bo[n] =  fl_tab[0][byte(bi[n],0)] ^             \
+             fl_tab[1][byte(bi[(n + 1) & 3],1)] ^   \
+             fl_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
+
+#define i_rl(bo, bi, n, k)                          \
+    bo[n] =  il_tab[0][byte(bi[n],0)] ^             \
+             il_tab[1][byte(bi[(n + 3) & 3],1)] ^   \
+             il_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
+
+#else
+
+#define ls_box(x)                            \
+    ((u4byte)sbx_tab[byte(x, 0)] <<  0) ^    \
+    ((u4byte)sbx_tab[byte(x, 1)] <<  8) ^    \
+    ((u4byte)sbx_tab[byte(x, 2)] << 16) ^    \
+    ((u4byte)sbx_tab[byte(x, 3)] << 24)
+
+#define f_rl(bo, bi, n, k)                                      \
+    bo[n] = (u4byte)sbx_tab[byte(bi[n],0)] ^                    \
+        rotl(((u4byte)sbx_tab[byte(bi[(n + 1) & 3],1)]),  8) ^  \
+        rotl(((u4byte)sbx_tab[byte(bi[(n + 2) & 3],2)]), 16) ^  \
+        rotl(((u4byte)sbx_tab[byte(bi[(n + 3) & 3],3)]), 24) ^ *(k + n)
+
+#define i_rl(bo, bi, n, k)                                      \
+    bo[n] = (u4byte)isb_tab[byte(bi[n],0)] ^                    \
+        rotl(((u4byte)isb_tab[byte(bi[(n + 3) & 3],1)]),  8) ^  \
+        rotl(((u4byte)isb_tab[byte(bi[(n + 2) & 3],2)]), 16) ^  \
+        rotl(((u4byte)isb_tab[byte(bi[(n + 1) & 3],3)]), 24) ^ *(k + n)
+
+#endif
+
+void gen_tabs(void)
+{   u4byte  i, t;
+    u1byte  p, q;
+
+    /* log and power tables for GF(2**8) finite field with  */
+    /* 0x11b as modular polynomial - the simplest prmitive  */
+    /* root is 0x11, used here to generate the tables       */
+
+    for(i = 0,p = 1; i < 256; ++i)
+    {
+        pow_tab[i] = (u1byte)p; log_tab[p] = (u1byte)i;
+
+        p = p ^ (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+    }
+
+    log_tab[1] = 0; p = 1;
+
+    for(i = 0; i < 10; ++i)
+    {
+        rco_tab[i] = p; 
+
+        p = (p << 1) ^ (p & 0x80 ? 0x1b : 0);
+    }
+
+    /* note that the affine byte transformation matrix in   */
+    /* rijndael specification is in big endian format with  */
+    /* bit 0 as the most significant bit. In the remainder  */
+    /* of the specification the bits are numbered from the  */
+    /* least significant end of a byte.                     */
+
+    for(i = 0; i < 256; ++i)
+    {   
+        p = (i ? pow_tab[255 - log_tab[i]] : 0); q = p; 
+        q = (q >> 7) | (q << 1); p ^= q; 
+        q = (q >> 7) | (q << 1); p ^= q; 
+        q = (q >> 7) | (q << 1); p ^= q; 
+        q = (q >> 7) | (q << 1); p ^= q ^ 0x63; 
+        sbx_tab[i] = (u1byte)p; isb_tab[p] = (u1byte)i;
+    }
+
+    for(i = 0; i < 256; ++i)
+    {
+        p = sbx_tab[i]; 
+
+#ifdef  LARGE_TABLES        
+        
+        t = p; fl_tab[0][i] = t;
+        fl_tab[1][i] = rotl(t,  8);
+        fl_tab[2][i] = rotl(t, 16);
+        fl_tab[3][i] = rotl(t, 24);
+#endif
+        t = ((u4byte)ff_mult(2, p)) |
+            ((u4byte)p <<  8) |
+            ((u4byte)p << 16) |
+            ((u4byte)ff_mult(3, p) << 24);
+        
+        ft_tab[0][i] = t;
+        ft_tab[1][i] = rotl(t,  8);
+        ft_tab[2][i] = rotl(t, 16);
+        ft_tab[3][i] = rotl(t, 24);
+
+        p = isb_tab[i]; 
+
+#ifdef  LARGE_TABLES        
+        
+        t = p; il_tab[0][i] = t; 
+        il_tab[1][i] = rotl(t,  8); 
+        il_tab[2][i] = rotl(t, 16); 
+        il_tab[3][i] = rotl(t, 24);
+#endif 
+        t = ((u4byte)ff_mult(14, p)) |
+            ((u4byte)ff_mult( 9, p) <<  8) |
+            ((u4byte)ff_mult(13, p) << 16) |
+            ((u4byte)ff_mult(11, p) << 24);
+        
+        it_tab[0][i] = t; 
+        it_tab[1][i] = rotl(t,  8); 
+        it_tab[2][i] = rotl(t, 16); 
+        it_tab[3][i] = rotl(t, 24); 
+    }
+
+    tab_gen = 1;
+};
+
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
+
+#define imix_col(y,x)       \
+    u   = star_x(x);        \
+    v   = star_x(u);        \
+    w   = star_x(v);        \
+    t   = w ^ (x);          \
+   (y)  = u ^ v ^ w;        \
+   (y) ^= rotr(u ^ t,  8) ^ \
+          rotr(v ^ t, 16) ^ \
+          rotr(t,24)
+
+/* initialise the key schedule from the user supplied key   */
+
+#define loop4(i)                                    \
+{ \
+   t = ls_box(rotr(t,  8)) ^ rco_tab[i];           \
+    t ^= e_key[4 * i];     e_key[4 * i + 4] = t;    \
+    t ^= e_key[4 * i + 1]; e_key[4 * i + 5] = t;    \
+    t ^= e_key[4 * i + 2]; e_key[4 * i + 6] = t;    \
+    t ^= e_key[4 * i + 3]; e_key[4 * i + 7] = t;    \
+}
+
+#define loop6(i)                                    \
+{   t = ls_box(rotr(t,  8)) ^ rco_tab[i];           \
+    t ^= e_key[6 * i];     e_key[6 * i + 6] = t;    \
+    t ^= e_key[6 * i + 1]; e_key[6 * i + 7] = t;    \
+    t ^= e_key[6 * i + 2]; e_key[6 * i + 8] = t;    \
+    t ^= e_key[6 * i + 3]; e_key[6 * i + 9] = t;    \
+    t ^= e_key[6 * i + 4]; e_key[6 * i + 10] = t;   \
+    t ^= e_key[6 * i + 5]; e_key[6 * i + 11] = t;   \
+}
+
+#define loop8(i)                                    \
+{   t = ls_box(rotr(t,  8)) ^ rco_tab[i];           \
+    t ^= e_key[8 * i];     e_key[8 * i + 8] = t;    \
+    t ^= e_key[8 * i + 1]; e_key[8 * i + 9] = t;    \
+    t ^= e_key[8 * i + 2]; e_key[8 * i + 10] = t;   \
+    t ^= e_key[8 * i + 3]; e_key[8 * i + 11] = t;   \
+    t  = e_key[8 * i + 4] ^ ls_box(t);              \
+    e_key[8 * i + 12] = t;                          \
+    t ^= e_key[8 * i + 5]; e_key[8 * i + 13] = t;   \
+    t ^= e_key[8 * i + 6]; e_key[8 * i + 14] = t;   \
+    t ^= e_key[8 * i + 7]; e_key[8 * i + 15] = t;   \
+}
+
+u4byte *rijndael_set_key(RijndaelContext *ctx,
+                        const u4byte in_key[], const u4byte key_len)
+{   
+    u4byte  i, t, u, v, w;
+    u4byte *e_key = ctx->e_key;
+    u4byte *d_key = ctx->d_key;
+    u4byte k_len;
+
+    if(!tab_gen)
+        gen_tabs();
+
+    k_len = ctx->k_len = (key_len + 31) / 32;
+
+    e_key[0] = in_key[0]; e_key[1] = in_key[1];
+    e_key[2] = in_key[2]; e_key[3] = in_key[3];
+
+    switch(k_len)
+    {
+        case 4: t = e_key[3];
+                for(i = 0; i < 10; ++i) 
+                    loop4(i);
+                break;
+
+        case 6: e_key[4] = in_key[4]; t = e_key[5] = in_key[5];
+                for(i = 0; i < 8; ++i) 
+                    loop6(i);
+                break;
+
+        case 8: e_key[4] = in_key[4]; e_key[5] = in_key[5];
+                e_key[6] = in_key[6]; t = e_key[7] = in_key[7];
+                for(i = 0; i < 7; ++i) 
+                    loop8(i);
+                break;
+    }
+
+    d_key[0] = e_key[0]; d_key[1] = e_key[1];
+    d_key[2] = e_key[2]; d_key[3] = e_key[3];
+
+    for(i = 4; i < 4 * k_len + 24; ++i)
+    {
+        imix_col(d_key[i], e_key[i]);
+    }
+
+    return e_key;
+};
+
+/* encrypt a block of text  */
+
+#define f_nround(bo, bi, k) \
+    f_rn(bo, bi, 0, k);     \
+    f_rn(bo, bi, 1, k);     \
+    f_rn(bo, bi, 2, k);     \
+    f_rn(bo, bi, 3, k);     \
+    k += 4
+
+#define f_lround(bo, bi, k) \
+    f_rl(bo, bi, 0, k);     \
+    f_rl(bo, bi, 1, k);     \
+    f_rl(bo, bi, 2, k);     \
+    f_rl(bo, bi, 3, k)
+
+void rijndael_encrypt(RijndaelContext *ctx,
+                     const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  b0[4], b1[4], *kp;
+    u4byte *e_key = ctx->e_key;
+    u4byte k_len = ctx->k_len;
+
+    b0[0] = in_blk[0] ^ e_key[0]; b0[1] = in_blk[1] ^ e_key[1];
+    b0[2] = in_blk[2] ^ e_key[2]; b0[3] = in_blk[3] ^ e_key[3];
+
+    kp = e_key + 4;
+
+    if(k_len > 6)
+    {
+        f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    }
+
+    if(k_len > 4)
+    {
+        f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    }
+
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_lround(b0, b1, kp);
+
+    out_blk[0] = b0[0]; out_blk[1] = b0[1];
+    out_blk[2] = b0[2]; out_blk[3] = b0[3];
+};
+
+/* decrypt a block of text  */
+
+#define i_nround(bo, bi, k) \
+    i_rn(bo, bi, 0, k);     \
+    i_rn(bo, bi, 1, k);     \
+    i_rn(bo, bi, 2, k);     \
+    i_rn(bo, bi, 3, k);     \
+    k -= 4
+
+#define i_lround(bo, bi, k) \
+    i_rl(bo, bi, 0, k);     \
+    i_rl(bo, bi, 1, k);     \
+    i_rl(bo, bi, 2, k);     \
+    i_rl(bo, bi, 3, k)
+
+void rijndael_decrypt(RijndaelContext *ctx,
+                     const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  b0[4], b1[4], *kp;
+    u4byte *e_key = ctx->e_key;
+    u4byte *d_key = ctx->d_key;
+    u4byte k_len = ctx->k_len;
+
+    b0[0] = in_blk[0] ^ e_key[4 * k_len + 24]; b0[1] = in_blk[1] ^ e_key[4 * k_len + 25];
+    b0[2] = in_blk[2] ^ e_key[4 * k_len + 26]; b0[3] = in_blk[3] ^ e_key[4 * k_len + 27];
+
+    kp = d_key + 4 * (k_len + 5);
+
+    if(k_len > 6)
+    {
+        i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    }
+
+    if(k_len > 4)
+    {
+        i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    }
+
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_lround(b0, b1, kp);
+
+    out_blk[0] = b0[0]; out_blk[1] = b0[1];
+    out_blk[2] = b0[2]; out_blk[3] = b0[3];
+};
diff --git a/lib/silccrypt/rijndael.h b/lib/silccrypt/rijndael.h
new file mode 100644 (file)
index 0000000..6307a5e
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+
+  rijndael.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef RIJNDAEL_H
+#define RIJNDAEL_H
+
+#include "rijndael_internal.h"
+
+/* 
+ * SILC Crypto API for Rijndael
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rijndael)
+{
+  rijndael_set_key((RijndaelContext *)context, (unsigned int *)key, keylen);
+  return TRUE;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rijndael)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return TRUE;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rijnadel)
+{
+  return sizeof(RijndaelContext);
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rijndael)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  rijndael_encrypt((RijndaelContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    rijndael_encrypt((RijndaelContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rijndael)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4], tmp2[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0];
+  tmp[1] = in[1];
+  tmp[2] = in[2];
+  tmp[3] = in[3];
+  rijndael_decrypt((RijndaelContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp2[0] = tmp[0];
+    tmp2[1] = tmp[1];
+    tmp2[2] = tmp[2];
+    tmp2[3] = tmp[3];
+    tmp[0] = in[0];
+    tmp[1] = in[1];
+    tmp[2] = in[2];
+    tmp[3] = in[3];
+    rijndael_decrypt((RijndaelContext *)context, in, out);
+    out[0] ^= tmp2[0];
+    out[1] ^= tmp2[1];
+    out[2] ^= tmp2[2];
+    out[3] ^= tmp2[3];
+    in += 4;
+    out += 4;
+  }
+
+  return TRUE;
+}
+
+#endif
diff --git a/lib/silccrypt/rijndael_internal.h b/lib/silccrypt/rijndael_internal.h
new file mode 100644 (file)
index 0000000..ae8b730
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+
+  rijndael_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef RIJNDAEL_INTERNAL_H
+#define RIJNDAEL_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+  u4byte e_key[60];
+  u4byte d_key[60];
+  u4byte k_len;
+} RijndaelContext;
+
+/* Prototypes */
+u4byte *rijndael_set_key(RijndaelContext *ctx,
+                        const u4byte in_key[], const u4byte key_len);
+void rijndael_encrypt(RijndaelContext *ctx,
+                     const u4byte in_blk[4], u4byte out_blk[4]);
+void rijndael_decrypt(RijndaelContext *ctx,
+                     const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/rsa.c b/lib/silccrypt/rsa.c
new file mode 100644 (file)
index 0000000..c185adb
--- /dev/null
@@ -0,0 +1,560 @@
+/* 
+ * rsa.c       RSA Public and Private key generation functions,
+ *             RSA encrypt and decrypt functions.
+ *
+ * Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ *
+ * Copyright (C) 1997 - 2000 Pekka Riikonen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Created: Sat Mar  1 13:26:45 1997 pekka
+ *
+ * RSA public key cryptographic algorithm used in this distribution is:
+ *
+ *     Key generation:
+ *     p, q            primes
+ *     p != q
+ *     n = p * q       modulus
+ *
+ *     Public key exponent:
+ *     e   relatively prime to (p-1) * (q-1)
+ *     Private key exponent:
+ *     d = e ^ -1 mod ((p-1) * (q-1))
+ *
+ *     Encryption:
+ *     c = m ^ e mod n
+ *     Decryption:
+ *     m = c ^ d mod n
+ *
+ * This code is based on SSH's (Secure Shell), PGP's (Pretty Good Privacy) 
+ * and RSAREF Toolkit's RSA source codes. They all were a big help for me.
+ *
+ * I also suggest reading Bruce Schneier's; Applied Cryptography, Second 
+ * Edition, John Wiley & Sons, Inc. 1996. This book deals about RSA and 
+ * everything else too about cryptography.
+ *
+ */
+
+#include "silcincludes.h"
+#include "rsa.h"
+
+/*
+ * SILC PKCS API for RSA
+ */
+
+/* Generates RSA key pair. */
+
+SILC_PKCS_API_INIT(rsa)
+{
+  unsigned int prime_bits = keylen / 2;
+  SilcInt p, q;
+
+  printf("Generating RSA Public and Private keys, might take a while...\n");
+
+  silc_mp_init(&p);
+  silc_mp_init(&q);
+
+  /* Find p and q */
+ retry_primes:
+  printf("Finding p: ");
+  silc_math_gen_prime(&p, prime_bits, TRUE);
+  
+  printf("\nFinding q: ");
+  silc_math_gen_prime(&q, prime_bits, TRUE);
+  
+  if ((silc_mp_cmp(&p, &q)) == 0) {
+    printf("\nFound equal primes, not good, retrying...\n");
+    goto retry_primes;
+  }
+
+  /* If p is smaller than q, switch them */
+  if ((silc_mp_cmp(&p, &q)) > 0) {
+    SilcInt hlp;
+    silc_mp_init(&hlp);
+
+    silc_mp_set(&hlp, &p);
+    silc_mp_set(&p, &q);
+    silc_mp_set(&q, &hlp);
+
+    silc_mp_clear(&hlp);
+  }
+
+  /* Generate the actual keys */
+  rsa_generate_keys((RsaKey *)context, keylen, &p, &q);
+
+  silc_mp_clear(&p);
+  silc_mp_clear(&q);
+  
+  printf("\nKeys generated succesfully.\n");
+
+  return TRUE;
+}
+
+SILC_PKCS_API_CLEAR_KEYS(rsa)
+{
+  rsa_clear_keys((RsaKey *)context);
+}
+
+/* Returns SILC style encoded RSA public key. */
+
+SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  unsigned char *e, *n, *ret;
+  unsigned int e_len, n_len;
+  unsigned char tmp[2];
+
+  e_len = silc_mp_sizeinbase(&key->e, 16);
+  n_len = silc_mp_sizeinbase(&key->n, 16);
+  e = silc_calloc(e_len + 1, sizeof(unsigned char));
+  n = silc_calloc(n_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(e, 16, &key->e);
+  silc_mp_get_str(n, 16, &key->n);
+
+  *ret_len = e_len + 2 + n_len + 2;
+  ret = silc_calloc(*ret_len, sizeof(unsigned char));
+
+  /* Put the length of the e. */
+  tmp[0] = e_len >> 8;
+  tmp[1] = e_len;
+  memcpy(ret, tmp, 2);
+
+  /* Put the e. */
+  memcpy(ret + 2, e, e_len);
+
+  /* Put the length of the n. */
+  tmp[0] = n_len >> 8;
+  tmp[1] = n_len;
+  memcpy(ret + 2 + e_len, tmp, 2);
+
+  /* Put the n. */
+  memcpy(ret + 2 + e_len + 2, n, n_len);
+
+  memset(e, 0, e_len);
+  memset(n, 0, n_len);
+  silc_free(e);
+  silc_free(n);
+
+  return ret;
+}
+
+/* Returns SILC style encoded RSA private key. Public key is always
+   returned in private key as well. Public keys are often derived
+   directly from private key. */
+
+SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  unsigned char *e, *n, *d, *ret;
+  unsigned int e_len, n_len, d_len;
+  unsigned char tmp[2];
+
+  e_len = silc_mp_sizeinbase(&key->e, 16);
+  n_len = silc_mp_sizeinbase(&key->n, 16);
+  d_len = silc_mp_sizeinbase(&key->d, 16);
+  e = silc_calloc(e_len + 1, sizeof(unsigned char));
+  n = silc_calloc(n_len + 1, sizeof(unsigned char));
+  d = silc_calloc(d_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(e, 16, &key->e);
+  silc_mp_get_str(n, 16, &key->n);
+  silc_mp_get_str(d, 16, &key->d);
+
+  *ret_len = e_len + 2 + n_len + 2 + d_len + 2;
+  ret = silc_calloc(*ret_len, sizeof(unsigned char));
+
+  /* Put the length of the e. */
+  tmp[0] = e_len >> 8;
+  tmp[1] = e_len;
+  memcpy(ret, tmp, 2);
+
+  /* Put the e. */
+  memcpy(ret + 2, e, e_len);
+
+  /* Put the length of the n. */
+  tmp[0] = n_len >> 8;
+  tmp[1] = n_len;
+  memcpy(ret + 2 + e_len, tmp, 2);
+
+  /* Put the n. */
+  memcpy(ret + 2 + e_len + 2, n, n_len);
+
+  /* Put the length of the d. */
+  tmp[0] = d_len >> 8;
+  tmp[1] = d_len;
+  memcpy(ret + 2 + e_len + 2 + n_len, tmp, 2);
+
+  /* Put the n. */
+  memcpy(ret + 2 + e_len + 2 + n_len + 2, d, d_len);
+
+  memset(e, 0, e_len);
+  memset(n, 0, n_len);
+  memset(d, 0, d_len);
+  silc_free(e);
+  silc_free(n);
+  silc_free(d);
+
+  return ret;
+}
+
+/* Set public key */
+
+SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  unsigned char *e, *n, tmp[2];
+  unsigned int e_len, n_len;
+
+  silc_mp_init(&key->e);
+  silc_mp_init(&key->n);
+
+  memcpy(tmp, key_data, 2);
+  e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+  e = silc_calloc(e_len + 1, sizeof(unsigned char));
+  memcpy(e, key_data + 2, e_len);
+  silc_mp_set_str(&key->e, e, 16);
+  
+  memcpy(tmp, key_data + 2 + e_len, 2);
+  n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+  n = silc_calloc(n_len + 1, sizeof(unsigned char));
+  memcpy(n, key_data + 2 + e_len + 2, n_len);
+  silc_mp_set_str(&key->n, n, 16);
+
+  memset(e, 0, e_len);
+  memset(n, 0, n_len);
+  silc_free(e);
+  silc_free(n);
+
+  return TRUE;
+}
+
+/* Set private key. This derives the public key from the private
+   key and sets the public key as well. Public key should not be set
+   already and should not be set after setting private key. */
+
+SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  unsigned char *e, *n, *d, tmp[2];
+  unsigned int e_len, n_len, d_len;
+
+  silc_mp_init(&key->e);
+  silc_mp_init(&key->n);
+  silc_mp_init(&key->d);
+
+  memcpy(tmp, key_data, 2);
+  e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+  e = silc_calloc(e_len + 1, sizeof(unsigned char));
+  memcpy(e, key_data + 2, e_len);
+  silc_mp_set_str(&key->e, e, 16);
+  
+  memcpy(tmp, key_data + 2 + e_len, 2);
+  n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+  n = silc_calloc(n_len + 1, sizeof(unsigned char));
+  memcpy(n, key_data + 2 + e_len + 2, n_len);
+  silc_mp_set_str(&key->n, n, 16);
+
+  memcpy(tmp, key_data + 2 + e_len + 2 + n_len, 2);
+  d_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+
+  d = silc_calloc(d_len + 1, sizeof(unsigned char));
+  memcpy(d, key_data + 2 + e_len + 2 + n_len + 2, d_len);
+  silc_mp_set_str(&key->d, d, 16);
+
+  memset(e, 0, e_len);
+  memset(n, 0, n_len);
+  memset(d, 0, d_len);
+  silc_free(e);
+  silc_free(n);
+  silc_free(d);
+
+  return TRUE;
+}
+
+SILC_PKCS_API_CONTEXT_LEN(rsa)
+{
+  return sizeof(RsaKey);
+}
+
+SILC_PKCS_API_DATA_CONTEXT_LEN(rsa)
+{
+  return sizeof(RsaDataContext);
+}
+
+SILC_PKCS_API_SET_ARG(rsa)
+{
+  RsaDataContext *data_ctx = (RsaDataContext *)data_context;
+
+  switch(argnum) {
+  case 1:
+    data_ctx->src = val;
+    return TRUE;
+    break;
+  case 2:
+    data_ctx->dst = val;
+    return TRUE;
+    break;
+  case 3:
+    data_ctx->exp = val;
+    return TRUE;
+    break;
+  case 4:
+    data_ctx->mod = val;
+    return TRUE;
+    break;
+  default:
+    return FALSE;
+    break;
+  }
+
+  return FALSE;
+}
+
+SILC_PKCS_API_ENCRYPT(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  int i, tmplen;
+  SilcInt mp_tmp;
+  SilcInt mp_dst;
+
+  silc_mp_init_set_ui(&mp_tmp, 0);
+  silc_mp_init_set_ui(&mp_dst, 0);
+
+  /* Format the data into MP int */
+  for (i = 0; i < src_len; i++) {
+    silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+    silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
+  }
+
+  silc_mp_out_str(stderr, 16, &mp_tmp);
+
+  /* Encrypt */
+  rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->e, &key->n);
+  
+  fprintf(stderr, "\n");
+  silc_mp_out_str(stderr, 16, &mp_dst);
+
+  tmplen = (1024 + 7) / 8;
+
+  /* Format the MP int back into data */
+  for (i = tmplen; i > 0; i--) {
+    dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
+    silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
+  }
+  *dst_len = tmplen;
+
+  silc_mp_clear(&mp_tmp);
+  silc_mp_clear(&mp_dst);
+
+  return TRUE;
+}
+
+SILC_PKCS_API_DECRYPT(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  int i, tmplen;
+  SilcInt mp_tmp;
+  SilcInt mp_dst;
+
+  silc_mp_init_set_ui(&mp_tmp, 0);
+  silc_mp_init_set_ui(&mp_dst, 0);
+
+  /* Format the data into MP int */
+  for (i = 0; i < src_len; i++) {
+    silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+    silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
+  }
+
+  silc_mp_out_str(stderr, 16, &mp_tmp);
+
+  /* Decrypt */
+  rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->d, &key->n);
+
+  fprintf(stderr, "\n");
+  silc_mp_out_str(stderr, 16, &mp_dst);
+
+  tmplen = (1024 + 7) / 8;
+
+  /* Format the MP int back into data */
+  for (i = tmplen; i > 0; i--) {
+    dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
+    silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
+  }
+  *dst_len = tmplen;
+
+  silc_mp_clear(&mp_tmp);
+  silc_mp_clear(&mp_dst);
+
+  return TRUE;
+}
+
+SILC_PKCS_API_SIGN(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  int i, tmplen;
+  SilcInt mp_tmp;
+  SilcInt mp_dst;
+
+  silc_mp_init_set_ui(&mp_tmp, 0);
+  silc_mp_init_set_ui(&mp_dst, 0);
+
+  /* Format the data into MP int */
+  for (i = 0; i < src_len; i++) {
+    silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+    silc_mp_add_ui(&mp_tmp, &mp_tmp, src[i]);
+  }
+
+  /* Sign */
+  rsa_en_de_crypt(&mp_dst, &mp_tmp, &key->d, &key->n);
+
+  tmplen = (1024 + 7) / 8;
+
+  /* Format the MP int back into data */
+  for (i = tmplen; i > 0; i--) {
+    dst[i - 1] = (unsigned char)(silc_mp_get_ui(&mp_dst) & 0xff);
+    silc_mp_fdiv_q_2exp(&mp_dst, &mp_dst, 8);
+  }
+  *dst_len = tmplen;
+
+  silc_mp_clear(&mp_tmp);
+  silc_mp_clear(&mp_dst);
+
+  return TRUE;
+}
+
+SILC_PKCS_API_VERIFY(rsa)
+{
+  RsaKey *key = (RsaKey *)context;
+  int i, ret;
+  SilcInt mp_tmp, mp_tmp2;
+  SilcInt mp_dst;
+
+  silc_mp_init_set_ui(&mp_tmp, 0);
+  silc_mp_init_set_ui(&mp_tmp2, 0);
+  silc_mp_init_set_ui(&mp_dst, 0);
+
+  /* Format the signature into MP int */
+  for (i = 0; i < signature_len; i++) {
+    silc_mp_mul_2exp(&mp_tmp2, &mp_tmp2, 8);
+    silc_mp_add_ui(&mp_tmp2, &mp_tmp2, signature[i]);
+  }
+
+  /* Verify */
+  rsa_en_de_crypt(&mp_dst, &mp_tmp2, &key->e, &key->n);
+
+  /* Format the data into MP int */
+  for (i = 0; i < data_len; i++) {
+    silc_mp_mul_2exp(&mp_tmp, &mp_tmp, 8);
+    silc_mp_add_ui(&mp_tmp, &mp_tmp, data[i]);
+  }
+
+  ret = TRUE;
+
+  /* Compare */
+  if ((silc_mp_cmp(&mp_tmp, &mp_dst)) != 0)
+    ret = FALSE;
+
+  silc_mp_clear(&mp_tmp);
+  silc_mp_clear(&mp_tmp2);
+  silc_mp_clear(&mp_dst);
+
+  return ret;
+}
+
+/* Generates RSA public and private keys. Primes p and q that are used
+   to compute the modulus n has to be generated before calling this. They
+   are then sent as argument for the function. */
+
+void rsa_generate_keys(RsaKey *key, unsigned int bits, 
+                      SilcInt *p, SilcInt *q)
+{
+  SilcInt phi, hlp;
+  SilcInt dq;
+  SilcInt pm1, qm1;
+  
+  /* Initialize variables */
+  silc_mp_init(&key->p);
+  silc_mp_init(&key->q);
+  silc_mp_init(&key->n);
+  silc_mp_init(&key->e);
+  silc_mp_init(&key->d);
+  silc_mp_init(&phi);
+  silc_mp_init(&hlp);
+  silc_mp_init(&dq);
+  silc_mp_init(&pm1);
+  silc_mp_init(&qm1);
+
+  /* Set the primes */
+  silc_mp_set(&key->p, p);
+  silc_mp_set(&key->q, q);
+  
+  /* Compute modulus, n = p * q */
+  silc_mp_mul(&key->n, &key->p, &key->q);
+  
+  /* phi = (p - 1) * (q - 1) */
+  silc_mp_sub_ui(&pm1, &key->p, 1);
+  silc_mp_sub_ui(&qm1, &key->q, 1);
+  silc_mp_mul(&phi, &pm1, &qm1);
+  
+  /* Set e, the public exponent. We try to use same public exponent
+     for all keys. Also, to make encryption faster we use small 
+     number. */
+  silc_mp_set_ui(&key->e, 127);
+ retry_e:
+  /* See if e is relatively prime to phi. gcd == greates common divisor,
+     if gcd equals 1 they are relatively prime. */
+  silc_mp_gcd(&hlp, &key->e, &phi);
+  if((silc_mp_cmp_ui(&hlp, 1)) > 0) {
+    silc_mp_add_ui(&key->e, &key->e, 2);
+    goto retry_e;
+  }
+  
+  /* Find d, the private exponent. First we do phi / 2, to get it a 
+     bit smaller */
+  silc_mp_div_ui(&dq, &phi, 2);
+  silc_mp_modinv(&key->d, &key->e, &dq);
+  
+  silc_mp_clear(&phi);
+  silc_mp_clear(&hlp);
+  silc_mp_clear(&dq);
+  silc_mp_clear(&pm1);
+  silc_mp_clear(&qm1);
+}
+
+/* Clears whole key structure. */
+
+void rsa_clear_keys(RsaKey *key)
+{
+  key->bits = 0;
+  silc_mp_clear(&key->p);
+  silc_mp_clear(&key->q);
+  silc_mp_clear(&key->n);
+  silc_mp_clear(&key->e);
+  silc_mp_clear(&key->d);
+}
+
+/* RSA encrypt/decrypt function. cm = ciphertext or plaintext,
+   mc = plaintext or ciphertext, expo = public or private exponent,
+   and modu = modulus. 
+
+   Encrypt: c = m ^ e mod n,
+   Decrypt: m = c ^ d mod n 
+*/
+
+void rsa_en_de_crypt(SilcInt *cm, SilcInt *mc, 
+                    SilcInt *expo, SilcInt *modu)
+{
+  silc_mp_powm(cm, mc, expo, modu);
+}
diff --git a/lib/silccrypt/rsa.h b/lib/silccrypt/rsa.h
new file mode 100644 (file)
index 0000000..6244fef
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+
+  rsa.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef RSA_H
+#define RSA_H
+
+#include "rsa_internal.h"
+
+/* Data context for RSA */
+typedef struct {
+  SilcInt src;
+  SilcInt dst;
+  SilcInt exp;
+  SilcInt mod;
+} RsaDataContext;
+
+RsaDataContext *silc_rsa_data_context;
+
+/*
+ * SILC PKCS API for RSA
+ */
+
+SILC_PKCS_API_INIT(rsa);
+SILC_PKCS_API_CLEAR_KEYS(rsa);
+SILC_PKCS_API_GET_PUBLIC_KEY(rsa);
+SILC_PKCS_API_GET_PRIVATE_KEY(rsa);
+SILC_PKCS_API_SET_PUBLIC_KEY(rsa);
+SILC_PKCS_API_SET_PRIVATE_KEY(rsa);
+SILC_PKCS_API_CONTEXT_LEN(rsa);
+SILC_PKCS_API_DATA_CONTEXT_LEN(rsa);
+SILC_PKCS_API_SET_ARG(rsa);
+SILC_PKCS_API_ENCRYPT(rsa);
+SILC_PKCS_API_DECRYPT(rsa);
+SILC_PKCS_API_SIGN(rsa);
+SILC_PKCS_API_VERIFY(rsa);
+
+
+#endif
diff --git a/lib/silccrypt/rsa_internal.h b/lib/silccrypt/rsa_internal.h
new file mode 100644 (file)
index 0000000..ab18c61
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+
+  rsa_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef RSA_INTERNAL_H
+#define RSA_INTERNAL_H
+
+/* RSA Keys, includes both Private and Public key */
+typedef struct {
+  int bits;                    /* bits in key */
+  SilcInt p;                   /* prime p */
+  SilcInt q;                   /* prime q */
+  SilcInt n;                   /* modulus */
+  SilcInt e;                   /* public exponent */
+  SilcInt d;                   /* private exponent */
+} RsaKey;
+
+void rsa_generate_keys(RsaKey *key, unsigned int bits, 
+                      SilcInt *p, SilcInt *q);
+void rsa_clear_keys(RsaKey *key);
+void rsa_en_de_crypt(SilcInt *cm, SilcInt *mc, 
+                    SilcInt *expo, SilcInt *modu);
+
+#endif
diff --git a/lib/silccrypt/safer.c b/lib/silccrypt/safer.c
new file mode 100644 (file)
index 0000000..bb0a3bc
--- /dev/null
@@ -0,0 +1,379 @@
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         SAFER+ by Cylink                                             */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+\r
+/* Timing data for SAFER+ (safer.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    4278 cycles\r
+Encrypt:      1722 cycles =    14.9 mbits/sec\r
+Decrypt:      1709 cycles =    15.0 mbits/sec\r
+Mean:         1716 cycles =    14.9 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    7426 cycles\r
+Encrypt:      2555 cycles =    10.0 mbits/sec\r
+Decrypt:      2530 cycles =    10.1 mbits/sec\r
+Mean:         2543 cycles =    10.1 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:   11313 cycles\r
+Encrypt:      3391 cycles =     7.5 mbits/sec\r
+Decrypt:      3338 cycles =     7.7 mbits/sec\r
+Mean:         3365 cycles =     7.6 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    3977 cycles\r
+Encrypt:      1751 cycles =    14.6 mbits/sec\r
+Decrypt:      1734 cycles =    14.8 mbits/sec\r
+Mean:         1743 cycles =    14.7 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    6490 cycles\r
+Encrypt:      2574 cycles =     9.9 mbits/sec\r
+Decrypt:      2549 cycles =    10.0 mbits/sec\r
+Mean:         2562 cycles =    10.0 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    9487 cycles\r
+Encrypt:      3412 cycles =     7.5 mbits/sec\r
+Decrypt:      3372 cycles =     7.6 mbits/sec\r
+Mean:         3392 cycles =     7.5 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "safer_internal.h"\r
+\r
+u1byte  expf[256] =\r
+{     1,  45, 226, 147, 190,  69,  21, 174, 120,   3, 135, 164, 184,  56, 207,  63, \r
+      8, 103,   9, 148, 235,  38, 168, 107, 189,  24,  52,  27, 187, 191, 114, 247, \r
+     64,  53,  72, 156,  81,  47,  59,  85, 227, 192, 159, 216, 211, 243, 141, 177, \r
+    255, 167,  62, 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, \r
+    241,  51, 239, 218,  44, 181, 178,  43, 136, 209, 153, 203, 140, 132,  29,  20, \r
+    129, 151, 113, 202,  95, 163, 139,  87,  60, 130, 196,  82,  92,  28, 232, 160, \r
+      4, 180, 133,  74, 246,  19,  84, 182, 223,  12,  26, 142, 222, 224,  57, 252, \r
+     32, 155,  36,  78, 169, 152, 158, 171, 242,  96, 208, 108, 234, 250, 199, 217, \r
+      0, 212,  31, 110,  67, 188, 236,  83, 137, 254, 122,  93,  73, 201,  50, 194, \r
+    249, 154, 248, 109,  22, 219,  89, 150,  68, 233, 205, 230,  70,  66, 143,  10, \r
+    193, 204, 185, 101, 176, 210, 198, 172,  30,  65,  98,  41,  46,  14, 116,  80, \r
+      2,  90, 195,  37, 123, 138,  42,  91, 240,   6,  13,  71, 111, 112, 157, 126, \r
+     16, 206,  18,  39, 213,  76,  79, 214, 121,  48, 104,  54, 117, 125, 228, 237, \r
+    128, 106, 144,  55, 162,  94, 118, 170, 197, 127,  61, 175, 165, 229,  25,  97, \r
+    253,  77, 124, 183,  11, 238, 173,  75,  34, 245, 231, 115,  35,  33, 200,   5, \r
+    225, 102, 221, 179,  88, 105,  99,  86,  15, 161,  49, 149,  23,   7,  58,  40 \r
+};\r
+\r
+u1byte logf[512] = \r
+{\r
+    128,   0, 176,   9,  96, 239, 185, 253,  16,  18, 159, 228, 105, 186, 173, 248, \r
+    192,  56, 194, 101,  79,   6, 148, 252,  25, 222, 106,  27,  93,  78, 168, 130, \r
+    112, 237, 232, 236, 114, 179,  21, 195, 255, 171, 182,  71,  68,   1, 172,  37, \r
+    201, 250, 142,  65,  26,  33, 203, 211,  13, 110, 254,  38,  88, 218,  50,  15, \r
+     32, 169, 157, 132, 152,   5, 156, 187,  34, 140,  99, 231, 197, 225, 115, 198, \r
+    175,  36,  91, 135, 102,  39, 247,  87, 244, 150, 177, 183,  92, 139, 213,  84, \r
+    121, 223, 170, 246,  62, 163, 241,  17, 202, 245, 209,  23, 123, 147, 131, 188, \r
+    189,  82,  30, 235, 174, 204, 214,  53,   8, 200, 138, 180, 226, 205, 191, 217, \r
+    208,  80,  89,  63,  77,  98,  52,  10,  72, 136, 181,  86,  76,  46, 107, 158, \r
+    210,  61,  60,   3,  19, 251, 151,  81, 117,  74, 145, 113,  35, 190, 118,  42, \r
+     95, 249, 212,  85,  11, 220,  55,  49,  22, 116, 215, 119, 167, 230,   7, 219, \r
+    164,  47,  70, 243,  97,  69, 103, 227,  12, 162,  59,  28, 133,  24,   4,  29, \r
+     41, 160, 143, 178,  90, 216, 166, 126, 238, 141,  83,  75, 161, 154, 193,  14, \r
+    122,  73, 165,  44, 129, 196, 199,  54,  43, 127,  67, 149,  51, 242, 108, 104, \r
+    109, 240,   2,  40, 206, 221, 155, 234,  94, 153, 124,  20, 134, 207, 229,  66, \r
+    184,  64, 120,  45,  58, 233, 100,  31, 146, 144, 125,  57, 111, 224, 137,  48,\r
+\r
+    128,   0, 176,   9,  96, 239, 185, 253,  16,  18, 159, 228, 105, 186, 173, 248, \r
+    192,  56, 194, 101,  79,   6, 148, 252,  25, 222, 106,  27,  93,  78, 168, 130, \r
+    112, 237, 232, 236, 114, 179,  21, 195, 255, 171, 182,  71,  68,   1, 172,  37, \r
+    201, 250, 142,  65,  26,  33, 203, 211,  13, 110, 254,  38,  88, 218,  50,  15, \r
+     32, 169, 157, 132, 152,   5, 156, 187,  34, 140,  99, 231, 197, 225, 115, 198, \r
+    175,  36,  91, 135, 102,  39, 247,  87, 244, 150, 177, 183,  92, 139, 213,  84, \r
+    121, 223, 170, 246,  62, 163, 241,  17, 202, 245, 209,  23, 123, 147, 131, 188, \r
+    189,  82,  30, 235, 174, 204, 214,  53,   8, 200, 138, 180, 226, 205, 191, 217, \r
+    208,  80,  89,  63,  77,  98,  52,  10,  72, 136, 181,  86,  76,  46, 107, 158, \r
+    210,  61,  60,   3,  19, 251, 151,  81, 117,  74, 145, 113,  35, 190, 118,  42, \r
+     95, 249, 212,  85,  11, 220,  55,  49,  22, 116, 215, 119, 167, 230,   7, 219, \r
+    164,  47,  70, 243,  97,  69, 103, 227,  12, 162,  59,  28, 133,  24,   4,  29, \r
+     41, 160, 143, 178,  90, 216, 166, 126, 238, 141,  83,  75, 161, 154, 193,  14, \r
+    122,  73, 165,  44, 129, 196, 199,  54,  43, 127,  67, 149,  51, 242, 108, 104, \r
+    109, 240,   2,  40, 206, 221, 155, 234,  94, 153, 124,  20, 134, 207, 229,  66, \r
+    184,  64, 120,  45,  58, 233, 100,  31, 146, 144, 125,  57, 111, 224, 137,  48\r
+};\r
+\r
+u4byte *safer_set_key(SaferContext *ctx,\r
+                     const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u1byte  by, lk[33];\r
+    u4byte  i, j, k, l, m;\r
+    u1byte *l_key = ctx->l_key;\r
+\r
+    get_key(lk, key_len);\r
+\r
+    ctx->k_bytes = k_bytes = key_len / 8; lk[k_bytes] = 0;\r
+\r
+    for(i = 0; i < k_bytes; ++i)\r
+    {\r
+        lk[k_bytes] ^= lk[i]; l_key[i] = lk[i];\r
+    }\r
+\r
+    for(i = 0; i < k_bytes; ++i)\r
+    {\r
+        for(j = 0; j <= k_bytes; ++j)\r
+        {\r
+            by = lk[j]; lk[j] = by << 3 | by >> 5;\r
+        }\r
+\r
+        k = 17 * i + 35; l = 16 * i + 16; m = i + 1;\r
+\r
+        if(i < 16)\r
+        {\r
+            for(j = 0; j < 16; ++j)\r
+            {\r
+                l_key[l + j] = lk[m] + expf[expf[(k + j) & 255]];\r
+\r
+                m = (m == k_bytes ? 0 : m + 1);\r
+            }\r
+        }\r
+        else\r
+        {\r
+            for(j = 0; j < 16; ++j)\r
+            {\r
+                l_key[l + j] = lk[m] + expf[(k + j) & 255];\r
+\r
+                m = (m == k_bytes ? 0 : m + 1);\r
+            }\r
+        }\r
+    }\r
+    return (u4byte*)l_key;\r
+};\r
+\r
+void do_fr(u1byte x[16], u1byte *kp)\r
+{   u1byte  t;\r
+\r
+    x[ 0] = expf[x[ 0] ^ kp[ 0]] + kp[16];\r
+    x[ 1] = logf[x[ 1] + kp[ 1]] ^ kp[17]; \r
+    x[ 2] = logf[x[ 2] + kp[ 2]] ^ kp[18]; \r
+    x[ 3] = expf[x[ 3] ^ kp[ 3]] + kp[19];\r
+\r
+    x[ 4] = expf[x[ 4] ^ kp[ 4]] + kp[20];\r
+    x[ 5] = logf[x[ 5] + kp[ 5]] ^ kp[21]; \r
+    x[ 6] = logf[x[ 6] + kp[ 6]] ^ kp[22]; \r
+    x[ 7] = expf[x[ 7] ^ kp[ 7]] + kp[23];\r
\r
+    x[ 8] = expf[x[ 8] ^ kp[ 8]] + kp[24];\r
+    x[ 9] = logf[x[ 9] + kp[ 9]] ^ kp[25]; \r
+    x[10] = logf[x[10] + kp[10]] ^ kp[26]; \r
+    x[11] = expf[x[11] ^ kp[11]] + kp[27];\r
+\r
+    x[12] = expf[x[12] ^ kp[12]] + kp[28];\r
+    x[13] = logf[x[13] + kp[13]] ^ kp[29]; \r
+    x[14] = logf[x[14] + kp[14]] ^ kp[30]; \r
+    x[15] = expf[x[15] ^ kp[15]] + kp[31];\r
+\r
+    x[ 1] += x[ 0]; x[ 0] += x[ 1];\r
+    x[ 3] += x[ 2]; x[ 2] += x[ 3];\r
+    x[ 5] += x[ 4]; x[ 4] += x[ 5];\r
+    x[ 7] += x[ 6]; x[ 6] += x[ 7];\r
+    x[ 9] += x[ 8]; x[ 8] += x[ 9];\r
+    x[11] += x[10]; x[10] += x[11];\r
+    x[13] += x[12]; x[12] += x[13];\r
+    x[15] += x[14]; x[14] += x[15];\r
+\r
+    x[ 7] += x[ 0]; x[ 0] += x[ 7];\r
+    x[ 1] += x[ 2]; x[ 2] += x[ 1];\r
+    x[ 3] += x[ 4]; x[ 4] += x[ 3];\r
+    x[ 5] += x[ 6]; x[ 6] += x[ 5];\r
+    x[11] += x[ 8]; x[ 8] += x[11];\r
+    x[ 9] += x[10]; x[10] += x[ 9];\r
+    x[15] += x[12]; x[12] += x[15];\r
+    x[13] += x[14]; x[14] += x[13];\r
+\r
+    x[ 3] += x[ 0]; x[ 0] += x[ 3];\r
+    x[15] += x[ 2]; x[ 2] += x[15];\r
+    x[ 7] += x[ 4]; x[ 4] += x[ 7];\r
+    x[ 1] += x[ 6]; x[ 6] += x[ 1];\r
+    x[ 5] += x[ 8]; x[ 8] += x[ 5];\r
+    x[13] += x[10]; x[10] += x[13];\r
+    x[11] += x[12]; x[12] += x[11];\r
+    x[ 9] += x[14]; x[14] += x[ 9];\r
+\r
+    x[13] += x[ 0]; x[ 0] += x[13];\r
+    x[ 5] += x[ 2]; x[ 2] += x[ 5];\r
+    x[ 9] += x[ 4]; x[ 4] += x[ 9];\r
+    x[11] += x[ 6]; x[ 6] += x[11];\r
+    x[15] += x[ 8]; x[ 8] += x[15];\r
+    x[ 1] += x[10]; x[10] += x[ 1];\r
+    x[ 3] += x[12]; x[12] += x[ 3];\r
+    x[ 7] += x[14]; x[14] += x[ 7];\r
+\r
+    t = x[0]; x[0] = x[14]; x[14] = x[12]; x[12] = x[10]; x[10] = x[2]; \r
+    x[2] = x[8]; x[8] = x[4]; x[4] = t;\r
+\r
+    t = x[1]; x[1] = x[7]; x[7] = x[11]; x[11] = x[5]; x[5] = x[13]; x[13] = t; \r
+    \r
+    t = x[15]; x[15] = x[3]; x[3] = t;\r
+};\r
+\r
+void do_ir(u1byte x[16], u1byte *kp)\r
+{   u1byte  t;\r
+\r
+    t = x[3]; x[3] = x[15]; x[15] = t; \r
+\r
+    t = x[13]; x[13] = x[5]; x[5] = x[11]; x[11] = x[7]; x[7] = x[1]; x[1] = t; \r
+\r
+    t = x[4]; x[4] = x[8]; x[8] = x[2]; x[2] = x[10]; \r
+    x[10] = x[12]; x[12] = x[14]; x[14] = x[0]; x[0] = t; \r
+\r
+    x[14] -= x[ 7]; x[ 7] -= x[14]; \r
+    x[12] -= x[ 3]; x[ 3] -= x[12];\r
+    x[10] -= x[ 1]; x[ 1] -= x[10];\r
+    x[ 8] -= x[15]; x[15] -= x[ 8];\r
+    x[ 6] -= x[11]; x[11] -= x[ 6]; \r
+    x[ 4] -= x[ 9]; x[ 9] -= x[ 4];\r
+    x[ 2] -= x[ 5]; x[ 5] -= x[ 2]; \r
+    x[ 0] -= x[13]; x[13] -= x[ 0]; \r
+\r
+    x[14] -= x[ 9]; x[ 9] -= x[14]; \r
+    x[12] -= x[11]; x[11] -= x[12]; \r
+    x[10] -= x[13]; x[13] -= x[10]; \r
+    x[ 8] -= x[ 5]; x[ 5] -= x[ 8]; \r
+    x[ 6] -= x[ 1]; x[ 1] -= x[ 6]; \r
+    x[ 4] -= x[ 7]; x[ 7] -= x[ 4]; \r
+    x[ 2] -= x[15]; x[15] -= x[ 2]; \r
+    x[ 0] -= x[ 3]; x[ 3] -= x[ 0]; \r
+\r
+    x[14] -= x[13]; x[13] -= x[14]; \r
+    x[12] -= x[15]; x[15] -= x[12]; \r
+    x[10] -= x[ 9]; x[ 9] -= x[10]; \r
+    x[ 8] -= x[11]; x[11] -= x[ 8];     \r
+    x[ 6] -= x[ 5]; x[ 5] -= x[ 6]; \r
+    x[ 4] -= x[ 3]; x[ 3] -= x[ 4]; \r
+    x[ 2] -= x[ 1]; x[ 1] -= x[ 2]; \r
+    x[ 0] -= x[ 7]; x[ 7] -= x[ 0]; \r
+\r
+    x[14] -= x[15]; x[15] -= x[14]; \r
+    x[12] -= x[13]; x[13] -= x[12];\r
+    x[10] -= x[11]; x[11] -= x[10]; \r
+    x[ 8] -= x[ 9]; x[ 9] -= x[ 8]; \r
+    x[ 6] -= x[ 7]; x[ 7] -= x[ 6];\r
+    x[ 4] -= x[ 5]; x[ 5] -= x[ 4]; \r
+    x[ 2] -= x[ 3]; x[ 3] -= x[ 2]; \r
+    x[ 0] -= x[ 1]; x[ 1] -= x[ 0]; \r
+    \r
+    x[ 0] = logf[x[ 0] - kp[16] + 256] ^ kp[ 0];\r
+    x[ 1] = expf[x[ 1] ^ kp[17]] - kp[ 1];\r
+    x[ 2] = expf[x[ 2] ^ kp[18]] - kp[ 2];\r
+    x[ 3] = logf[x[ 3] - kp[19] + 256] ^ kp[ 3];\r
+\r
+    x[ 4] = logf[x[ 4] - kp[20] + 256] ^ kp[ 4];\r
+    x[ 5] = expf[x[ 5] ^ kp[21]] - kp[ 5];\r
+    x[ 6] = expf[x[ 6] ^ kp[22]] - kp[ 6];\r
+    x[ 7] = logf[x[ 7] - kp[23] + 256] ^ kp[ 7];\r
+\r
+    x[ 8] = logf[x[ 8] - kp[24] + 256] ^ kp[ 8];\r
+    x[ 9] = expf[x[ 9] ^ kp[25]] - kp[ 9];\r
+    x[10] = expf[x[10] ^ kp[26]] - kp[10];\r
+    x[11] = logf[x[11] - kp[27] + 256] ^ kp[11];\r
+\r
+    x[12] = logf[x[12] - kp[28] + 256] ^ kp[12];\r
+    x[13] = expf[x[13] ^ kp[29]] - kp[13];\r
+    x[14] = expf[x[14] ^ kp[30]] - kp[14];\r
+    x[15] = logf[x[15] - kp[31] + 256] ^ kp[15];\r
+};\r
+\r
+void safer_encrypt(SaferContext *ctx,\r
+                  const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u1byte  blk[16], *kp;\r
+    u1byte *l_key = ctx->l_key;\r
+    u4byte k_bytes = ctx->k_bytes;\r
+\r
+    get_block(blk);\r
+\r
+    do_fr(blk, l_key);       do_fr(blk, l_key +  32); \r
+    do_fr(blk, l_key +  64); do_fr(blk, l_key +  96);\r
+    do_fr(blk, l_key + 128); do_fr(blk, l_key + 160);\r
+    do_fr(blk, l_key + 192); do_fr(blk, l_key + 224);\r
+    \r
+    if(k_bytes > 16)\r
+    {\r
+        do_fr(blk, l_key + 256); do_fr(blk, l_key + 288); \r
+        do_fr(blk, l_key + 320); do_fr(blk, l_key + 352);\r
+    }\r
+\r
+    if(k_bytes > 24)\r
+    {\r
+        do_fr(blk, l_key + 384); do_fr(blk, l_key + 416); \r
+        do_fr(blk, l_key + 448); do_fr(blk, l_key + 480);\r
+    }\r
+\r
+    kp = l_key + 16 * k_bytes;\r
+\r
+    blk[ 0] ^= kp[ 0]; blk[ 1] += kp[ 1];\r
+    blk[ 2] += kp[ 2]; blk[ 3] ^= kp[ 3]; \r
+    blk[ 4] ^= kp[ 4]; blk[ 5] += kp[ 5];\r
+    blk[ 6] += kp[ 6]; blk[ 7] ^= kp[ 7]; \r
+    blk[ 8] ^= kp[ 8]; blk[ 9] += kp[ 9];\r
+    blk[10] += kp[10]; blk[11] ^= kp[11]; \r
+    blk[12] ^= kp[12]; blk[13] += kp[13];\r
+    blk[14] += kp[14]; blk[15] ^= kp[15]; \r
+\r
+    put_block(blk);\r
+};\r
+\r
+void safer_decrypt(SaferContext *ctx,\r
+                  const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u1byte  blk[16], *kp;\r
+    u1byte *l_key = ctx->l_key;\r
+    u4byte k_bytes = ctx->k_bytes;\r
+\r
+    get_block(blk);\r
+\r
+    kp = l_key + 16 * k_bytes;\r
+\r
+    blk[ 0] ^= kp[ 0]; blk[ 1] -= kp[ 1];\r
+    blk[ 2] -= kp[ 2]; blk[ 3] ^= kp[ 3];\r
+    blk[ 4] ^= kp[ 4]; blk[ 5] -= kp[ 5];\r
+    blk[ 6] -= kp[ 6]; blk[ 7] ^= kp[ 7];\r
+    blk[ 8] ^= kp[ 8]; blk[ 9] -= kp[ 9];\r
+    blk[10] -= kp[10]; blk[11] ^= kp[11];\r
+    blk[12] ^= kp[12]; blk[13] -= kp[13];\r
+    blk[14] -= kp[14]; blk[15] ^= kp[15];\r
+\r
+    if(k_bytes > 24)\r
+    {\r
+        do_ir(blk, l_key + 480); do_ir(blk, l_key + 448); \r
+        do_ir(blk, l_key + 416); do_ir(blk, l_key + 384);\r
+    }\r
+\r
+    if(k_bytes > 16)\r
+    {\r
+        do_ir(blk, l_key + 352); do_ir(blk, l_key + 320); \r
+        do_ir(blk, l_key + 288); do_ir(blk, l_key + 256);\r
+    }\r
+\r
+    do_ir(blk, l_key + 224); do_ir(blk, l_key + 192); \r
+    do_ir(blk, l_key + 160); do_ir(blk, l_key + 128);\r
+    do_ir(blk, l_key +  96); do_ir(blk, l_key +  64); \r
+    do_ir(blk, l_key +  32); do_ir(blk, l_key);\r
+\r
+    put_block(blk);\r
+};\r
diff --git a/lib/silccrypt/safer.h b/lib/silccrypt/safer.h
new file mode 100644 (file)
index 0000000..063be80
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+
+  safer.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef SAFER_H
+#define SAFER_H
+
+#include "safer_internal.h"
+
+/* 
+ * SILC Crypto API for Safer
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_safer_init(void *context, 
+                          const unsigned char *key, 
+                          size_t keylen)
+{
+  safer_set_key((SaferContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+inline int silc_safer_set_string_as_key(void *context, 
+                                       const unsigned char *string,
+                                       size_t keylen)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_safer_context_len()
+{
+  return sizeof(SaferContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_safer_encrypt_cbc(void *context,
+                                 const unsigned char *src,
+                                 unsigned char *dst,
+                                 size_t len,
+                                 unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  safer_encrypt((SaferContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    safer_encrypt((SaferContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_safer_decrypt_cbc(void *context,
+                                 const unsigned char *src,
+                                 unsigned char *dst,
+                                 size_t len,
+                                 unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  safer_decrypt((SaferContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    safer_decrypt((SaferContext *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/safer_internal.h b/lib/silccrypt/safer_internal.h
new file mode 100644 (file)
index 0000000..ee3bb1b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+
+  safer_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SAFER_INTERNAL_H
+#define SAFER_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+  u1byte l_key[33 * 16];
+  u4byte k_bytes;
+} SaferContext;
+
+/* Prototypes */
+u4byte *safer_set_key(SaferContext *ctx,
+                     const u4byte in_key[], const u4byte key_len);
+void safer_encrypt(SaferContext *ctx,
+                  const u4byte in_blk[4], u4byte out_blk[4]);
+void safer_decrypt(SaferContext *ctx,
+                  const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/serpent.c b/lib/silccrypt/serpent.c
new file mode 100644 (file)
index 0000000..63640c8
--- /dev/null
@@ -0,0 +1,657 @@
+/* Modified for SILC. -Pekka */x\r
+\r
+/* This is an independent implementation of the encryption algorithm:   */\r
+/*                                                                      */\r
+/*         Serpent by Ross Anderson, Eli Biham and Lars Knudsen         */\r
+/*                                                                      */\r
+/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
+/* programme of the US National Institute of Standards and Technology.  */\r
+/*                                                                      */\r
+/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
+/* hereby give permission for its free direct or derivative use subject */\r
+/* to acknowledgment of its origin and compliance with any conditions   */\r
+/* that the originators of the algorithm place on its exploitation.     */\r
+/*                                                                      */\r
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
+\r
+/* Timing data for Serpent (serpent.c)\r
+\r
+Core timing without I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    2402 cycles\r
+Encrypt:       952 cycles =    26.9 mbits/sec\r
+Decrypt:       914 cycles =    28.0 mbits/sec\r
+Mean:          933 cycles =    27.4 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    2449 cycles\r
+Encrypt:       952 cycles =    26.9 mbits/sec\r
+Decrypt:       914 cycles =    28.0 mbits/sec\r
+Mean:          933 cycles =    27.4 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    2349 cycles\r
+Encrypt:       952 cycles =    26.9 mbits/sec\r
+Decrypt:       914 cycles =    28.0 mbits/sec\r
+Mean:          933 cycles =    27.4 mbits/sec\r
+\r
+Full timing with I/O endian conversion:\r
+\r
+128 bit key:\r
+Key Setup:    2415 cycles\r
+Encrypt:       985 cycles =    26.0 mbits/sec\r
+Decrypt:       954 cycles =    26.8 mbits/sec\r
+Mean:          970 cycles =    26.4 mbits/sec\r
+\r
+192 bit key:\r
+Key Setup:    2438 cycles\r
+Encrypt:       985 cycles =    26.0 mbits/sec\r
+Decrypt:       954 cycles =    26.8 mbits/sec\r
+Mean:          970 cycles =    26.4 mbits/sec\r
+\r
+256 bit key:\r
+Key Setup:    2463 cycles\r
+Encrypt:       985 cycles =    26.0 mbits/sec\r
+Decrypt:       954 cycles =    26.8 mbits/sec\r
+Mean:          970 cycles =    26.4 mbits/sec\r
+\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <sys/types.h>\r
+#include "serpent_internal.h"\r
+\r
+/* Partially optimised Serpent S Box boolean functions derived  */\r
+/* using a recursive descent analyser but without a full search */\r
+/* of all subtrees. This set of S boxes is the result of work   */\r
+/* by Sam Simpson and Brian Gladman using the spare time on a   */\r
+/* cluster of high capacity servers to search for S boxes with  */\r
+/* this customised search engine.                               */\r
+/*                                                              */\r
+/* Copyright:   Dr B. R Gladman (gladman@seven77.demon.co.uk)   */\r
+/*              and Sam Simpson (s.simpson@mia.co.uk)           */ \r
+/*              17th December 1998                              */\r
+/*                                                              */\r
+/* We hereby give permission for information in this file to be */\r
+/* used freely subject only to acknowledgement of its origin    */\r
+\r
+/* 15 terms */\r
+\r
+#define sb0(a,b,c,d,e,f,g,h)    \\r
+    t1 = a ^ d;     \\r
+    t2 = a & d;     \\r
+    t3 = c ^ t1;    \\r
+    t6 = b & t1;    \\r
+    t4 = b ^ t3;    \\r
+    t10 = ~t3;      \\r
+    h = t2 ^ t4;    \\r
+    t7 = a ^ t6;    \\r
+    t14 = ~t7;      \\r
+    t8 = c | t7;    \\r
+    t11 = t3 ^ t7;  \\r
+    g = t4 ^ t8;    \\r
+    t12 = h & t11;  \\r
+    f = t10 ^ t12;  \\r
+    e = t12 ^ t14\r
+\r
+/* 15 terms */\r
+\r
+#define ib0(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~a;        \\r
+    t2 = a ^ b;     \\r
+    t3 = t1 | t2;   \\r
+    t4 = d ^ t3;    \\r
+    t7 = d & t2;    \\r
+    t5 = c ^ t4;    \\r
+    t8 = t1 ^ t7;   \\r
+    g = t2 ^ t5;    \\r
+    t11 = a & t4;   \\r
+    t9 = g & t8;    \\r
+    t14 = t5 ^ t8;  \\r
+    f = t4 ^ t9;    \\r
+    t12 = t5 | f;   \\r
+    h = t11 ^ t12;  \\r
+    e = h ^ t14\r
+\r
+/* 14 terms!  */\r
+\r
+#define sb1(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~a;        \\r
+    t2 = b ^ t1;    \\r
+    t3 = a | t2;    \\r
+    t4 = d | t2;    \\r
+    t5 = c ^ t3;    \\r
+    g = d ^ t5;     \\r
+    t7 = b ^ t4;    \\r
+    t8 = t2 ^ g;    \\r
+    t9 = t5 & t7;   \\r
+    h = t8 ^ t9;    \\r
+    t11 = t5 ^ t7;  \\r
+    f = h ^ t11;    \\r
+    t13 = t8 & t11; \\r
+    e = t5 ^ t13\r
+\r
+/* 17 terms */\r
+\r
+#define ib1(a,b,c,d,e,f,g,h)    \\r
+    t1 = a ^ d;     \\r
+    t2 = a & b;     \\r
+    t3 = b ^ c;     \\r
+    t4 = a ^ t3;    \\r
+    t5 = b | d;     \\r
+    t7 = c | t1;    \\r
+    h = t4 ^ t5;    \\r
+    t8 = b ^ t7;    \\r
+    t11 = ~t2;      \\r
+    t9 = t4 & t8;   \\r
+    f = t1 ^ t9;    \\r
+    t13 = t9 ^ t11; \\r
+    t12 = h & f;    \\r
+    g = t12 ^ t13;  \\r
+    t15 = a & d;    \\r
+    t16 = c ^ t13;  \\r
+    e = t15 ^ t16\r
+\r
+/* 16 terms */\r
+\r
+#define sb2(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~a;        \\r
+    t2 = b ^ d;     \\r
+    t3 = c & t1;    \\r
+    t13 = d | t1;   \\r
+    e = t2 ^ t3;    \\r
+    t5 = c ^ t1;    \\r
+    t6 = c ^ e;     \\r
+    t7 = b & t6;    \\r
+    t10 = e | t5;   \\r
+    h = t5 ^ t7;    \\r
+    t9 = d | t7;    \\r
+    t11 = t9 & t10; \\r
+    t14 = t2 ^ h;   \\r
+    g = a ^ t11;    \\r
+    t15 = g ^ t13;  \\r
+    f = t14 ^ t15\r
+\r
+/* 16 terms */\r
+\r
+#define ib2(a,b,c,d,e,f,g,h)    \\r
+    t1 = b ^ d;     \\r
+    t2 = ~t1;       \\r
+    t3 = a ^ c;     \\r
+    t4 = c ^ t1;    \\r
+    t7 = a | t2;    \\r
+    t5 = b & t4;    \\r
+    t8 = d ^ t7;    \\r
+    t11 = ~t4;      \\r
+    e = t3 ^ t5;    \\r
+    t9 = t3 | t8;   \\r
+    t14 = d & t11;  \\r
+    h = t1 ^ t9;    \\r
+    t12 = e | h;    \\r
+    f = t11 ^ t12;  \\r
+    t15 = t3 ^ t12; \\r
+    g = t14 ^ t15\r
+\r
+/* 17 terms */\r
+\r
+#define sb3(a,b,c,d,e,f,g,h)    \\r
+    t1 = a ^ c;     \\r
+    t2 = d ^ t1;    \\r
+    t3 = a & t2;    \\r
+    t4 = d ^ t3;    \\r
+    t5 = b & t4;    \\r
+    g = t2 ^ t5;    \\r
+    t7 = a | g;     \\r
+    t8 = b | d;     \\r
+    t11 = a | d;    \\r
+    t9 = t4 & t7;   \\r
+    f = t8 ^ t9;    \\r
+    t12 = b ^ t11;  \\r
+    t13 = g ^ t9;   \\r
+    t15 = t3 ^ t8;  \\r
+    h = t12 ^ t13;  \\r
+    t16 = c & t15;  \\r
+    e = t12 ^ t16\r
+\r
+/* 16 term solution that performs less well than 17 term one\r
+   in my environment (PPro/PII)                                  \r
+\r
+#define sb3(a,b,c,d,e,f,g,h)    \\r
+    t1 = a ^ b;     \\r
+    t2 = a & c;     \\r
+    t3 = a | d;     \\r
+    t4 = c ^ d;     \\r
+    t5 = t1 & t3;   \\r
+    t6 = t2 | t5;   \\r
+    g = t4 ^ t6;    \\r
+    t8 = b ^ t3;    \\r
+    t9 = t6 ^ t8;   \\r
+    t10 = t4 & t9;  \\r
+    e = t1 ^ t10;   \\r
+    t12 = g & e;    \\r
+    f = t9 ^ t12;   \\r
+    t14 = b | d;    \\r
+    t15 = t4 ^ t12; \\r
+    h = t14 ^ t15\r
+*/\r
+\r
+/* 17 terms */\r
+\r
+#define ib3(a,b,c,d,e,f,g,h)    \\r
+    t1 = b ^ c;     \\r
+    t2 = b | c;     \\r
+    t3 = a ^ c;     \\r
+    t7 = a ^ d;     \\r
+    t4 = t2 ^ t3;   \\r
+    t5 = d | t4;    \\r
+    t9 = t2 ^ t7;   \\r
+    e = t1 ^ t5;    \\r
+    t8 = t1 | t5;   \\r
+    t11 = a & t4;   \\r
+    g = t8 ^ t9;    \\r
+    t12 = e | t9;   \\r
+    f = t11 ^ t12;  \\r
+    t14 = a & g;    \\r
+    t15 = t2 ^ t14; \\r
+    t16 = e & t15;  \\r
+    h = t4 ^ t16\r
+\r
+/* 15 terms */\r
+\r
+#define sb4(a,b,c,d,e,f,g,h)    \\r
+    t1 = a ^ d;     \\r
+    t2 = d & t1;    \\r
+    t3 = c ^ t2;    \\r
+    t4 = b | t3;    \\r
+    h = t1 ^ t4;    \\r
+    t6 = ~b;        \\r
+    t7 = t1 | t6;   \\r
+    e = t3 ^ t7;    \\r
+    t9 = a & e;     \\r
+    t10 = t1 ^ t6;  \\r
+    t11 = t4 & t10; \\r
+    g = t9 ^ t11;   \\r
+    t13 = a ^ t3;   \\r
+    t14 = t10 & g;  \\r
+    f = t13 ^ t14\r
+\r
+/* 17 terms */\r
+\r
+#define ib4(a,b,c,d,e,f,g,h)    \\r
+    t1 = c ^ d;     \\r
+    t2 = c | d;     \\r
+    t3 = b ^ t2;    \\r
+    t4 = a & t3;    \\r
+    f = t1 ^ t4;    \\r
+    t6 = a ^ d;     \\r
+    t7 = b | d;     \\r
+    t8 = t6 & t7;   \\r
+    h = t3 ^ t8;    \\r
+    t10 = ~a;       \\r
+    t11 = c ^ h;    \\r
+    t12 = t10 | t11;\\r
+    e = t3 ^ t12;   \\r
+    t14 = c | t4;   \\r
+    t15 = t7 ^ t14; \\r
+    t16 = h | t10;  \\r
+    g = t15 ^ t16\r
+\r
+/* 16 terms */\r
+\r
+#define sb5(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~a;        \\r
+    t2 = a ^ b;     \\r
+    t3 = a ^ d;     \\r
+    t4 = c ^ t1;    \\r
+    t5 = t2 | t3;   \\r
+    e = t4 ^ t5;    \\r
+    t7 = d & e;     \\r
+    t8 = t2 ^ e;    \\r
+    t10 = t1 | e;   \\r
+    f = t7 ^ t8;    \\r
+    t11 = t2 | t7;  \\r
+    t12 = t3 ^ t10; \\r
+    t14 = b ^ t7;   \\r
+    g = t11 ^ t12;  \\r
+    t15 = f & t12;  \\r
+    h = t14 ^ t15\r
+\r
+/* 16 terms */\r
+\r
+#define ib5(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~c;        \\r
+    t2 = b & t1;    \\r
+    t3 = d ^ t2;    \\r
+    t4 = a & t3;    \\r
+    t5 = b ^ t1;    \\r
+    h = t4 ^ t5;    \\r
+    t7 = b | h;     \\r
+    t8 = a & t7;    \\r
+    f = t3 ^ t8;    \\r
+    t10 = a | d;    \\r
+    t11 = t1 ^ t7;  \\r
+    e = t10 ^ t11;  \\r
+    t13 = a ^ c;    \\r
+    t14 = b & t10;  \\r
+    t15 = t4 | t13; \\r
+    g = t14 ^ t15\r
+\r
+/* 15 terms */\r
+\r
+#define sb6(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~a;        \\r
+    t2 = a ^ d;     \\r
+    t3 = b ^ t2;    \\r
+    t4 = t1 | t2;   \\r
+    t5 = c ^ t4;    \\r
+    f = b ^ t5;     \\r
+    t13 = ~t5;      \\r
+    t7 = t2 | f;    \\r
+    t8 = d ^ t7;    \\r
+    t9 = t5 & t8;   \\r
+    g = t3 ^ t9;    \\r
+    t11 = t5 ^ t8;  \\r
+    e = g ^ t11;    \\r
+    t14 = t3 & t11; \\r
+    h = t13 ^ t14\r
+\r
+/* 15 terms */\r
+\r
+#define ib6(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~a;        \\r
+    t2 = a ^ b;     \\r
+    t3 = c ^ t2;    \\r
+    t4 = c | t1;    \\r
+    t5 = d ^ t4;    \\r
+    t13 = d & t1;   \\r
+    f = t3 ^ t5;    \\r
+    t7 = t3 & t5;   \\r
+    t8 = t2 ^ t7;   \\r
+    t9 = b | t8;    \\r
+    h = t5 ^ t9;    \\r
+    t11 = b | h;    \\r
+    e = t8 ^ t11;   \\r
+    t14 = t3 ^ t11; \\r
+    g = t13 ^ t14\r
+\r
+/* 17 terms */\r
+\r
+#define sb7(a,b,c,d,e,f,g,h)    \\r
+    t1 = ~c;        \\r
+    t2 = b ^ c;     \\r
+    t3 = b | t1;    \\r
+    t4 = d ^ t3;    \\r
+    t5 = a & t4;    \\r
+    t7 = a ^ d;     \\r
+    h = t2 ^ t5;    \\r
+    t8 = b ^ t5;    \\r
+    t9 = t2 | t8;   \\r
+    t11 = d & t3;   \\r
+    f = t7 ^ t9;    \\r
+    t12 = t5 ^ f;   \\r
+    t15 = t1 | t4;  \\r
+    t13 = h & t12;  \\r
+    g = t11 ^ t13;  \\r
+    t16 = t12 ^ g;  \\r
+    e = t15 ^ t16\r
+\r
+/* 17 terms */\r
+\r
+#define ib7(a,b,c,d,e,f,g,h)    \\r
+    t1 = a & b;     \\r
+    t2 = a | b;     \\r
+    t3 = c | t1;    \\r
+    t4 = d & t2;    \\r
+    h = t3 ^ t4;    \\r
+    t6 = ~d;        \\r
+    t7 = b ^ t4;    \\r
+    t8 = h ^ t6;    \\r
+    t11 = c ^ t7;   \\r
+    t9 = t7 | t8;   \\r
+    f = a ^ t9;     \\r
+    t12 = d | f;    \\r
+    e = t11 ^ t12;  \\r
+    t14 = a & h;    \\r
+    t15 = t3 ^ f;   \\r
+    t16 = e ^ t14;  \\r
+    g = t15 ^ t16\r
+\r
+#define k_xor(r,a,b,c,d)    \\r
+    a ^= l_key[4 * r +  8]; \\r
+    b ^= l_key[4 * r +  9]; \\r
+    c ^= l_key[4 * r + 10]; \\r
+    d ^= l_key[4 * r + 11]\r
+\r
+#define k_set(r,a,b,c,d)    \\r
+    a = l_key[4 * r +  8];  \\r
+    b = l_key[4 * r +  9];  \\r
+    c = l_key[4 * r + 10];  \\r
+    d = l_key[4 * r + 11]\r
+\r
+#define k_get(r,a,b,c,d)    \\r
+    l_key[4 * r +  8] = a;  \\r
+    l_key[4 * r +  9] = b;  \\r
+    l_key[4 * r + 10] = c;  \\r
+    l_key[4 * r + 11] = d\r
+\r
+/* the linear transformation and its inverse    */\r
+\r
+#define rot(a,b,c,d)    \\r
+    a = rotl(a, 13);    \\r
+    c = rotl(c, 3);     \\r
+    d ^= c ^ (a << 3);  \\r
+    b ^= a ^ c;         \\r
+    d = rotl(d, 7);     \\r
+    b = rotl(b, 1);     \\r
+    a ^= b ^ d;         \\r
+    c ^= d ^ (b << 7);  \\r
+    a = rotl(a, 5);     \\r
+    c = rotl(c, 22)\r
+\r
+#define irot(a,b,c,d)   \\r
+    c = rotr(c, 22);    \\r
+    a = rotr(a, 5);     \\r
+    c ^= d ^ (b << 7);  \\r
+    a ^= b ^ d;         \\r
+    d = rotr(d, 7);     \\r
+    b = rotr(b, 1);     \\r
+    d ^= c ^ (a << 3);  \\r
+    b ^= a ^ c;         \\r
+    c = rotr(c, 3);     \\r
+    a = rotr(a, 13)\r
+\r
+/* initialise the key schedule from the user supplied key   */\r
+\r
+u4byte *serpent_set_key(SerpentContext *ctx,\r
+                       const u4byte in_key[], const u4byte key_len)\r
+{   \r
+    u4byte  i,lk,a,b,c,d,e,f,g,h;\r
+    u4byte  t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+    if(key_len < 0 || key_len > 256)\r
+\r
+        return (u4byte*)0;\r
+\r
+    i = 0; lk = (key_len + 31) / 32;\r
+    \r
+    while(i < lk)\r
+    {\r
+#ifdef  BLOCK_SWAP\r
+        l_key[i] = io_swap(in_key[lk - i - 1]);\r
+#else\r
+        l_key[i] = in_key[i];\r
+#endif  \r
+        i++;\r
+    }\r
+\r
+    if(key_len < 256)\r
+    {\r
+        while(i < 8)\r
+\r
+            l_key[i++] = 0;\r
+\r
+        i = key_len / 32; lk = 1 << key_len % 32; \r
+\r
+        l_key[i] = l_key[i] & (lk - 1) | lk;\r
+    }\r
+\r
+    for(i = 0; i < 132; ++i)\r
+    {\r
+        lk = l_key[i] ^ l_key[i + 3] ^ l_key[i + 5] \r
+                                ^ l_key[i + 7] ^ 0x9e3779b9 ^ i;\r
+\r
+        l_key[i + 8] = (lk << 11) | (lk >> 21); \r
+    }\r
+\r
+    k_set( 0,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( 0,e,f,g,h);\r
+    k_set( 1,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( 1,e,f,g,h);\r
+    k_set( 2,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get( 2,e,f,g,h);\r
+    k_set( 3,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get( 3,e,f,g,h);\r
+    k_set( 4,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get( 4,e,f,g,h);\r
+    k_set( 5,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get( 5,e,f,g,h);\r
+    k_set( 6,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get( 6,e,f,g,h);\r
+    k_set( 7,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get( 7,e,f,g,h);\r
+    k_set( 8,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( 8,e,f,g,h);\r
+    k_set( 9,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( 9,e,f,g,h);\r
+    k_set(10,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(10,e,f,g,h);\r
+    k_set(11,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(11,e,f,g,h);\r
+    k_set(12,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(12,e,f,g,h);\r
+    k_set(13,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(13,e,f,g,h);\r
+    k_set(14,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(14,e,f,g,h);\r
+    k_set(15,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(15,e,f,g,h);\r
+    k_set(16,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(16,e,f,g,h);\r
+    k_set(17,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get(17,e,f,g,h);\r
+    k_set(18,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(18,e,f,g,h);\r
+    k_set(19,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(19,e,f,g,h);\r
+    k_set(20,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(20,e,f,g,h);\r
+    k_set(21,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(21,e,f,g,h);\r
+    k_set(22,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(22,e,f,g,h);\r
+    k_set(23,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(23,e,f,g,h);\r
+    k_set(24,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(24,e,f,g,h);\r
+    k_set(25,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get(25,e,f,g,h);\r
+    k_set(26,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(26,e,f,g,h);\r
+    k_set(27,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(27,e,f,g,h);\r
+    k_set(28,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(28,e,f,g,h);\r
+    k_set(29,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(29,e,f,g,h);\r
+    k_set(30,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(30,e,f,g,h);\r
+    k_set(31,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(31,e,f,g,h);\r
+    k_set(32,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(32,e,f,g,h);\r
+\r
+    return l_key;\r
+};\r
+\r
+/* encrypt a block of text  */\r
+\r
+void serpent_encrypt(SerpentContext *ctx,\r
+                    const u4byte in_blk[4], u4byte out_blk[])\r
+{   \r
+    u4byte  a,b,c,d,e,f,g,h;\r
+    u4byte  t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
+    u4byte *l_key = ctx->l_key;\r
+\r
+#ifdef  BLOCK_SWAP\r
+    a = io_swap(in_blk[3]); b = io_swap(in_blk[2]); \r
+    c = io_swap(in_blk[1]); d = io_swap(in_blk[0]);\r
+#else\r
+    a = in_blk[0]; b = in_blk[1]; c = in_blk[2]; d = in_blk[3];\r
+#endif\r
+\r
+    k_xor( 0,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor( 1,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor( 2,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor( 3,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor( 4,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor( 5,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor( 6,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor( 7,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor( 8,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor( 9,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(10,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(11,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(12,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(13,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(14,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(15,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(16,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(17,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(18,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(19,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(20,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(21,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(22,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(23,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(24,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(25,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(26,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(27,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(28,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(29,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
+    k_xor(30,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
+    k_xor(31,e,f,g,h); sb7(e,f,g,h,a,b,c,d); k_xor(32,a,b,c,d); \r
+    \r
+#ifdef  BLOCK_SWAP\r
+    out_blk[3] = io_swap(a); out_blk[2] = io_swap(b); \r
+    out_blk[1] = io_swap(c); out_blk[0] = io_swap(d);\r
+#else\r
+    out_blk[0] = a; out_blk[1] = b; out_blk[2] = c; out_blk[3] = d;\r
+#endif\r
+};\r
+\r
+/* decrypt a block of text  */\r
+\r
+void serpent_decrypt(SerpentContext *ctx,\r
+                    const u4byte in_blk[4], u4byte out_blk[4])\r
+{   \r
+    u4byte  a,b,c,d,e,f,g,h;\r
+    u4byte  t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
+    u4byte *l_key = ctx->l_key;\r
+    \r
+#ifdef  BLOCK_SWAP\r
+    a = io_swap(in_blk[3]); b = io_swap(in_blk[2]); \r
+    c = io_swap(in_blk[1]); d = io_swap(in_blk[0]);\r
+#else\r
+    a = in_blk[0]; b = in_blk[1]; c = in_blk[2]; d = in_blk[3];\r
+#endif\r
+\r
+    k_xor(32,a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(31,e,f,g,h);\r
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(30,a,b,c,d);\r
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(29,e,f,g,h);\r
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(28,a,b,c,d);\r
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(27,e,f,g,h);\r
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(26,a,b,c,d);\r
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(25,e,f,g,h);\r
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(24,a,b,c,d);\r
+    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(23,e,f,g,h);\r
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(22,a,b,c,d);\r
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(21,e,f,g,h);\r
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(20,a,b,c,d);\r
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(19,e,f,g,h);\r
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(18,a,b,c,d);\r
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(17,e,f,g,h);\r
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(16,a,b,c,d);\r
+    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(15,e,f,g,h);\r
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(14,a,b,c,d);\r
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(13,e,f,g,h);\r
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(12,a,b,c,d);\r
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(11,e,f,g,h);\r
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(10,a,b,c,d);\r
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 9,e,f,g,h);\r
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 8,a,b,c,d);\r
+    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor( 7,e,f,g,h);\r
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor( 6,a,b,c,d);\r
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor( 5,e,f,g,h);\r
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor( 4,a,b,c,d);\r
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor( 3,e,f,g,h);\r
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor( 2,a,b,c,d);\r
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 1,e,f,g,h);\r
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 0,a,b,c,d);\r
+    \r
+#ifdef  BLOCK_SWAP\r
+    out_blk[3] = io_swap(a); out_blk[2] = io_swap(b); \r
+    out_blk[1] = io_swap(c); out_blk[0] = io_swap(d);\r
+#else\r
+    out_blk[0] = a; out_blk[1] = b; out_blk[2] = c; out_blk[3] = d;\r
+#endif\r
+};\r
diff --git a/lib/silccrypt/serpent.h b/lib/silccrypt/serpent.h
new file mode 100644 (file)
index 0000000..cadff85
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+
+  serpent.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef SERPENT_H
+#define SERPENT_H
+
+#include "serpent_internal.h"
+
+/* 
+ * SILC Crypto API for Serpent
+ */
+
+/* Sets the key for the cipher. */
+
+inline int silc_serpent_init(void *context, 
+                            const unsigned char *key, 
+                            size_t keylen)
+{
+  serpent_set_key((SerpentContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+inline int silc_serpent_set_string_as_key(void *context, 
+                                         const unsigned char *string,
+                                         size_t keylen)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+inline size_t silc_serpent_context_len()
+{
+  return sizeof(SerpentContext);
+}
+
+/* Encrypts with the cipher in CBC mode. */
+
+inline int silc_serpent_encrypt_cbc(void *context,
+                                   const unsigned char *src,
+                                   unsigned char *dst,
+                                   size_t len,
+                                   unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  serpent_encrypt((SerpentContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    serpent_encrypt((SerpentContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+/* Decrypts with the cipher in CBC mode. */
+
+inline int silc_serpent_decrypt_cbc(void *context,
+                                   const unsigned char *src,
+                                   unsigned char *dst,
+                                   size_t len,
+                                   unsigned char *iv)
+{
+  unsigned int *in, *out, *tiv;
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  serpent_decrypt((SerpentContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    serpent_decrypt((SerpentContext *)context, in, out);
+    out[0] ^= in[0 - 4];
+    out[1] ^= in[1 - 4];
+    out[2] ^= in[2 - 4];
+    out[3] ^= in[3 - 4];
+    in += 4;
+    out += 4;
+  }
+
+  return 1;
+}
+
+#endif
diff --git a/lib/silccrypt/serpent_internal.h b/lib/silccrypt/serpent_internal.h
new file mode 100644 (file)
index 0000000..c777ed0
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+
+  serpent_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SERPENT_INTERNAL_H
+#define SERPENT_INTERNAL_H
+
+/* Cipher's context */
+typedef struct {
+  u4byte l_key[140];
+} SerpentContext;
+
+/* Prototypes */
+u4byte *serpent_set_key(SerpentContext *ctx,
+                       const u4byte in_key[], const u4byte key_len);
+void serpent_encrypt(SerpentContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[]);
+void serpent_decrypt(SerpentContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silccrypt/sha1.c b/lib/silccrypt/sha1.c
new file mode 100644 (file)
index 0000000..e60a6d0
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+
+#include "silcincludes.h"
+#include "sha1.h"
+
+/* 
+ * SILC Hash API for SHA1
+ */
+
+SILC_HASH_API_INIT(sha1)
+{
+  SHA1Init((SHA1_CTX *)context);
+}
+
+SILC_HASH_API_UPDATE(sha1)
+{
+  SHA1Update((SHA1_CTX *)context, data, len);
+}
+
+SILC_HASH_API_FINAL(sha1)
+{
+  SHA1Final(digest, (SHA1_CTX *)context);
+}
+
+SILC_HASH_API_TRANSFORM(sha1)
+{
+  SHA1Transform(state, buffer);
+}
+
+SILC_HASH_API_CONTEXT_LEN(sha1)
+{
+  return sizeof(SHA1_CTX);
+}
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
+{
+unsigned long a, b, c, d, e;
+typedef union {
+    unsigned char c[64];
+    unsigned long l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+    block = (CHAR64LONG16*)workspace;
+    memcpy(block, buffer, 64);
+#else
+    block = (CHAR64LONG16*)buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
+{
+unsigned int i, j;
+
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+unsigned long i, j;
+unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++) {
+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
+    for (i = 0; i < 20; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    i = j = 0;
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, 20);
+    memset(context->count, 0, 8);
+    memset(finalcount, 0, 8);
+#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
+    SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+/*************************************************************/
+
+/* Test Code */
+
+#if 0
+
+int main(int argc, char** argv)
+{
+int i, j;
+SHA1_CTX context;
+unsigned char digest[20], buffer[16384];
+FILE* file;
+
+    if (argc > 2) {
+        puts("Public domain SHA-1 implementation - by Steve Reid <steve@edmweb.com>");
+        puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
+        exit(0);
+    }
+    if (argc < 2) {
+        file = stdin;
+    }
+    else {
+        if (!(file = fopen(argv[1], "rb"))) {
+            fputs("Unable to open file.", stderr);
+            exit(-1);
+        }
+    } 
+    SHA1Init(&context);
+    while (!feof(file)) {  /* note: what if ferror(file) */
+        i = fread(buffer, 1, 16384, file);
+        SHA1Update(&context, buffer, i);
+    }
+    SHA1Final(digest, &context);
+    fclose(file);
+    for (i = 0; i < 5; i++) {
+        for (j = 0; j < 4; j++) {
+            printf("%02X", digest[i*4+j]);
+        }
+        putchar(' ');
+    }
+    putchar('\n');
+    exit(0);
+}
+
+#endif
diff --git a/lib/silccrypt/sha1.h b/lib/silccrypt/sha1.h
new file mode 100644 (file)
index 0000000..6ac0d5b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+  sha1.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#include "sha1_internal.h"
+
+/* 
+ * SILC Hash API for SHA1
+ */
+
+SILC_HASH_API_INIT(sha1);
+SILC_HASH_API_UPDATE(sha1);
+SILC_HASH_API_FINAL(sha1);
+SILC_HASH_API_TRANSFORM(sha1);
+SILC_HASH_API_CONTEXT_LEN(sha1);
+
+#endif
diff --git a/lib/silccrypt/sha1_internal.h b/lib/silccrypt/sha1_internal.h
new file mode 100644 (file)
index 0000000..15ae9bd
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+*/
+/* Header portion split from main code for convenience (AYB 3/02/98) */
+
+#ifndef SHA1_INTERNAL_H
+#define SHA1_INTERNAL_H
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* Context declaration */
+typedef struct {
+    unsigned long state[5];
+    unsigned long count[2];
+    unsigned char buffer[64];
+} SHA1_CTX;
+
+/* Function forward declerations */
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#endif
diff --git a/lib/silccrypt/silccipher.c b/lib/silccrypt/silccipher.c
new file mode 100644 (file)
index 0000000..72bbc43
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+
+  silccipher.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#include "ciphers.h"           /* Includes cipher definitions */
+
+/* List of all ciphers in SILC. You can dynamically add new ciphers
+   into the list. At the initialization of SILC this list is filled with
+   the configured ciphers. */
+struct SilcCipherListStruct {
+  SilcCipherObject *cipher;
+  struct SilcCipherListStruct *next;
+};
+
+/* Dynamically registered list of ciphers. */
+struct SilcCipherListStruct *silc_cipher_list = NULL;
+
+/* XXX: add the other good ciphers here as well */
+
+/* Staticly declared list of ciphers. This is used if system doesn't
+   support SIM's. */
+SilcCipherObject silc_cipher_builtin_list[] =
+{
+  { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
+    silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
+    silc_none_context_len },
+  { "twofish", 16, 16, silc_twofish_set_key, silc_twofish_set_key_with_string,
+    silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
+    silc_twofish_context_len },
+  { "rc6", 16, 16, silc_rc6_set_key, silc_rc6_set_key_with_string,
+    silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
+    silc_rc6_context_len },
+  { "mars", 16, 16, silc_mars_set_key, silc_mars_set_key_with_string,
+    silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
+    silc_mars_context_len },
+
+  { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* Register a new cipher into SILC. This is used at the initialization of
+   the SILC. This function allocates a new object for the cipher to be
+   registered. Therefore, if memory has been allocated for the object sent
+   as argument it has to be free'd after this function returns succesfully. */
+
+int silc_cipher_register(SilcCipherObject *cipher)
+{
+  struct SilcCipherListStruct *new, *c;
+
+  SILC_LOG_DEBUG(("Registering new cipher"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new cipher list object: %s",
+                   strerror(errno)));
+    return FALSE;
+  }
+
+  new->cipher = silc_calloc(1, sizeof(*new->cipher));
+  if (!new->cipher) {
+    SILC_LOG_ERROR(("Could not allocate new cipher object: %s",
+                   strerror(errno)));
+    return FALSE;
+  }
+
+  /* Set the pointers */
+  new->cipher->name = strdup(cipher->name);
+  new->cipher->block_len = cipher->block_len;
+  new->cipher->key_len = cipher->key_len;
+  new->cipher->set_key = cipher->set_key;
+  new->cipher->set_key_with_string = cipher->set_key_with_string;
+  new->cipher->encrypt = cipher->encrypt;
+  new->cipher->decrypt = cipher->decrypt;
+  new->cipher->context_len = cipher->context_len;
+  new->next = NULL;
+
+  /* Add the new cipher to the list */
+  if (!silc_cipher_list) {
+    silc_cipher_list = new;
+    return TRUE;
+  }
+
+  c = silc_cipher_list;
+  while (c) {
+    if (!c->next) {
+      c->next = new;
+      break;
+    }
+    c = c->next;
+  }
+
+  return TRUE;
+}
+
+/* Unregister a cipher from the SILC. */
+
+int silc_cipher_unregister(SilcCipherObject *cipher)
+{
+  struct SilcCipherListStruct *c, *tmp;
+
+  SILC_LOG_DEBUG(("Unregistering cipher"));
+
+  c = silc_cipher_list;
+  
+  if (cipher == SILC_ALL_CIPHERS) {
+    /* Unregister all ciphers */
+    while (c) {
+      tmp = c->next;
+      silc_free(c->cipher->name);
+      silc_free(c);
+      c = tmp;
+    }
+
+    return TRUE;
+  }
+
+  /* Unregister the cipher */
+  if (c->cipher == cipher) {
+    tmp = c->next;
+    silc_free(c->cipher->name);
+    silc_free(c);
+    silc_cipher_list = tmp;
+    
+    return TRUE;
+  }
+
+  while (c) {
+    if (c->next->cipher == cipher) {
+
+      tmp = c->next->next;
+      silc_free(c->cipher->name);
+      silc_free(c);
+      c->next = tmp;
+
+      return TRUE;
+    }
+
+    c = c->next;
+  }
+
+  return FALSE;
+}
+
+/* Allocates a new SILC cipher object. Function returns 1 on succes and 0 
+   on error. The allocated cipher is returned in new_cipher argument. The
+   caller must set the key to the cipher after this function has returned
+   by calling the ciphers set_key function. */
+
+int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
+{
+  struct SilcCipherListStruct *c;
+  int i;
+
+  SILC_LOG_DEBUG(("Allocating new cipher object"));
+
+  /* Allocate the new object */
+  *new_cipher = silc_calloc(1, sizeof(**new_cipher));
+  if (*new_cipher == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new cipher object"));
+    return FALSE;
+  }
+  
+  if (silc_cipher_list) {
+
+    c = silc_cipher_list;
+    while (c) {
+      if (!strcmp(c->cipher->name, name))
+       break;
+      c = c->next;
+    }
+
+    if (!c)
+      goto check_builtin;
+
+    /* Set the pointers */
+    (*new_cipher)->cipher = c->cipher;
+    (*new_cipher)->context = silc_calloc(1, c->cipher->context_len());
+    (*new_cipher)->set_iv = silc_cipher_set_iv;
+    (*new_cipher)->get_iv = silc_cipher_get_iv;
+    (*new_cipher)->get_key_len = silc_cipher_get_key_len;
+    (*new_cipher)->get_block_len = silc_cipher_get_block_len;
+    
+    return TRUE;
+  }
+
+ check_builtin:
+
+  for (i = 0; silc_cipher_builtin_list[i].name; i++)
+    if (!strcmp(silc_cipher_builtin_list[i].name, name))
+      break;
+
+  if (silc_cipher_builtin_list[i].name == NULL) {
+    silc_free(*new_cipher);
+    return FALSE;
+  }
+
+  /* Set the pointers */
+  (*new_cipher)->cipher = &silc_cipher_builtin_list[i];
+  (*new_cipher)->context = 
+    silc_calloc(1, (*new_cipher)->cipher->context_len());
+  (*new_cipher)->set_iv = silc_cipher_set_iv;
+  (*new_cipher)->get_iv = silc_cipher_get_iv;
+  (*new_cipher)->get_key_len = silc_cipher_get_key_len;
+  (*new_cipher)->get_block_len = silc_cipher_get_block_len;
+  memset(&(*new_cipher)->iv, 0, sizeof((*new_cipher)->iv));
+
+  return TRUE;
+}
+
+/* Free's the given cipher. */
+
+void silc_cipher_free(SilcCipher cipher)
+{
+  if (cipher) {
+    silc_free(cipher->context);
+    silc_free(cipher);
+  }
+}
+
+/* Returns TRUE if cipher `name' is supported. */
+
+int silc_cipher_is_supported(const unsigned char *name)
+{
+  struct SilcCipherListStruct *c;
+  int i;
+
+  if (silc_cipher_list) {
+    c = silc_cipher_list;
+
+    while (c) {
+      if (!strcmp(c->cipher->name, name))
+       return TRUE;
+      c = c->next;
+    }
+  }
+
+  for (i = 0; silc_cipher_builtin_list[i].name; i++)
+    if (!strcmp(silc_cipher_builtin_list[i].name, name))
+      return TRUE;
+
+  return FALSE;
+}
+
+/* Returns comma separated list of supported ciphers. */
+
+char *silc_cipher_get_supported()
+{
+  char *list = NULL;
+  int i, len;
+  struct SilcCipherListStruct *c;
+
+  len = 0;
+  if (silc_cipher_list) {
+    c = silc_cipher_list;
+
+    while (c) {
+      len += strlen(c->cipher->name);
+      list = silc_realloc(list, len + 1);
+      
+      memcpy(list + (len - strlen(c->cipher->name)), 
+            c->cipher->name, strlen(c->cipher->name));
+      memcpy(list + len, ",", 1);
+      len++;
+      
+      c = c->next;
+    }
+  }
+
+  for (i = 0; silc_cipher_builtin_list[i].name; i++) {
+    len += strlen(silc_cipher_builtin_list[i].name);
+    list = silc_realloc(list, len + 1);
+    
+    memcpy(list + (len - strlen(silc_cipher_builtin_list[i].name)), 
+          silc_cipher_builtin_list[i].name, 
+          strlen(silc_cipher_builtin_list[i].name));
+    memcpy(list + len, ",", 1);
+    len++;
+  }
+
+  list[len - 1] = 0;
+
+  return list;
+}
+
+/* Sets the IV (initial vector) for the cipher. */
+
+void silc_cipher_set_iv(SilcCipher itself, const unsigned char *iv)
+{
+  memset(&itself->iv, 0, sizeof(itself->iv));
+  memcpy(&itself->iv, iv, itself->cipher->block_len);
+}
+
+/* Returns the IV (initial vector) of the cipher. The IV is returned 
+   to 'iv' argument. */
+
+void silc_cipher_get_iv(SilcCipher itself, unsigned char *iv)
+{
+  memcpy(iv, &itself->iv, itself->cipher->block_len);
+}
+
+/* Returns the key length of the cipher. */
+/* XXX */
+
+unsigned int silc_cipher_get_key_len(SilcCipher itself, 
+                                    const unsigned char *name)
+{
+
+  return TRUE;
+}
+
+/* Returns the block size of the cipher. */
+/* XXX */
+
+unsigned int silc_cipher_get_block_len(SilcCipher itself)
+{
+
+  return TRUE;
+}
diff --git a/lib/silccrypt/silccipher.h b/lib/silccrypt/silccipher.h
new file mode 100644 (file)
index 0000000..1080149
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+
+  silccipher.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCCIPHER_H
+#define SILCCIPHER_H
+
+/* 
+   SILC Cipher object.
+
+   Default SILC cipher object to represent any cipher. The function
+   pointers are the stub functions for each implemented cipher. Following
+   short description of the fields:
+
+   char *name
+
+       Logical name of the cipher.
+
+   unsigned int block_len
+
+       Block size of the cipher.
+
+   unsigned int key_len
+
+       Length of the key of the cipher (in bits).
+
+*/
+typedef struct {
+  char *name;
+  unsigned int block_len;
+  unsigned key_len;
+
+  int (*set_key)(void *, const unsigned char *, unsigned int);
+  int (*set_key_with_string)(void *, const unsigned char *, unsigned int);
+  int (*encrypt)(void *, const unsigned char *, unsigned char *,
+                unsigned int, unsigned char *);
+  int (*decrypt)(void *, const unsigned char *, unsigned char *, 
+                unsigned int, unsigned char *);
+  unsigned int (*context_len)();
+} SilcCipherObject;
+
+#define SILC_CIPHER_MAX_IV_SIZE 16
+
+/* The main SilcCipher structure. Use SilcCipher instead of SilcCipherStruct.
+   Also remember that SilcCipher is a pointer. */
+typedef struct SilcCipherStruct {
+  SilcCipherObject *cipher;
+  void *context;
+  unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+
+  void (*set_iv)(struct SilcCipherStruct *, const unsigned char *);
+  void (*get_iv)(struct SilcCipherStruct *, unsigned char *);
+  unsigned int (*get_key_len)(struct SilcCipherStruct *, 
+                             const unsigned char *);
+  unsigned int (*get_block_len)(struct SilcCipherStruct *);
+} *SilcCipher;
+
+/* List of all registered ciphers. */
+extern struct SilcCipherListStruct *silc_cipher_list;
+
+/* Marks for all ciphers in silc. This can be used in silc_cipher_unregister
+   to unregister all ciphers at once. */
+#define SILC_ALL_CIPHERS ((SilcCipherObject *)1)
+
+/* Macros */
+
+/* Function names in SILC Crypto modules. The name of the cipher
+   is appended into these names and used to the get correct symbol out
+   of the module. All SILC Crypto API compliant modules must support
+   these function names (use macros below to assure this). */
+#define SILC_CIPHER_SIM_SET_KEY "set_key"
+#define SILC_CIPHER_SIM_SET_KEY_WITH_STRING "set_key_with_string"
+#define SILC_CIPHER_SIM_ENCRYPT_CBC "encrypt_cbc"
+#define SILC_CIPHER_SIM_DECRYPT_CBC "decrypt_cbc"
+#define SILC_CIPHER_SIM_CONTEXT_LEN "context_len"
+
+/* These macros can be used to implement the SILC Crypto API and to avoid
+   errors in the API these macros should be used always. */
+#define SILC_CIPHER_API_SET_KEY(cipher)                        \
+int silc_##cipher##_set_key(void *context,             \
+                           const unsigned char *key,   \
+                           unsigned int keylen)
+#define SILC_CIPHER_API_SET_KEY_WITH_STRING(cipher)                    \
+int silc_##cipher##_set_key_with_string(void *context,                 \
+                                       const unsigned char *string,    \
+                                       unsigned int stringlen)
+#define SILC_CIPHER_API_ENCRYPT_CBC(cipher)                    \
+int silc_##cipher##_encrypt_cbc(void *context,                 \
+                               const unsigned char *src,       \
+                               unsigned char *dst,             \
+                               unsigned int len,               \
+                               unsigned char *iv)
+#define SILC_CIPHER_API_DECRYPT_CBC(cipher)                    \
+int silc_##cipher##_decrypt_cbc(void *context,                 \
+                               const unsigned char *src,       \
+                               unsigned char *dst,             \
+                               unsigned int len,               \
+                               unsigned char *iv)
+#define SILC_CIPHER_API_CONTEXT_LEN(cipher)                    \
+unsigned int silc_##cipher##_context_len()
+
+/* Prototypes */
+int silc_cipher_register(SilcCipherObject *cipher);
+int silc_cipher_unregister(SilcCipherObject *cipher);
+int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher);
+void silc_cipher_free(SilcCipher cipher);
+int silc_cipher_is_supported(const unsigned char *name);
+char *silc_cipher_get_supported();
+void silc_cipher_set_iv(SilcCipher itself, const unsigned char *iv);
+void silc_cipher_get_iv(SilcCipher itself, unsigned char *iv);
+unsigned int silc_cipher_get_key_len(SilcCipher itself, 
+                                    const unsigned char *name);
+unsigned int silc_cipher_get_block_len(SilcCipher itself);
+
+#endif
diff --git a/lib/silccrypt/silchash.c b/lib/silccrypt/silchash.c
new file mode 100644 (file)
index 0000000..8068085
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+
+  silchash.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#include "md5.h"
+#include "sha1.h"
+
+/* List of all hash functions in SILC. You can dynamically add new hash
+   functions into the list. At the initialization of SILC this list is 
+   filled with the configured hash functions. */
+struct SilcHashListStruct {
+  SilcHashObject *hash;
+  struct SilcHashListStruct *next;
+};
+
+/* List of dynamically registered hash functions. */
+struct SilcHashListStruct *silc_hash_list = NULL;
+
+/* Statically declared list of hash functions. */
+SilcHashObject silc_hash_builtin_list[] = 
+{
+  { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
+    silc_md5_transform, silc_md5_context_len },
+  { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
+    silc_sha1_transform, silc_sha1_context_len },
+
+  { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* Registers a ned hash function into the SILC. This function is used at
+   the initialization of the SILC. */
+
+int silc_hash_register(SilcHashObject *hash)
+{
+  struct SilcHashListStruct *new, *h;
+
+  SILC_LOG_DEBUG(("Registering new hash function"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new hash list object"));
+    return FALSE;
+  }
+
+  new->hash = silc_calloc(1, sizeof(*new->hash));
+  if (!new->hash) {
+    SILC_LOG_ERROR(("Could not allocate new hash object"));
+    return FALSE;
+  }
+
+  /* Set the pointers */
+  new->hash->name = silc_calloc(1, strlen(hash->name));
+  memcpy(new->hash->name, hash->name, strlen(hash->name));
+  new->hash->hash_len = hash->hash_len;
+  new->hash->block_len = hash->block_len;
+  new->hash->init = hash->init;
+  new->hash->update = hash->update;
+  new->hash->final = hash->final;
+  new->hash->context_len = hash->context_len;
+  new->next = NULL;
+
+  /* Add the new hash function to the list */
+  if (!silc_hash_list) {
+    silc_hash_list = new;
+    return TRUE;
+  }
+
+  h = silc_hash_list;
+  while (h) {
+    if (!h->next) {
+      h->next = new;
+      break;
+    }
+    h = h->next;
+  }
+
+  return TRUE;
+}
+
+/* Unregister a hash function from the SILC. */
+
+int silc_hash_unregister(SilcHashObject *hash)
+{
+  struct SilcHashListStruct *h, *tmp;
+
+  SILC_LOG_DEBUG(("Unregistering hash function"));
+
+  h = silc_hash_list;
+
+  /* Unregister all hash functions */
+  if (hash == SILC_ALL_HASH_FUNCTIONS) {
+    /* Unregister all ciphers */
+    while (h) {
+      tmp = h->next;
+      silc_free(h->hash->name);
+      silc_free(h);
+      h = tmp;
+    }
+
+    return TRUE;
+  }
+
+  /* Unregister the hash function */
+  if (h->hash == hash) {
+    tmp = h->next;
+    silc_free(h->hash->name);
+    silc_free(h);
+    silc_hash_list = tmp;
+
+    return TRUE;
+  }
+
+  while (h) {
+    if (h->next->hash == hash) {
+      tmp = h->next->next;
+      silc_free(h->hash->name);
+      silc_free(h);
+      h->next = tmp;
+      return TRUE;
+    }
+
+    h = h->next;
+  }
+
+  return FALSE;
+}
+
+/* Allocates a new SilcHash object. New object is returned into new_hash
+   argument. */
+
+int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
+{
+  struct SilcHashListStruct *h;
+  int i;
+  
+  SILC_LOG_DEBUG(("Allocating new hash object"));
+
+  /* Allocate the new object */
+  *new_hash = silc_calloc(1, sizeof(**new_hash));
+  if (*new_hash == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new hash object"));
+    return FALSE;
+  }
+
+  if (silc_hash_list) {
+    h = silc_hash_list;
+    while (h) {
+      if (!strcmp(h->hash->name, name))
+       break;
+      h = h->next;
+    }
+
+    if (!h)
+      goto check_builtin;
+
+    /* Set the pointers */
+    (*new_hash)->hash = h->hash;
+    (*new_hash)->context = silc_calloc(1, h->hash->context_len());
+    (*new_hash)->make_hash = silc_hash_make;
+
+    return TRUE;
+  }
+
+ check_builtin:
+  for (i = 0; silc_hash_builtin_list[i].name; i++)
+    if (!strcmp(silc_hash_builtin_list[i].name, name))
+      break;
+
+  if (silc_hash_builtin_list[i].name == NULL) {
+    silc_free(*new_hash);
+    return FALSE;
+  }
+  
+  /* Set the pointers */
+  (*new_hash)->hash = &silc_hash_builtin_list[i];
+  (*new_hash)->context = silc_calloc(1, (*new_hash)->hash->context_len());
+  (*new_hash)->make_hash = silc_hash_make;
+  
+  return TRUE;
+}
+
+/* Free's the SilcHash object */
+
+void silc_hash_free(SilcHash hash)
+{
+  if (hash) {
+    silc_free(hash->context);
+    silc_free(hash);
+  }
+}
+
+/* Returns TRUE if hash algorithm `name' is supported. */
+
+int silc_hash_is_supported(const unsigned char *name)
+{
+  struct SilcHashListStruct *h;
+  int i;
+  
+  if (silc_hash_list) {
+    h = silc_hash_list;
+
+    while (h) {
+      if (!strcmp(h->hash->name, name))
+       return TRUE;
+      h = h->next;
+    }
+  }
+
+  for (i = 0; silc_hash_builtin_list[i].name; i++)
+    if (!strcmp(silc_hash_builtin_list[i].name, name))
+      return TRUE;
+
+  return FALSE;
+}
+
+/* Returns comma separated list of supported hash functions. */
+
+char *silc_hash_get_supported()
+{
+  char *list = NULL;
+  int i, len;
+  struct SilcHashListStruct *h;
+
+  len = 0;
+  if (silc_hash_list) {
+    h = silc_hash_list;
+
+    while (h) {
+      len += strlen(h->hash->name);
+      list = silc_realloc(list, len + 1);
+      
+      memcpy(list + (len - strlen(h->hash->name)), 
+            h->hash->name, strlen(h->hash->name));
+      memcpy(list + len, ",", 1);
+      len++;
+      
+      h = h->next;
+    }
+  }
+
+  for (i = 0; silc_hash_builtin_list[i].name; i++) {
+    len += strlen(silc_hash_builtin_list[i].name);
+    list = silc_realloc(list, len + 1);
+    
+    memcpy(list + (len - strlen(silc_hash_builtin_list[i].name)), 
+          silc_hash_builtin_list[i].name, 
+          strlen(silc_hash_builtin_list[i].name));
+    memcpy(list + len, ",", 1);
+    len++;
+  }
+
+  list[len - 1] = 0;
+
+  return list;
+}
+
+/* Creates the hash value and returns it to the return_hash argument. */
+
+void silc_hash_make(SilcHash hash, const unsigned char *data, 
+                   unsigned int len, unsigned char *return_hash)
+{
+  hash->hash->init(hash->context);
+  hash->hash->update(hash->context, (unsigned char *)data, len);
+  hash->hash->final(hash->context, return_hash);
+}
diff --git a/lib/silccrypt/silchash.h b/lib/silccrypt/silchash.h
new file mode 100644 (file)
index 0000000..98f85ef
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+
+  silchash.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCHASH_H
+#define SILCHASH_H
+
+/* The default Silc hash object to represent any hash function in SILC. */
+typedef struct {
+  char *name;
+  unsigned int hash_len;
+  unsigned int block_len;
+
+  void (*init)(void *);
+  void (*update)(void *, unsigned char *, unsigned int);
+  void (*final)(void *, unsigned char *);
+  void (*transform)(unsigned long *, unsigned char *);
+  unsigned int (*context_len)();
+} SilcHashObject;
+
+/* The main SILC hash structure. Use SilcHash instead of SilcHashStruct.
+   Also remember that SilcHash is a pointer. */
+typedef struct SilcHashStruct {
+  SilcHashObject *hash;
+  void *context;
+
+  void (*make_hash)(struct SilcHashStruct *, const unsigned char *, 
+                   unsigned int, unsigned char *);
+} *SilcHash;
+
+extern struct SilcHashListStruct *silc_hash_list;
+
+/* Marks for all hash functions. This can be used in silc_hash_unregister
+   to unregister all hash function at once. */
+#define SILC_ALL_HASH_FUNCTIONS ((SilcHashObject *)1)
+
+/* Macros */
+
+/* Following macros are used to implement the SILC Hash API. These
+   macros should be used instead of declaring functions by hand. */
+
+/* Function names in SILC Hash modules. The name of the hash function
+   is appended into these names and used to the get correct symbol out
+   of the module. All SILC Hash API compliant modules has to support
+   these names as function names (use macros below to assure this). */
+#define SILC_HASH_SIM_INIT "init"
+#define SILC_HASH_SIM_UPDATE "update"
+#define SILC_HASH_SIM_FINAL "final"
+#define SILC_HASH_SIM_TRANSFORM "transform"
+#define SILC_HASH_SIM_CONTEXT_LEN "context_len"
+
+/* Macros that can be used to declare SILC Hash API functions. */
+#define SILC_HASH_API_INIT(hash)               \
+void silc_##hash##_init(void *context)
+#define SILC_HASH_API_UPDATE(hash)                             \
+void silc_##hash##_update(void *context, unsigned char *data,  \
+                                       unsigned int len)
+#define SILC_HASH_API_FINAL(hash)                              \
+void silc_##hash##_final(void *context, unsigned char *digest)
+#define SILC_HASH_API_TRANSFORM(hash)                                  \
+void silc_##hash##_transform(unsigned long *state,                     \
+                                         unsigned char *buffer)
+#define SILC_HASH_API_CONTEXT_LEN(hash)                \
+unsigned int silc_##hash##_context_len()
+
+/* Prototypes */
+int silc_hash_register(SilcHashObject *hash);
+int silc_hash_unregister(SilcHashObject *hash);
+int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
+void silc_hash_free(SilcHash hash);
+int silc_hash_is_supported(const unsigned char *name);
+char *silc_hash_get_supported();
+void silc_hash_make(SilcHash hash, const unsigned char *data,
+                   unsigned int len, unsigned char *return_hash);
+
+#endif
diff --git a/lib/silccrypt/silchmac.c b/lib/silccrypt/silchmac.c
new file mode 100644 (file)
index 0000000..ddf7453
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+
+  silchmac.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* Allocates a new SilcHmac object. First argument is the hash function
+   object to tell the hmac which hash function should be used when creating
+   HMAC's. The new SilcHmac object is returned to new_hmac argument. */
+
+int silc_hmac_alloc(SilcHash hash, SilcHmac *new_hmac)
+{
+  SILC_LOG_DEBUG(("Allocating new hmac object"));
+
+  *new_hmac = silc_calloc(1, sizeof(**new_hmac));
+  if (*new_hmac == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new hmac object"));
+    return 0;
+  }
+
+  (*new_hmac)->hash = hash;
+  (*new_hmac)->set_key = silc_hmac_set_key;
+  (*new_hmac)->make_hmac = silc_hmac_make;
+  (*new_hmac)->make_hmac_with_key = silc_hmac_make_with_key;
+  (*new_hmac)->make_hmac_truncated = silc_hmac_make_truncated;
+
+  return 1;
+}
+
+/* Free's the SilcHmac object. */
+
+void silc_hmac_free(SilcHmac hmac)
+{
+  if (hmac)
+    silc_free(hmac);
+}
+
+/* Creates the HMAC. The created keyed hash value is returned to 
+   return_hash argument. */
+
+void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data,
+                            unsigned int data_len, unsigned char *key,
+                            unsigned int key_len, unsigned char *return_hash)
+{
+  SilcHash hash = hmac->hash;
+  unsigned char inner_pad[hash->hash->block_len + 1];
+  unsigned char outer_pad[hash->hash->block_len + 1];
+  unsigned char hvalue[hash->hash->hash_len];
+  void *hash_context;
+  int i;
+
+  SILC_LOG_DEBUG(("Making HMAC for message"));
+
+  hash_context = silc_calloc(1, hash->hash->context_len());
+
+  memset(inner_pad, 0, sizeof(inner_pad));
+  memset(outer_pad, 0, sizeof(outer_pad));
+
+  /* If the key length is more than block size of the hash function, the
+     key is hashed. */
+  if (key_len > hash->hash->block_len) {
+    hash->make_hash(hash, key, key_len, hvalue);
+    key = hvalue;
+    key_len = hash->hash->hash_len;
+  }
+
+  /* Copy the key into the pads */
+  memcpy(inner_pad, key, key_len);
+  memcpy(outer_pad, key, key_len);
+
+  /* XOR the key with pads */
+  for (i = 0; i < hash->hash->block_len; i++) {
+    inner_pad[i] ^= 0x36;
+    outer_pad[i] ^= 0x5c;
+  }
+
+  /* Do the HMAC transform (too bad I can't do make_hash directly, sigh) */
+  hash->hash->init(hash_context);
+  hash->hash->update(hash_context, inner_pad, hash->hash->block_len);
+  hash->hash->update(hash_context, data, data_len);
+  hash->hash->final(hash_context, return_hash);
+  hash->hash->init(hash_context);
+  hash->hash->update(hash_context, outer_pad, hash->hash->block_len);
+  hash->hash->update(hash_context, return_hash, hash->hash->hash_len);
+  hash->hash->final(hash_context, return_hash);
+}
+
+/* Create the HMAC. This is thee make_hmac function pointer.  This
+   uses the internal key set with silc_hmac_set_key. */
+
+void silc_hmac_make(SilcHmac hmac, unsigned char *data,
+                   unsigned int data_len, unsigned char *return_hash)
+{
+  silc_hmac_make_internal(hmac, data, data_len, hmac->key, 
+                         hmac->key_len, return_hash);
+}
+
+/* Creates the HMAC just as above except that the hash value is truncated
+   to the truncated_len sent as argument. NOTE: One should not truncate to
+   less than half of the length of original hash value. However, this 
+   routine allows these dangerous truncations. */
+
+void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
+                             unsigned int data_len,
+                             unsigned int truncated_len,
+                             unsigned char *return_hash)
+{
+  unsigned char hvalue[hmac->hash->hash->hash_len];
+
+  silc_hmac_make_internal(hmac, data, data_len, 
+                         hmac->key, hmac->key_len, hvalue);
+  memcpy(return_hash, hvalue, truncated_len);
+  memset(hvalue, 0, sizeof(hvalue));
+}
+
+/* Creates HMAC just as above except that this doesn't use the internal
+   key. The key is sent as argument to the function. */
+
+void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
+                            unsigned int data_len, 
+                            unsigned char *key, unsigned int key_len,
+                            unsigned char *return_hash)
+{
+  silc_hmac_make_internal(hmac, data, data_len, key, key_len, return_hash);
+}
+
+/* Sets the HMAC key used in the HMAC creation */
+
+void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
+                      unsigned int key_len)
+{
+  hmac->key = silc_calloc(key_len, sizeof(unsigned char));
+  memcpy(hmac->key, key, key_len);
+}
diff --git a/lib/silccrypt/silchmac.h b/lib/silccrypt/silchmac.h
new file mode 100644 (file)
index 0000000..d69822d
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+
+  silchmac.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCHMAC_H
+#define SILCHMAC_H
+
+/* 
+   SILC HMAC object. 
+   
+   This is the HMAC object to create keyed hash values for message
+   authentication. These routines uses already implemented hash functions.
+   HMAC's can be created using any hash function implemented in SILC. These
+   routines were created according to RFC2104. Following short description 
+   of the fields:
+
+   SilcHash hash
+
+       The hash object to tell what hash function to use with this HMAC.
+
+   unsigned char *key
+   unsigned int len
+
+       The key and its length used to make the HMAC. This is set
+       with silc_hmac_set_key function.
+
+   void (*set_key)(SilcHmac, const unsigned char *, unsigned int)
+
+       Function used to set the key for the HMAC. Second argument is
+       the key to be set and last argument is the length of the key.
+
+   void (*make_hmac)(SilcHmac, unsigned char *, unsigned int,
+                     unsigned char *)
+
+       Function what is used to create HMAC's. User can also use directly
+       silc_hmac_make fuction. Although, one needs to allocate a SilcHmac
+       object before doing it, naturally. This uses the key set with
+       silc_hmac_set_key function.
+
+   void (*make_hmac_with_key)(SilcHmac, unsigned char *, unsigned int,
+                              unsigned char *, unsigned int, unsigned char *)
+
+       Same function as above except that the key used in the HMAC
+       creation is sent as argument. The key set with silc_hmac_set_key
+       is ignored in this case.
+
+   void (*make_hmac_truncated)(SilcHmac, unsigned char *, unsigned int,
+                              unsigned int, unsigned char *)
+
+       Same function as above except that the output hash value is truncated
+       to the length sent as argument (second last argument). This makes
+       variable truncations possible, however, one should not truncate
+       hash values to less than half of the length of the hash value.
+
+*/
+typedef struct SilcHmacStruct *SilcHmac;
+
+struct SilcHmacStruct {
+  SilcHash hash;
+  unsigned char *key;
+  unsigned int key_len;
+  void (*set_key)(SilcHmac, const unsigned char *, unsigned int);
+  void (*make_hmac)(SilcHmac, unsigned char *, unsigned int,
+                   unsigned char *);
+  void (*make_hmac_with_key)(SilcHmac, unsigned char *, unsigned int,
+                            unsigned char *, unsigned int, unsigned char *);
+  void (*make_hmac_truncated)(SilcHmac, unsigned char *, 
+                             unsigned int, unsigned int, unsigned char *);
+};
+
+/* Prototypes */
+int silc_hmac_alloc(SilcHash hash, SilcHmac *new_hmac);
+void silc_hmac_free(SilcHmac hmac);
+void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
+                      unsigned int key_len);
+void silc_hmac_make(SilcHmac hmac, 
+                   unsigned char *data, 
+                   unsigned int data_len,
+                   unsigned char *return_hash);
+void silc_hmac_make_with_key(SilcHmac hmac, 
+                            unsigned char *data, 
+                            unsigned int data_len,
+                            unsigned char *key, 
+                            unsigned int key_len, 
+                            unsigned char *return_hash);
+void silc_hmac_make_truncated(SilcHmac hmac, 
+                             unsigned char *data, 
+                             unsigned int data_len,
+                             unsigned int truncated_len,
+                             unsigned char *return_hash);
+
+#endif
diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c
new file mode 100644 (file)
index 0000000..6b99d59
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+
+  silcpkcs.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+#include "rsa.h"
+
+/* List of all PKCS's in SILC. PKCS's don't support SIM's thus
+   only static declarations are possible. XXX: I hope this to change
+   real soon. */
+SilcPKCSObject silc_pkcs_list[] =
+{
+  { "rsa", &silc_rsa_data_context, 
+    silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
+    silc_rsa_get_private_key, silc_rsa_set_public_key,
+    silc_rsa_set_private_key, silc_rsa_context_len,
+    silc_rsa_data_context_len, silc_rsa_set_arg,
+    silc_rsa_encrypt, silc_rsa_decrypt,
+    silc_rsa_sign, silc_rsa_verify },
+
+  { NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* Allocates a new SilcPKCS object. The new allocated object is returned
+   to the 'new_pkcs' argument. This function also initializes the data
+   context structure. Function returns 1 on success and 0 on error.
+
+*/
+int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
+{
+  int i;
+
+  SILC_LOG_DEBUG(("Allocating new PKCS object"));
+
+  for (i = 0; silc_pkcs_list[i].name; i++) {
+    if (!strcmp(silc_pkcs_list[i].name, name))
+      break;
+  }
+
+  if (silc_pkcs_list[i].name == NULL)
+    return FALSE;
+
+  *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
+  if (*new_pkcs == NULL) {
+    SILC_LOG_ERROR(("Could not allocate new PKCS object"));
+    return FALSE;
+  }
+
+  /* Set the pointers */
+  (*new_pkcs)->pkcs = &silc_pkcs_list[i];
+  (*new_pkcs)->pkcs->data_context = 
+    silc_calloc(1, (*new_pkcs)->pkcs->data_context_len());
+  (*new_pkcs)->context = silc_calloc(1, (*new_pkcs)->pkcs->context_len());
+  (*new_pkcs)->get_key_len = silc_pkcs_get_key_len;
+
+  return TRUE;
+}
+
+/* Free's the PKCS object */
+
+void silc_pkcs_free(SilcPKCS pkcs)
+{
+  if (pkcs)
+    silc_free(pkcs->context);
+}
+
+/* Return TRUE if PKCS algorithm `name' is supported. */
+
+int silc_pkcs_is_supported(const unsigned char *name)
+{
+  int i;
+
+  for (i = 0; silc_pkcs_list[i].name; i++) {
+    if (!strcmp(silc_pkcs_list[i].name, name))
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* Returns comma separated list of supported PKCS algorithms */
+
+char *silc_pkcs_get_supported()
+{
+  char *list = NULL;
+  int i, len;
+
+  len = 0;
+  for (i = 0; silc_pkcs_list[i].name; i++) {
+    len += strlen(silc_pkcs_list[i].name);
+    list = silc_realloc(list, len + 1);
+
+    memcpy(list + (len - strlen(silc_pkcs_list[i].name)), 
+          silc_pkcs_list[i].name, strlen(silc_pkcs_list[i].name));
+    memcpy(list + len, ",", 1);
+    len++;
+  }
+
+  list[len - 1] = 0;
+
+  return list;
+}
+
+/* Returns the length of the key */
+
+unsigned int silc_pkcs_get_key_len(SilcPKCS self)
+{
+  return self->key_len;
+}
+
+/* Returns SILC style public key */
+
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len)
+{
+  return pkcs->pkcs->get_public_key(pkcs->context, len);
+}
+
+/* Returns SILC style private key */
+
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
+{
+  return pkcs->pkcs->get_private_key(pkcs->context, len);
+}
+
+/* Sets public key */
+/* XXX rewrite */
+
+int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk, 
+                            unsigned int pk_len)
+{
+  return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
+}
+
+/* Sets private key */
+
+int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv, 
+                             unsigned int prv_len)
+{
+  return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
+}
+
+/* Saves public key into file */
+
+int silc_pkcs_save_public_key(SilcPKCS pkcs, char *filename,
+                             unsigned char *pk, unsigned int pk_len)
+{
+  SilcBuffer buf;
+  int ret = TRUE;
+
+  buf = silc_buffer_alloc(strlen(pkcs->pkcs->name) + 2 + pk_len
+                         + strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) 
+                         + strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+  silc_buffer_format(buf,
+                    SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
+                    SILC_STR_UI32_STRING(pkcs->pkcs->name),
+                    SILC_STR_UI_SHORT(pk_len),
+                    SILC_STR_UI_XNSTRING(pk, pk_len),
+                    SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
+                    SILC_STR_END);
+
+  /* Save into a file */
+  if (silc_file_write(filename, buf->data, buf->len)) {
+    ret = FALSE;
+    goto out;
+  }
+
+ out:
+  silc_buffer_free(buf);
+  return ret;
+}
+
+/* XXX The buffer should be encrypted */
+/* XXX rewrite */
+
+int silc_pkcs_save_private_key(SilcPKCS pkcs, char *filename,
+                              unsigned char *prv, unsigned int prv_len,
+                              char *passphrase)
+{
+  SilcBuffer buf;
+  int ret = TRUE;
+
+  buf = silc_buffer_alloc(strlen(pkcs->pkcs->name) + 2 + prv_len
+                         + strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) 
+                         + strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+  silc_buffer_format(buf,
+                    SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
+                    SILC_STR_UI32_STRING(pkcs->pkcs->name),
+                    SILC_STR_UI_SHORT(prv_len),
+                    SILC_STR_UI_XNSTRING(prv, prv_len),
+                    SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
+                    SILC_STR_END);
+
+  /* Save into a file */
+  if (silc_file_write(filename, buf->data, buf->len)) {
+    ret = FALSE;
+    goto out;
+  }
+
+ out:
+  silc_buffer_free(buf);
+  return ret;
+}
+
+/* Loads public key from file and allocates new PKCS object and
+   sets the loaded key into it. */
+
+int silc_pkcs_load_public_key(char *filename, SilcPKCS *ret_pkcs)
+{
+
+  return TRUE;
+}
+
+/* Loads private key from file and allocates new PKCS object and
+   sets the loaded key into it. */
+
+int silc_pkcs_load_private_key(char *filename, SilcPKCS *ret_pkcs)
+{
+
+  return TRUE;
+}
diff --git a/lib/silccrypt/silcpkcs.h b/lib/silccrypt/silcpkcs.h
new file mode 100644 (file)
index 0000000..9d7fd82
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+
+  silcpkcs.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPKCS_H
+#define SILCPKCS_H
+
+/* The default SILC PKCS (Public Key Cryptosystem) object to represent
+   any PKCS in SILC. */
+typedef struct SilcPKCSObjectStruct {
+  unsigned char *name;
+  void *data_context;
+
+  int (*init)(void *, unsigned int, SilcRng);
+  void (*clear_keys)(void *);
+  unsigned char *(*get_public_key)(void *, unsigned int *);
+  unsigned char *(*get_private_key)(void *, unsigned int *);
+  int (*set_public_key)(void *, unsigned char *, unsigned int);
+  int (*set_private_key)(void *, unsigned char *, unsigned int);
+  unsigned int (*context_len)();
+  unsigned int (*data_context_len)();
+  int (*set_arg)(void *, void *, int, SilcInt);
+  int (*encrypt)(void *, unsigned char *, unsigned int,
+                unsigned char *, unsigned int *);
+  int (*decrypt)(void *, unsigned char *, unsigned int,
+                unsigned char *, unsigned int *);
+  int (*sign)(void *, unsigned char *, unsigned int,
+             unsigned char *, unsigned int *);
+  int (*verify)(void *, unsigned char *, unsigned int,
+               unsigned char *, unsigned int);
+} SilcPKCSObject;
+
+/* The main SILC PKCS structure. Use SilcPKCS instead of SilcPKCSStruct.
+   Also remember that SilcPKCS is a pointer. */
+typedef struct SilcPKCSStruct {
+  void *context;
+  SilcPKCSObject *pkcs;
+  unsigned int key_len;
+
+  unsigned int (*get_key_len)(struct SilcPKCSStruct *);
+} *SilcPKCS;
+
+/* List of all PKCS in SILC. */
+extern SilcPKCSObject silc_pkcs_list[];
+
+/* Public and private key file headers */
+#define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
+#define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
+
+/* Macros */
+
+/* Macros used to implement the SILC PKCS API */
+
+/* XXX: This needs slight redesigning. These needs to be made even
+   more generic. I don't like that the actual prime generation is done
+   in PKCS_API_INIT. The primes used in key generation should be sent
+   as argument to the init function. By doing this we would achieve
+   that PKCS could be used as SIM's. The only requirement would be
+   that they are compiled against GMP (well, actually even that would
+   not be a requirement, but the most generic case anyway). The new init 
+   would look something like this:
+
+   #define SILC_PKCS_API_INIT(pkcs) \
+   inline int silc_##pkcs##_init(void *context, unsigned int keylen, \
+                                 void *p1, void *p2)
+
+   Now we wouldn't have to send the SilcRng object since the primes are 
+   provided as arguments. To send them as void * they could actually be 
+   used as in anyway for real (MP_INT (SilcInt) or even something else 
+   (the pointer could be kludged to be something else in the module))
+   (Plus, the SilcRng object management in prime generation would be
+   simpler and better what it is now (in silcprimegen.c, that is)).
+*/
+
+#define SILC_PKCS_API_INIT(pkcs) \
+int silc_##pkcs##_init(void *context, unsigned int keylen, \
+                      SilcRng rng)
+#define SILC_PKCS_API_CLEAR_KEYS(pkcs) \
+void silc_##pkcs##_clear_keys(void *context)
+#define SILC_PKCS_API_GET_PUBLIC_KEY(pkcs) \
+unsigned char *silc_##pkcs##_get_public_key(void *context, \
+                                            unsigned int *ret_len)
+#define SILC_PKCS_API_GET_PRIVATE_KEY(pkcs) \
+unsigned char *silc_##pkcs##_get_private_key(void *context, \
+                                             unsigned int *ret_len)
+#define SILC_PKCS_API_SET_PUBLIC_KEY(pkcs) \
+int silc_##pkcs##_set_public_key(void *context, unsigned char *key_data, \
+                                 unsigned int key_len)
+#define SILC_PKCS_API_SET_PRIVATE_KEY(pkcs) \
+int silc_##pkcs##_set_private_key(void *context, unsigned char *key_data, \
+                                  unsigned int key_len)
+#define SILC_PKCS_API_CONTEXT_LEN(pkcs) \
+unsigned int silc_##pkcs##_context_len()
+#define SILC_PKCS_API_DATA_CONTEXT_LEN(pkcs) \
+unsigned int silc_##pkcs##_data_context_len()
+#define SILC_PKCS_API_SET_ARG(pkcs) \
+int silc_##pkcs##_set_arg(void *context, \
+                         void *data_context, \
+                         int argnum, \
+                         SilcInt val)
+#define SILC_PKCS_API_ENCRYPT(pkcs) \
+int silc_##pkcs##_encrypt(void *context, \
+                         unsigned char *src, \
+                         unsigned int src_len, \
+                         unsigned char *dst, \
+                         unsigned int *dst_len)
+#define SILC_PKCS_API_DECRYPT(pkcs) \
+int silc_##pkcs##_decrypt(void *context, \
+                         unsigned char *src, \
+                         unsigned int src_len, \
+                         unsigned char *dst, \
+                         unsigned int *dst_len)
+#define SILC_PKCS_API_SIGN(pkcs) \
+int silc_##pkcs##_sign(void *context, \
+                      unsigned char *src, \
+                      unsigned int src_len, \
+                      unsigned char *dst, \
+                      unsigned int *dst_len)
+#define SILC_PKCS_API_VERIFY(pkcs) \
+int silc_##pkcs##_verify(void *context, \
+                        unsigned char *signature, \
+                        unsigned int signature_len, \
+                        unsigned char *data, \
+                        unsigned int data_len)
+
+/* Prototypes */
+int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs);
+void silc_pkcs_free(SilcPKCS pkcs);
+int silc_pkcs_is_supported(const unsigned char *name);
+char *silc_pkcs_get_supported();
+unsigned int silc_pkcs_get_key_len(SilcPKCS self);
+unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len);
+unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len);
+int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk, 
+                            unsigned int pk_len);
+int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv, 
+                             unsigned int prv_len);
+int silc_pkcs_save_public_key(SilcPKCS pkcs, char *filename,
+                             unsigned char *pk, unsigned int pk_len);
+int silc_pkcs_save_private_key(SilcPKCS pkcs, char *filename,
+                              unsigned char *prv, unsigned int prv_len,
+                              char *passphrase);
+int silc_pkcs_load_public_key(char *filename, SilcPKCS *ret_pkcs);
+int silc_pkcs_load_private_key(char *filename, SilcPKCS *ret_pkcs);
+
+#endif
diff --git a/lib/silccrypt/silcrng.c b/lib/silccrypt/silcrng.c
new file mode 100644 (file)
index 0000000..d5f2533
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+
+  silcrng.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Created: Sun Mar  9 00:09:18 1997
+ *
+ * This RNG is based on Secure Shell's random number generator.
+ */
+/* XXX: Some operations block resulting slow initialization.
+ * XXX: I have some pending changes to make this better. */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+#undef SILC_RNG_DEBUG
+/* #define SILC_RNG_DEBUG */
+
+/* 
+   SILC SilcRng State context.
+
+   This object is used by the random number generator to provide
+   variable points where the actual random number is fetched from
+   the random pool. This provides that the data is not fetched always
+   from the same point of the pool. Short description of the fields
+   following.
+
+   unsigned int low
+   unsigned int pos
+
+       The index for the random pool buffer. Lowest and current
+       positions.
+
+   SilcRngStateContext *next
+
+       Pointer to the next state. If this is the last state this
+       will point to the first state thus providing circular list.
+
+*/
+typedef struct SilcRngStateContext {
+  unsigned int low;
+  unsigned int pos;
+  struct SilcRngStateContext *next;
+} *SilcRngState;
+
+/* 
+   SILC Random Number Generator object. 
+
+   This object holds random pool which is used to generate the random
+   numbers used by various routines needing cryptographically strong
+   random numbers. Following short descriptions of the fields.
+
+   unsigned char pool[]
+
+       The random pool. This buffer holds the random data. This is
+       frequently stirred thus providing ever changing randomnes.
+
+   unsigned char key[64]
+
+       Key used in stirring the random pool. The pool is encrypted
+       with SHA1 hash function in CFB (Cipher Feedback) mode.
+
+   SilcSilcRngState state
+
+       State object that is used to get the next position for the
+       random pool. This position is used to fetch data from pool
+       or to save the data to the pool. The state changes everytime
+       SilcRng is used.
+
+   SilcHash sha1
+
+       Hash object (SHA1) used to make the CFB encryption to the
+       random pool. This is allocated when RNG object is allocated and
+       free'd when RNG object is free'd.
+
+*/
+typedef struct SilcRngObjectStruct {
+  unsigned char pool[SILC_RNG_POOLSIZE];
+  unsigned char key[64];
+  SilcRngState state;
+  SilcHash sha1;
+} SilcRngObject;
+
+/* Allocates new RNG object. */
+
+SilcRng silc_rng_alloc()
+{
+  SilcRng new;
+
+  SILC_LOG_DEBUG(("Allocating new RNG object"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new RNG object"));
+    return NULL;
+  }
+
+  memset(new->pool, 0, sizeof(new->pool));
+  memset(new->key, 0, sizeof(new->key));
+  new->state = NULL;
+  silc_hash_alloc("sha1", &new->sha1);
+
+  return new;
+}
+
+/* Free's RNG object. */
+
+void silc_rng_free(SilcRng rng)
+{
+  if (rng) {
+    memset(rng->pool, 0, sizeof(rng->pool));
+    memset(rng->key, 0, sizeof(rng->key));
+    silc_free(rng->sha1);
+    silc_free(rng);
+  }
+}
+
+/* Initializes random number generator by getting noise from environment. 
+   The environmental noise is our so called seed. One should not call
+   this function more than once. */
+
+void silc_rng_init(SilcRng rng)
+{
+  int i;
+  SilcRngState first, next;
+
+  assert(rng != NULL);
+
+  SILC_LOG_DEBUG(("Initializing RNG object"));
+
+  /* Initialize the states for the RNG. */
+  rng->state = silc_malloc(sizeof(*rng->state));
+  rng->state->low = 0;
+  rng->state->pos = 8;
+  rng->state->next = NULL;
+  first = rng->state;
+  for (i = SILC_RNG_STATE_NUM - 1; i >= 1; i--) {
+    next = silc_malloc(sizeof(*rng->state));
+    next->low = 
+      (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM));
+    next->pos =
+      (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM)) + 8;
+#if 0
+    next->pos = sizeof(rng->pool) - 
+      ((i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM))) + 8;
+#endif
+    next->next = rng->state;
+    rng->state = next;
+  }
+  first->next = next;
+  rng->state = first;
+
+  memset(rng->pool, 0, sizeof(rng->pool));
+
+  /* Get noise from various environmental sources */
+  silc_rng_get_soft_noise(rng);
+  silc_rng_get_medium_noise(rng);
+  silc_rng_get_hard_noise(rng);
+}
+
+/* This function gets 'soft' noise from environment. */
+
+void silc_rng_get_soft_noise(SilcRng rng)
+{
+  struct tms ptime;
+  
+  silc_rng_xor(rng, clock(), 0);
+  silc_rng_xor(rng, getpid(), 1);
+  silc_rng_xor(rng, getpgid(getpid() << 8), 2);
+  silc_rng_xor(rng, getpgid(getpid() << 8), 3);
+  silc_rng_xor(rng, getgid(), 4);
+  silc_rng_xor(rng, getpgrp(), 5);
+  silc_rng_xor(rng, getsid(getpid() << 16), 6);
+  silc_rng_xor(rng, times(&ptime), 7);
+  silc_rng_xor(rng, ptime.tms_utime, 8);
+  silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 9);
+  silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), 10);
+  silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 11);
+  silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), 12);
+  silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), 13);
+  silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), 14);
+  silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), 15);
+  silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), 16);
+  silc_rng_xor(rng, (ptime.tms_stime << 8), 17);
+  silc_rng_xor(rng, clock() << 4, 18);
+  silc_rng_xor(rng, getpgid(getpid() << 8), 19);
+  silc_rng_xor(rng, getpgrp(), 20);
+  silc_rng_xor(rng, getsid(getpid() << 16), 21);
+  silc_rng_xor(rng, times(&ptime), 22);
+  silc_rng_xor(rng, ptime.tms_utime, 23);
+  silc_rng_xor(rng, getpgrp(), 24);
+
+  /* Stir random pool */
+  silc_rng_stir_pool(rng);
+}
+
+/* This function gets noise from different commands */
+
+void silc_rng_get_medium_noise(SilcRng rng)
+{
+  silc_rng_exec_command(rng, "ps -lefaww 2> /dev/null");
+  silc_rng_exec_command(rng, "ls -afiln 2> /dev/null");
+  silc_rng_exec_command(rng, "ps -asww 2> /dev/null");
+  silc_rng_exec_command(rng, "ls -afiln /proc 2> /dev/null");
+  /*
+  silc_rng_exec_command(rng, "ps -ef 2> /dev/null");
+  silc_rng_exec_command(rng, "ls -alin /dev 2> /dev/null");
+  */
+}
+
+/* This function gets 'hard' noise from environment. This tries to
+   get the noise from /dev/random if available. */
+
+void silc_rng_get_hard_noise(SilcRng rng)
+{
+  char buf[32];
+  int fd, len, i;
+  
+  /* Get noise from /dev/random if available */
+  fd = open("/dev/random", O_RDONLY);
+  if (fd < 0)
+    return;
+
+  fcntl(fd, F_SETFL, O_NONBLOCK);
+
+  for (i = 0; i < 8; i++) {
+    len = read(fd, buf, sizeof(buf));
+    if (len <= 0)
+      goto out;
+    silc_rng_add_noise(rng, buf, len);
+  }
+
+ out:
+  close(fd);
+  memset(buf, 0, sizeof(buf));
+}
+
+/* Execs command and gets noise from its output */
+
+void silc_rng_exec_command(SilcRng rng, char *command)
+{
+  char buf[2048];
+  FILE *fd;
+  int i;
+  int c;
+  
+  /* Open process */
+  fd = popen(command, "r");
+  if (!fd)
+    return;
+  
+  /* Get data as much as we can get into the buffer */
+  for (i = 0; i < sizeof(buf); i++) {
+    c = fgetc(fd);
+    if (c == EOF) {
+      if (!i)
+       return;
+      break; 
+    }
+    buf[i] = c;
+  }
+  
+  pclose(fd);
+  
+  /* Add the buffer into random pool */
+  silc_rng_add_noise(rng, buf, strlen(buf));
+  memset(buf, 0, sizeof(buf));
+}
+
+/* This function adds the contents of the buffer as noise into random 
+   pool. After adding the noise the pool is stirred. */
+
+void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, 
+                       unsigned int len)
+{
+  unsigned int i, pos;
+
+  pos = silc_rng_get_position(rng);
+
+  /* Add the buffer one by one into the pool */
+  for(i = 0; i < len; i++, buffer++) {
+    if(pos >= SILC_RNG_POOLSIZE)
+      break;
+    rng->pool[pos++] ^= *buffer;
+  }
+
+  /* Stir random pool */
+  silc_rng_stir_pool(rng);
+}
+
+/* XOR's data into the pool */
+
+void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos)
+{
+  assert(rng != NULL);
+  rng->pool[pos] ^= val + val;
+}
+
+/* This function stirs the random pool by encrypting buffer in CFB 
+   (cipher feedback) mode with SHA1 algorithm. */
+
+void silc_rng_stir_pool(SilcRng rng)
+{
+  int i;
+  unsigned long iv[5];
+
+  /* Get the IV */
+  memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv));
+
+  /* First CFB pass */
+  for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
+    rng->sha1->hash->transform(iv, rng->key);
+    iv[0] = rng->pool[i] ^= iv[0];
+    iv[1] = rng->pool[i + 1] ^= iv[1];
+    iv[2] = rng->pool[i + 2] ^= iv[2];
+    iv[3] = rng->pool[i + 3] ^= iv[3];
+    iv[4] = rng->pool[i + 4] ^= iv[4];
+  }
+
+  /* Get new key */
+  memcpy(rng->key, &rng->pool[silc_rng_get_position(rng)], sizeof(rng->key));
+
+  /* Second CFB pass */
+  for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
+    rng->sha1->hash->transform(iv, rng->key);
+    iv[0] = rng->pool[i] ^= iv[0];
+    iv[1] = rng->pool[i + 1] ^= iv[1];
+    iv[2] = rng->pool[i + 2] ^= iv[2];
+    iv[3] = rng->pool[i + 3] ^= iv[3];
+    iv[4] = rng->pool[i + 4] ^= iv[4];
+  }
+
+  memset(iv, 0, sizeof(iv));
+}
+
+/* Returns next position where data is fetched from the pool or
+   put to the pool. */
+
+unsigned int silc_rng_get_position(SilcRng rng)
+{
+  SilcRngState next;
+  unsigned int pos;
+
+  next = rng->state->next;
+
+  pos = rng->state->pos++;
+  if ((next->low != 0 && pos >= next->low) || (pos >= SILC_RNG_POOLSIZE))
+    rng->state->pos = rng->state->low;
+
+#ifdef SILC_RNG_DEBUG
+    fprintf(stderr, "state: %p: low: %d, pos: %d\n", 
+           rng->state, rng->state->low, rng->state->pos);
+#endif
+
+  rng->state = next;
+
+  return pos;
+}
+
+/* returns random byte. Every two byte is from pools low or high state. */
+
+unsigned char silc_rng_get_byte(SilcRng rng)
+{
+  return rng->pool[silc_rng_get_position(rng)];
+}
+
+/* Returns 16 bit random number */
+
+unsigned short silc_rng_get_rn16(SilcRng rng)
+{
+  unsigned char rn[2];
+  unsigned short num;
+
+  rn[0] = silc_rng_get_byte(rng);
+  rn[1] = silc_rng_get_byte(rng);
+  SILC_GET16_MSB(num, rn);
+
+  return num;
+}
+
+/* Returns 32 bit random number */
+
+unsigned int silc_rng_get_rn32(SilcRng rng)
+{
+  unsigned char rn[4];
+  unsigned short num;
+
+  rn[0] = silc_rng_get_byte(rng);
+  rn[1] = silc_rng_get_byte(rng);
+  rn[2] = silc_rng_get_byte(rng);
+  rn[3] = silc_rng_get_byte(rng);
+  SILC_GET32_MSB(num, rn);
+
+  return num;
+}
+
+/* Returns random number string. Returned string is in HEX format. */
+
+unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len)
+{
+  int i;
+  unsigned char *string;
+
+  string = silc_calloc((len * 2 + 1), sizeof(unsigned char));
+  if (string == NULL)
+    return NULL;
+
+  for (i = 0; i < len; i++)
+    sprintf(string + 2 * i, "%02x", silc_rng_get_byte(rng));
+
+  return string;
+}
diff --git a/lib/silccrypt/silcrng.h b/lib/silccrypt/silcrng.h
new file mode 100644 (file)
index 0000000..c35f864
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+
+  silcSilcRng.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCRNG_H
+#define SILCRNG_H
+
+/* Forward declaration. Actual object is in source file. */
+typedef struct SilcRngObjectStruct *SilcRng;
+
+/* Number of states to fetch data from pool. */
+#define SILC_RNG_STATE_NUM 4
+
+/* Byte size of the random data pool. */
+#define SILC_RNG_POOLSIZE 1024
+
+/* Prototypes */
+SilcRng silc_rng_alloc();
+void silc_rng_free(SilcRng rng);
+void silc_rng_init(SilcRng rng);
+void silc_rng_get_soft_noise(SilcRng rng);
+void silc_rng_get_medium_noise(SilcRng rng);
+void silc_rng_get_hard_noise(SilcRng rng);
+void silc_rng_exec_command(SilcRng rng, char *command);
+void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, 
+                       unsigned int len);
+void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos);
+void silc_rng_stir_pool(SilcRng rng);
+unsigned int silc_rng_get_position(SilcRng rng);
+unsigned char silc_rng_get_byte(SilcRng rng);
+unsigned short silc_rng_get_rn16(SilcRng rng);
+unsigned int silc_rng_get_rn32(SilcRng rng);
+unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len);
+
+#endif
diff --git a/lib/silccrypt/tests/inst b/lib/silccrypt/tests/inst
new file mode 100644 (file)
index 0000000..06485bd
--- /dev/null
@@ -0,0 +1,7 @@
+gcc -I.. \
+-I../../../includes -I../../silccore \
+-I../.. -I../../silccore -I../../silcmath \
+-I../../silcmath/gmp-2.0.2 -I../../silcske -I../../silcsim \
+-Wall -finline-functions \
+-o test_rsa test_rsa.c -L../.. -lsilc
+
diff --git a/lib/silccrypt/tests/inst_rsa b/lib/silccrypt/tests/inst_rsa
new file mode 100644 (file)
index 0000000..06485bd
--- /dev/null
@@ -0,0 +1,7 @@
+gcc -I.. \
+-I../../../includes -I../../silccore \
+-I../.. -I../../silccore -I../../silcmath \
+-I../../silcmath/gmp-2.0.2 -I../../silcske -I../../silcsim \
+-Wall -finline-functions \
+-o test_rsa test_rsa.c -L../.. -lsilc
+
diff --git a/lib/silccrypt/tests/inst_twofish b/lib/silccrypt/tests/inst_twofish
new file mode 100644 (file)
index 0000000..9837a5d
--- /dev/null
@@ -0,0 +1,7 @@
+gcc -I.. \
+-I../../../includes -I../../silccore \
+-I../.. -I../../silccore -I../../silcmath \
+-I../../silcmath/gmp-2.0.2 -I../../silcske -I../../silcsim \
+-Wall -finline-functions \
+-o test_twofish test_twofish.c -L../.. -lsilc
+
diff --git a/lib/silccrypt/tests/insth b/lib/silccrypt/tests/insth
new file mode 100644 (file)
index 0000000..30e225d
--- /dev/null
@@ -0,0 +1,6 @@
+gcc -I../ 
+-I../../../includes -I../../silccore \
+-I../
+-Wall -finline-functions
+-o test_rsa test_rsa.c -L../.. -lsilc
+
diff --git a/lib/silccrypt/tests/test_mars.c b/lib/silccrypt/tests/test_mars.c
new file mode 100644 (file)
index 0000000..78bf2ff
--- /dev/null
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mars.h"
+
+int main()
+{
+       int i;
+       unsigned char key[256];
+       unsigned char plain[256];
+       unsigned char plain2[256];
+       unsigned char cipher[256];
+       unsigned char iv[256];
+
+       memset(&key, 0, sizeof(key));
+       memset(&plain, 0, sizeof(plain));
+       memset(&plain2, 0, sizeof(plain2));
+       memset(&cipher, 0, sizeof(cipher));
+       memset(&iv, 0, sizeof(iv));
+
+       fprintf(stderr, "\nKey:\n");
+       for (i = 0; i < (sizeof(key) / 2); i += 2) {
+               fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
+       }
+
+       fprintf(stderr, "\nSetting key\n");
+       silc_mars_init(NULL, key, 128);
+
+       fprintf(stderr, "\nPlaintext:\n");
+       for (i = 0; i < (sizeof(plain) / 2); i += 2) {
+               plain[i] = i;
+               plain[i+1] = i+1;
+               fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+       }
+
+       fprintf(stderr, "\n\nEncrypting\n");
+       silc_mars_encrypt_cbc(NULL, plain, cipher, 256, iv);
+
+       fprintf(stderr, "Ciphertext:\n");
+       for (i = 0; i < (sizeof(cipher)/2); i += 2) {
+               fprintf(stderr, "%02x", cipher[i]);
+               fprintf(stderr, "%02x ", cipher[i+1]);
+       }
+
+       fprintf(stderr, "\n\nDecrypting\n");
+       silc_mars_decrypt_cbc(NULL, cipher, plain2, 256, iv);
+
+       fprintf(stderr, "Decryptedtext:\n");
+       for (i = 0; i < (sizeof(plain2)/2); i += 2) {
+               fprintf(stderr, "%02x", plain2[i]);
+               fprintf(stderr, "%02x ", plain2[i+1]);
+       }
+       fprintf(stderr, "\nDone\n");
+
+       return 0;
+}
diff --git a/lib/silccrypt/tests/test_rijndael.c b/lib/silccrypt/tests/test_rijndael.c
new file mode 100644 (file)
index 0000000..ac07f54
--- /dev/null
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+main()
+{
+       int i, k;
+       unsigned char key[256];
+       unsigned char plain[256];
+       unsigned char plain2[256];
+       unsigned char cipher[256];
+       memset(&key, 0, sizeof(key));
+       memset(&plain, 0, sizeof(plain));
+       memset(&plain2, 0, sizeof(plain2));
+       memset(&cipher, 0, sizeof(cipher));
+
+       fprintf(stderr, "\nKey:\n");
+       for (i = 0; i < sizeof(key) / 2; i++) {
+               key[i] = i;
+               key[i+1] = i+1;
+               fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
+       }
+
+       fprintf(stderr, "\nSetting key\n");
+       set_key(key, 128);
+
+       fprintf(stderr, "\nPlaintext:\n");
+       for (i = 0; i < sizeof(plain) / 2; i++) {
+               plain[i] = i;
+               plain[i+1] = i+1;
+               fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+       }
+
+       fprintf(stderr, "Encrypting\n");
+       encrypt(plain, cipher);
+
+       fprintf(stderr, "\nCiphertext:\n");
+       for (i = 0; i < sizeof(cipher); i++) {
+               fprintf(stderr, "%02x", cipher[i]);
+       }
+
+       fprintf(stderr, "Decrypting\n");
+       decrypt(cipher, plain2);
+
+       fprintf(stderr, "\nDecryptedtext:\n");
+       for (i = 0; i < sizeof(plain2); i++) {
+               fprintf(stderr, "%02x", plain2[i]);
+       }
+
+}
diff --git a/lib/silccrypt/tests/test_rsa.c b/lib/silccrypt/tests/test_rsa.c
new file mode 100644 (file)
index 0000000..d8ff4df
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "silcincludes.h"
+#include "rsa.h"
+#include "rsa_internal.h"
+
+void testi(SilcRng rng, void *context)
+{
+        char *numbuf;
+        unsigned int bytes;
+        unsigned int i;
+        MP_INT tnum;            /* number we'll encrypt */
+        MP_INT test;            /* en/decrypted result of tnum */
+       RsaKey *key = (RsaKey *)context;
+       int bits = 1024;        
+
+        numbuf = (char *)malloc((bits / 3) + 1);
+        bytes = bits / 10;
+            
+        mpz_init(&tnum);
+        mpz_init(&test);
+        
+        fprintf(stderr, "\nTesting encryption and decryption ... ");
+
+        for(i = 0; i < bytes; i++)
+            sprintf(numbuf + 2 * i, "%02x", silc_rng_get_byte(rng));
+        
+        mpz_set_str(&tnum, numbuf, 16);
+
+        /* empty buffer */
+        memset(numbuf, 0, bits / 3);
+        free(numbuf);
+
+        /* make tnum smaller than n */
+        mpz_div_ui(&tnum, &tnum, 10);
+        /* encrypt */
+        rsa_en_de_crypt(&test, &tnum, &key->e, &key->n);
+        /* decrypt */
+        rsa_en_de_crypt(&test, &test, &key->d, &key->n);
+        /* see if decrypted result is same than the original one is */
+        if (mpz_cmp(&test, &tnum) != 0) {
+            fprintf(stderr, "Error in encryption and decryption!\n");
+            return -1;
+        }
+
+        mpz_clear(&tnum);
+        mpz_clear(&test);
+
+        fprintf(stderr, "Keys are Ok.\n");
+}
+
+int main()
+{
+       SilcPKCS pkcs;
+       SilcRng rng;
+       unsigned char *pk, *prv;
+       unsigned int pk_len, prv_len;
+       unsigned char *src, *dst, *new;
+       unsigned int src_len, dst_len, new_len;
+       SilcInt tnum, test;
+
+       silc_pkcs_alloc("rsa", &pkcs);
+
+       rng = silc_rng_alloc();
+       silc_rng_init(rng);
+       silc_math_primegen_init();
+
+       pkcs->pkcs->init(pkcs->context, 1024, rng);
+       
+       pk = silc_pkcs_get_public_key(pkcs, &pk_len);
+       prv = silc_pkcs_get_public_key(pkcs, &prv_len);
+
+       src = "PEKKA RIIKONEN";
+       src_len = 5;
+       dst = silc_calloc(200, sizeof(unsigned char));
+       pkcs->pkcs->encrypt(pkcs->context, src, src_len, dst, &dst_len);
+
+       SILC_LOG_HEXDUMP(("src"), src, src_len);
+       SILC_LOG_HEXDUMP(("dst"), dst, dst_len);
+
+       new = silc_calloc(200, sizeof(unsigned char));
+       pkcs->pkcs->decrypt(pkcs->context, dst, dst_len, new, &new_len);
+
+       SILC_LOG_HEXDUMP(("new"), new, new_len);
+
+       testi(rng, pkcs->context);
+
+       return 0;
+}
diff --git a/lib/silccrypt/tests/test_speed.c b/lib/silccrypt/tests/test_speed.c
new file mode 100644 (file)
index 0000000..65c2def
--- /dev/null
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+//#include "../ciphers.h"
+#include "../serpent.h"
+
+#define timediff(tv2, tv1)  (((tv2)->tv_sec - (tv1)->tv_sec)*1000000 + \
+                             ((tv2)->tv_usec - (tv1)->tv_usec))
+
+int main(int argc, char **argv)
+{
+       int i;
+       unsigned char key[256];
+       unsigned char plain[512];
+       unsigned char plain2[512];
+       unsigned char cipher[512];
+       unsigned char iv[128];
+       struct timeval tv1,tv2;
+
+       memset(&key, 0, sizeof(key));
+       memset(&plain, 0, sizeof(plain));
+       memset(&plain2, 0, sizeof(plain2));
+       memset(&cipher, 0, sizeof(cipher));
+       memset(&iv, 0, sizeof(iv));
+
+       gettimeofday(&tv1, NULL);
+       silc_serpent_init(NULL, key, 128);
+       gettimeofday(&tv2, NULL);
+
+       fprintf(stderr, "\nPlaintext:\n");
+       for (i = 0; i < sizeof(plain) / 2; i += 2) {
+               plain[i] = i;
+               plain[i+1] = i+1;
+               fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+       }
+
+       fprintf(stderr, "\n\nEncrypting\n");
+       gettimeofday(&tv1, NULL);
+       silc_serpent_encrypt_cbc(NULL, plain, cipher, sizeof(plain), iv);
+       gettimeofday(&tv2, NULL);
+
+       fprintf(stderr, "Encrypt %6.3f Mb/s\n", 
+                  1000000.0*8.0/timediff(&tv2,&tv1));
+
+       fprintf(stderr, "Ciphertext:\n");
+       for (i = 0; i < (sizeof(cipher)/2); i += 2) {
+               fprintf(stderr, "%02x", cipher[i]);
+               fprintf(stderr, "%02x ", cipher[i+1]);
+       }
+
+       fprintf(stderr, "\n\nDecrypting\n");
+       gettimeofday(&tv1, NULL);
+       silc_serpent_decrypt_cbc(NULL, cipher, plain2, sizeof(cipher), iv);
+       gettimeofday(&tv2, NULL);
+
+       fprintf(stderr, "Decrypt %6.3f Mb/s\n", 
+                  1000000.0*8.0/timediff(&tv2,&tv1));
+
+       fprintf(stderr, "Decrypted text:\n");
+       for (i = 0; i < (sizeof(plain2)/2); i += 2) {
+               fprintf(stderr, "%02x", plain2[i]);
+               fprintf(stderr, "%02x ", plain2[i+1]);
+       }
+       fprintf(stderr, "\nDone\n");
+
+       return 0;
+}
diff --git a/lib/silccrypt/tests/test_twofish.c b/lib/silccrypt/tests/test_twofish.c
new file mode 100644 (file)
index 0000000..4467e0e
--- /dev/null
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+       int i, k, l;
+       unsigned char key[256];
+       unsigned char plain[256];
+       unsigned char plain2[256];
+       unsigned char cipher[256];
+       memset(&key, 0, sizeof(key));
+       memset(&plain, 0, sizeof(plain));
+       memset(&plain2, 0, sizeof(plain2));
+       memset(&cipher, 0, sizeof(cipher));
+
+       fprintf(stderr, "\nKey:\n");
+       for (i = 0; i < (sizeof(plain) / 2); i++) {
+               key[i] = i;
+               key[i+1] = i+1;
+               fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
+       }
+
+       fprintf(stderr, "\nSetting key\n");
+       set_key(key, 128);
+
+       fprintf(stderr, "\nPlaintext:\n");
+       for (i = 0; i < (sizeof(plain) / 2); i++) {
+               plain[i] = i;
+               plain[i+1] = i+1;
+               fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
+       }
+
+       fprintf(stderr, "\n\nEncrypting\n");
+       fprintf(stderr, "Ciphertext:\n");
+       l = 0;
+       for (k = 0; k < 8; k++) {
+               encrypt(&plain[l], &cipher[l]);
+               for (i = 0; i < 16; i++) {
+                       fprintf(stderr, "%02x", cipher[l+i]);
+                       fprintf(stderr, "%02x ", cipher[l+i+1]);
+               }
+               l += 16;
+       }
+
+       fprintf(stderr, "\n\nDecrypting\n");
+
+       fprintf(stderr, "Decryptedtext:\n");
+       l = 0;
+       for (k = 0; k < 8; k++) {
+               decrypt(&cipher[l], &plain2[l]);
+               for (i = 0; i < 16; i++) {
+                       fprintf(stderr, "%02x", plain2[l+i]);
+                       fprintf(stderr, "%02x ", plain2[l+i+1]);
+               }
+               l += 16;
+       }
+       fprintf(stderr, "\nAll done.\n");
+
+       return 0;
+}
diff --git a/lib/silccrypt/twofish.c b/lib/silccrypt/twofish.c
new file mode 100644 (file)
index 0000000..08d3d51
--- /dev/null
@@ -0,0 +1,601 @@
+/* Modified for SILC. -Pekka */
+
+/* This is an independent implementation of the encryption algorithm:   */
+/*                                                                      */
+/*         Twofish by Bruce Schneier and colleagues                     */
+/*                                                                      */
+/* which is a candidate algorithm in the Advanced Encryption Standard   */
+/* programme of the US National Institute of Standards and Technology.  */
+/*                                                                      */
+/* Copyright in this implementation is held by Dr B R Gladman but I     */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions   */
+/* that the originators of t he algorithm place on its exploitation.     */
+/*                                                                      */
+/* My thanks to Doug Whiting and Niels Ferguson for comments that led   */
+/* to improvements in this implementation.                              */
+/*                                                                      */
+/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */
+
+/* Timing data for Twofish (twofish.c)
+
+128 bit key:
+Key Setup:    8414 cycles
+Encrypt:       376 cycles =    68.1 mbits/sec
+Decrypt:       374 cycles =    68.4 mbits/sec
+Mean:          375 cycles =    68.3 mbits/sec
+
+192 bit key:
+Key Setup:   11628 cycles
+Encrypt:       376 cycles =    68.1 mbits/sec
+Decrypt:       374 cycles =    68.4 mbits/sec
+Mean:          375 cycles =    68.3 mbits/sec
+
+256 bit key:
+Key Setup:   15457 cycles
+Encrypt:       381 cycles =    67.2 mbits/sec
+Decrypt:       374 cycles =    68.4 mbits/sec
+Mean:          378 cycles =    67.8 mbits/sec
+
+*/
+
+#include "silcincludes.h"
+#include "twofish.h"
+
+/* 
+ * SILC Crypto API for Twofish
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(twofish)
+{
+  twofish_set_key((TwofishContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(twofish)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(twofish)
+{
+  return sizeof(TwofishContext);
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(twofish)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  twofish_encrypt((TwofishContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    twofish_encrypt((TwofishContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = out[0 - 4];
+  tiv[1] = out[1 - 4];
+  tiv[2] = out[2 - 4];
+  tiv[3] = out[3 - 4];
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(twofish)
+{
+  unsigned int *tiv, *in, *out;
+  unsigned int tmp[4], tmp2[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0];
+  tmp[1] = in[1];
+  tmp[2] = in[2];
+  tmp[3] = in[3];
+  twofish_decrypt((TwofishContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp2[0] = tmp[0];
+    tmp2[1] = tmp[1];
+    tmp2[2] = tmp[2];
+    tmp2[3] = tmp[3];
+    tmp[0] = in[0];
+    tmp[1] = in[1];
+    tmp[2] = in[2];
+    tmp[3] = in[3];
+    twofish_decrypt((TwofishContext *)context, in, out);
+    out[0] ^= tmp2[0];
+    out[1] ^= tmp2[1];
+    out[2] ^= tmp2[2];
+    out[3] ^= tmp2[3];
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = tmp[0];
+  tiv[1] = tmp[1];
+  tiv[2] = tmp[2];
+  tiv[3] = tmp[3];
+
+  return TRUE;
+}
+
+#if 0
+#define Q_TABLES
+#define M_TABLE
+#define MK_TABLE
+#define ONE_STEP
+#endif
+
+/* finite field arithmetic for GF(2**8) with the modular    */
+/* polynomial x^8 + x^6 + x^5 + x^3 + 1 (0x169)             */
+
+#define G_M 0x0169
+
+u1byte  tab_5b[4] = { 0, G_M >> 2, G_M >> 1, (G_M >> 1) ^ (G_M >> 2) };
+u1byte  tab_ef[4] = { 0, (G_M >> 1) ^ (G_M >> 2), G_M >> 1, G_M >> 2 };
+
+#define ffm_01(x)    (x)
+#define ffm_5b(x)   ((x) ^ ((x) >> 2) ^ tab_5b[(x) & 3])
+#define ffm_ef(x)   ((x) ^ ((x) >> 1) ^ ((x) >> 2) ^ tab_ef[(x) & 3])
+
+u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
+u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };
+
+u1byte qt0[2][16] = 
+{   { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
+    { 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
+};
+
+u1byte qt1[2][16] =
+{   { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 }, 
+    { 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
+};
+
+u1byte qt2[2][16] = 
+{   { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
+    { 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
+};
+
+u1byte qt3[2][16] = 
+{   { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
+    { 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
+};
+u1byte qp(const u4byte n, const u1byte x)
+{   u1byte  a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;
+
+    a0 = x >> 4; b0 = x & 15;
+    a1 = a0 ^ b0; b1 = ror4[b0] ^ ashx[a0];
+    a2 = qt0[n][a1]; b2 = qt1[n][b1];
+    a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
+    a4 = qt2[n][a3]; b4 = qt3[n][b3];
+    return (b4 << 4) | a4;
+};
+
+#ifdef  Q_TABLES
+
+u4byte  qt_gen = 0;
+u1byte  q_tab[2][256];
+
+#define q(n,x)  q_tab[n][x]
+
+void gen_qtab(void)
+{   u4byte  i;
+
+    for(i = 0; i < 256; ++i)
+    {       
+        q(0,i) = qp(0, (u1byte)i);
+        q(1,i) = qp(1, (u1byte)i);
+    }
+};
+
+#else
+
+#define q(n,x)  qp(n, x)
+
+#endif
+
+#ifdef  M_TABLE
+
+u4byte  mt_gen = 0;
+u4byte  m_tab[4][256];
+
+void gen_mtab(void)
+{   u4byte  i, f01, f5b, fef;
+    
+    for(i = 0; i < 256; ++i)
+    {
+        f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
+        m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
+        m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);
+
+        f01 = q(0,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
+        m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
+        m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
+    }
+};
+
+#define mds(n,x)    m_tab[n][x]
+
+#else
+
+#define fm_00   ffm_01
+#define fm_10   ffm_5b
+#define fm_20   ffm_ef
+#define fm_30   ffm_ef
+#define q_0(x)  q(1,x)
+
+#define fm_01   ffm_ef
+#define fm_11   ffm_ef
+#define fm_21   ffm_5b
+#define fm_31   ffm_01
+#define q_1(x)  q(0,x)
+
+#define fm_02   ffm_5b
+#define fm_12   ffm_ef
+#define fm_22   ffm_01
+#define fm_32   ffm_ef
+#define q_2(x)  q(1,x)
+
+#define fm_03   ffm_5b
+#define fm_13   ffm_01
+#define fm_23   ffm_ef
+#define fm_33   ffm_5b
+#define q_3(x)  q(0,x)
+
+#define f_0(n,x)    ((u4byte)fm_0##n(x))
+#define f_1(n,x)    ((u4byte)fm_1##n(x) << 8)
+#define f_2(n,x)    ((u4byte)fm_2##n(x) << 16)
+#define f_3(n,x)    ((u4byte)fm_3##n(x) << 24)
+
+#define mds(n,x)    f_0(n,q_##n(x)) ^ f_1(n,q_##n(x)) ^ f_2(n,q_##n(x)) ^ f_3(n,q_##n(x))
+
+#endif
+
+u4byte h_fun(TwofishContext *ctx, const u4byte x, const u4byte key[])
+{   u4byte  b0, b1, b2, b3;
+
+#ifndef M_TABLE
+    u4byte  m5b_b0, m5b_b1, m5b_b2, m5b_b3;
+    u4byte  mef_b0, mef_b1, mef_b2, mef_b3;
+#endif
+
+    b0 = byte(x, 0); b1 = byte(x, 1); b2 = byte(x, 2); b3 = byte(x, 3);
+
+    switch(ctx->k_len)
+    {
+    case 4: b0 = q(1, b0) ^ byte(key[3],0);
+            b1 = q(0, b1) ^ byte(key[3],1);
+            b2 = q(0, b2) ^ byte(key[3],2);
+            b3 = q(1, b3) ^ byte(key[3],3);
+    case 3: b0 = q(1, b0) ^ byte(key[2],0);
+            b1 = q(1, b1) ^ byte(key[2],1);
+            b2 = q(0, b2) ^ byte(key[2],2);
+            b3 = q(0, b3) ^ byte(key[2],3);
+    case 2: b0 = q(0,q(0,b0) ^ byte(key[1],0)) ^ byte(key[0],0);
+            b1 = q(0,q(1,b1) ^ byte(key[1],1)) ^ byte(key[0],1);
+            b2 = q(1,q(0,b2) ^ byte(key[1],2)) ^ byte(key[0],2);
+            b3 = q(1,q(1,b3) ^ byte(key[1],3)) ^ byte(key[0],3);
+    }
+#ifdef  M_TABLE
+
+    return  mds(0, b0) ^ mds(1, b1) ^ mds(2, b2) ^ mds(3, b3);
+
+#else
+
+    b0 = q(1, b0); b1 = q(0, b1); b2 = q(1, b2); b3 = q(0, b3);
+    m5b_b0 = ffm_5b(b0); m5b_b1 = ffm_5b(b1); m5b_b2 = ffm_5b(b2); m5b_b3 = ffm_5b(b3);
+    mef_b0 = ffm_ef(b0); mef_b1 = ffm_ef(b1); mef_b2 = ffm_ef(b2); mef_b3 = ffm_ef(b3);
+    b0 ^= mef_b1 ^ m5b_b2 ^ m5b_b3; b3 ^= m5b_b0 ^ mef_b1 ^ mef_b2;
+    b2 ^= mef_b0 ^ m5b_b1 ^ mef_b3; b1 ^= mef_b0 ^ mef_b2 ^ m5b_b3;
+
+    return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);
+
+#endif
+};
+
+#ifdef  MK_TABLE
+
+#ifdef  ONE_STEP
+u4byte  mk_tab[4][256];
+#else
+u1byte  sb[4][256];
+#endif
+
+#define q20(x)  q(0,q(0,x) ^ byte(key[1],0)) ^ byte(key[0],0)
+#define q21(x)  q(0,q(1,x) ^ byte(key[1],1)) ^ byte(key[0],1)
+#define q22(x)  q(1,q(0,x) ^ byte(key[1],2)) ^ byte(key[0],2)
+#define q23(x)  q(1,q(1,x) ^ byte(key[1],3)) ^ byte(key[0],3)
+
+#define q30(x)  q(0,q(0,q(1, x) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
+#define q31(x)  q(0,q(1,q(1, x) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
+#define q32(x)  q(1,q(0,q(0, x) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
+#define q33(x)  q(1,q(1,q(0, x) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)
+
+#define q40(x)  q(0,q(0,q(1, q(1, x) ^ byte(key[3],0)) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
+#define q41(x)  q(0,q(1,q(1, q(0, x) ^ byte(key[3],1)) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
+#define q42(x)  q(1,q(0,q(0, q(0, x) ^ byte(key[3],2)) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
+#define q43(x)  q(1,q(1,q(0, q(1, x) ^ byte(key[3],3)) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)
+
+void gen_mk_tab(TwofishContext *ctx, u4byte key[])
+{   u4byte  i;
+    u1byte  by;
+
+    switch(ctx->k_len)
+    {
+    case 2: for(i = 0; i < 256; ++i)
+            {
+                by = (u1byte)i;
+#ifdef ONE_STEP
+                mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
+                mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));
+#else
+                sb[0][i] = q20(by); sb[1][i] = q21(by); 
+                sb[2][i] = q22(by); sb[3][i] = q23(by);
+#endif
+            }
+            break;
+    
+    case 3: for(i = 0; i < 256; ++i)
+            {
+                by = (u1byte)i;
+#ifdef ONE_STEP
+                mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
+                mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));
+#else
+                sb[0][i] = q30(by); sb[1][i] = q31(by); 
+                sb[2][i] = q32(by); sb[3][i] = q33(by);
+#endif
+            }
+            break;
+    
+    case 4: for(i = 0; i < 256; ++i)
+            {
+                by = (u1byte)i;
+#ifdef ONE_STEP
+                mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
+                mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));
+#else
+                sb[0][i] = q40(by); sb[1][i] = q41(by); 
+                sb[2][i] = q42(by); sb[3][i] = q43(by);
+#endif
+            }
+    }
+};
+
+#  ifdef ONE_STEP
+#    define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
+                      ^ mk_tab[2][byte(x,2)] ^ mk_tab[3][byte(x,3)] )
+#    define g1_fun(x) ( mk_tab[0][byte(x,3)] ^ mk_tab[1][byte(x,0)] \
+                      ^ mk_tab[2][byte(x,1)] ^ mk_tab[3][byte(x,2)] )
+#  else
+#    define g0_fun(x) ( mds(0, sb[0][byte(x,0)]) ^ mds(1, sb[1][byte(x,1)]) \
+                      ^ mds(2, sb[2][byte(x,2)]) ^ mds(3, sb[3][byte(x,3)]) )
+#    define g1_fun(x) ( mds(0, sb[0][byte(x,3)]) ^ mds(1, sb[1][byte(x,0)]) \
+                      ^ mds(2, sb[2][byte(x,1)]) ^ mds(3, sb[3][byte(x,2)]) )
+#  endif
+
+#else
+
+#define g0_fun(x)   h_fun(ctx,x,s_key)
+#define g1_fun(x)   h_fun(ctx,rotl(x,8),s_key)
+
+#endif
+
+/* The (12,8) Reed Soloman code has the generator polynomial
+
+  g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1
+
+where the coefficients are in the finite field GF(2^8) with a
+modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
+remainder we have to start with a 12th order polynomial with our
+eight input bytes as the coefficients of the 4th to 11th terms. 
+That is:
+
+  m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0
+  
+We then multiply the generator polynomial by m[7] * x^7 and subtract
+it - xor in GF(2^8) - from the above to eliminate the x^7 term (the 
+artihmetic on the coefficients is done in GF(2^8). We then multiply 
+the generator polynomial by x^6 * coeff(x^10) and use this to remove
+the x^10 term. We carry on in this way until the x^4 term is removed
+so that we are left with:
+
+  r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]
+
+which give the resulting 4 bytes of the remainder. This is equivalent 
+to the matrix multiplication in the Twofish description but much faster 
+to implement.
+
+*/
+
+#define G_MOD   0x0000014d
+
+u4byte mds_rem(u4byte p0, u4byte p1)
+{   u4byte  i, t, u;
+
+    for(i = 0; i < 8; ++i)
+    {
+        t = p1 >> 24;   // get most significant coefficient
+        
+        p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8;  // shift others up
+            
+        // multiply t by a (the primitive element - i.e. left shift)
+
+        u = (t << 1); 
+        
+        if(t & 0x80)            // subtract modular polynomial on overflow
+        
+            u ^= G_MOD; 
+
+        p1 ^= t ^ (u << 16);    // remove t * (a * x^2 + 1)  
+
+        u ^= (t >> 1);          // form u = a * t + t / a = t * (a + 1 / a); 
+        
+        if(t & 0x01)            // add the modular polynomial on underflow
+        
+            u ^= G_MOD >> 1;
+
+        p1 ^= (u << 24) | (u << 8); // remove t * (a + 1/a) * (x^3 + x)
+    }
+
+    return p1;
+};
+
+/* initialise the key schedule from the user supplied key   */
+
+u4byte *twofish_set_key(TwofishContext *ctx,
+                       const u4byte in_key[], const u4byte key_len)
+{   
+    u4byte  i, a, b, me_key[4], mo_key[4];
+    u4byte *l_key = ctx->l_key;
+    u4byte *s_key = ctx->s_key;
+    
+#ifdef Q_TABLES
+    if(!qt_gen)
+    {
+        gen_qtab(); qt_gen = 1;
+    }
+#endif
+
+#ifdef M_TABLE
+    if(!mt_gen)
+    {
+        gen_mtab(); mt_gen = 1;
+    }
+#endif
+
+    ctx->k_len = ctx->k_len = key_len / 64;   /* 2, 3 or 4 */
+
+    for(i = 0; i < ctx->k_len; ++i)
+    {
+        a = in_key[i + i];     me_key[i] = a;
+        b = in_key[i + i + 1]; mo_key[i] = b;
+        s_key[ctx->k_len - i - 1] = mds_rem(a, b);
+    }
+
+    for(i = 0; i < 40; i += 2)
+    {
+        a = 0x01010101 * i; b = a + 0x01010101;
+        a = h_fun(ctx,a, me_key);
+        b = rotl(h_fun(ctx,b, mo_key), 8);
+        l_key[i] = a + b;
+        l_key[i + 1] = rotl(a + 2 * b, 9);
+    }
+
+#ifdef MK_TABLE
+    gen_mk_tab(ctx,s_key);
+#endif
+
+    return l_key;
+};
+
+/* encrypt a block of text  */
+
+#define f_rnd(i)                                                    \
+    t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
+    blk[2] = rotr(blk[2] ^ (t0 + t1 + l_key[4 * (i) + 8]), 1);      \
+    blk[3] = rotl(blk[3], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]);  \
+    t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
+    blk[0] = rotr(blk[0] ^ (t0 + t1 + l_key[4 * (i) + 10]), 1);     \
+    blk[1] = rotl(blk[1], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 11])
+
+void twofish_encrypt(TwofishContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[])
+{   
+    u4byte  t0, t1, blk[4];
+    u4byte *l_key = ctx->l_key;
+    u4byte *s_key = ctx->s_key;
+
+    blk[0] = in_blk[0] ^ l_key[0];
+    blk[1] = in_blk[1] ^ l_key[1];
+    blk[2] = in_blk[2] ^ l_key[2];
+    blk[3] = in_blk[3] ^ l_key[3];
+
+    f_rnd(0); f_rnd(1); f_rnd(2); f_rnd(3);
+    f_rnd(4); f_rnd(5); f_rnd(6); f_rnd(7);
+
+    out_blk[0] = blk[2] ^ l_key[4];
+    out_blk[1] = blk[3] ^ l_key[5];
+    out_blk[2] = blk[0] ^ l_key[6];
+    out_blk[3] = blk[1] ^ l_key[7]; 
+};
+
+/* decrypt a block of text  */
+
+#define i_rnd(i)                                                        \
+        t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
+        blk[2] = rotl(blk[2], 1) ^ (t0 + t1 + l_key[4 * (i) + 10]);     \
+        blk[3] = rotr(blk[3] ^ (t0 + 2 * t1 + l_key[4 * (i) + 11]), 1); \
+        t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
+        blk[0] = rotl(blk[0], 1) ^ (t0 + t1 + l_key[4 * (i) +  8]);     \
+        blk[1] = rotr(blk[1] ^ (t0 + 2 * t1 + l_key[4 * (i) +  9]), 1)
+
+void twofish_decrypt(TwofishContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[4])
+{   
+    u4byte  t0, t1, blk[4];
+    u4byte *l_key = ctx->l_key;
+    u4byte *s_key = ctx->s_key;
+
+    blk[0] = in_blk[0] ^ l_key[4];
+    blk[1] = in_blk[1] ^ l_key[5];
+    blk[2] = in_blk[2] ^ l_key[6];
+    blk[3] = in_blk[3] ^ l_key[7];
+
+    i_rnd(7); i_rnd(6); i_rnd(5); i_rnd(4);
+    i_rnd(3); i_rnd(2); i_rnd(1); i_rnd(0);
+
+    out_blk[0] = blk[2] ^ l_key[0];
+    out_blk[1] = blk[3] ^ l_key[1];
+    out_blk[2] = blk[0] ^ l_key[2];
+    out_blk[3] = blk[1] ^ l_key[3]; 
+};
diff --git a/lib/silccrypt/twofish.h b/lib/silccrypt/twofish.h
new file mode 100644 (file)
index 0000000..565bb8e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+  twofish.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef TWOFISH_H
+#define TWOFISH_H
+
+#include "twofish_internal.h"
+
+/* 
+ * SILC Crypto API for Twofish
+ */
+
+SILC_CIPHER_API_SET_KEY(twofish);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(twofish);
+SILC_CIPHER_API_CONTEXT_LEN(twofish);
+SILC_CIPHER_API_ENCRYPT_CBC(twofish);
+SILC_CIPHER_API_DECRYPT_CBC(twofish);
+
+#endif
diff --git a/lib/silccrypt/twofish_internal.h b/lib/silccrypt/twofish_internal.h
new file mode 100644 (file)
index 0000000..0cabe2c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+
+  twofish_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef TWOFISH_INTERNAL_H
+#define TWOFISH_INTERNAL_H
+
+#include "ciphers_def.h"
+
+/* Cipher's context */
+typedef struct {
+  u4byte k_len;
+  u4byte l_key[40];
+  u4byte s_key[4];
+} TwofishContext;
+
+/* Prototypes */
+u4byte *twofish_set_key(TwofishContext *ctx,
+                       const u4byte in_key[], const u4byte key_len);
+void twofish_encrypt(TwofishContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[]);
+void twofish_decrypt(TwofishContext *ctx,
+                    const u4byte in_blk[4], u4byte out_blk[4]);
+
+#endif
diff --git a/lib/silcmath/Makefile.am b/lib/silcmath/Makefile.am
new file mode 100644 (file)
index 0000000..436ad72
--- /dev/null
@@ -0,0 +1,33 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+SUBDIRS = gmp-3.0.1
+
+noinst_LIBRARIES = libsilcmath.a
+
+libsilcmath_a_SOURCES = \
+       silcprimegen.c \
+       modinv.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcske \
+       -I../silcsim -I../.. -I../../includes \
+       -I./gmp-3.0.1
diff --git a/lib/silcmath/modinv.c b/lib/silcmath/modinv.c
new file mode 100644 (file)
index 0000000..1a60f7b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+
+  modinv.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+/* Table for finding multiplicative inverse */
+typedef struct {
+  SilcInt x;
+} ModInv;
+
+#define plus1  (i == 2 ? 0 : i + 1)
+#define minus1         (i == 0 ? 2 : i - 1)
+
+/* Find multiplicative inverse using Euclid's extended algorithm. 
+   Computes inverse such that a * inv mod n = 1, where 0 < a < n. 
+   Algorithm goes like this:
+   
+   g(0) = n    v(0) = 0
+   g(1) = a    v(1) = 1
+   
+   y = g(i-1) / g(i)
+   g(i+1) = g(i-1) - y * g(i) = g(i)-1 mod g(i)
+   v(i+1) = v(i-1) - y * v(i)
+   
+   do until g(i) = 0, then inverse = v(i-1). If inverse is negative then n, 
+   is added to inverse making it positive again. (Sometimes the algorithm 
+   has a variable u defined too and it behaves just like v, except that 
+   initalize values are swapped (i.e. u(0) = 1, u(1) = 0). However, u is 
+   not needed by the algorithm so it does not have to be included.)
+*/
+
+void silc_mp_modinv(SilcInt *inv, SilcInt *a, SilcInt *n)
+{
+  int i;
+  SilcInt y;
+  SilcInt x;
+  
+  ModInv g[3];
+  ModInv v[3];
+  
+  /* init MP vars */
+  silc_mp_init(&y);
+  silc_mp_init(&x);
+  silc_mp_init_set_ui(&v[0].x, 0L);            /* v(0) = 0 */
+  silc_mp_init_set_ui(&v[1].x, 1L);            /* v(1) = 1 */
+  silc_mp_init(&v[2].x);
+  silc_mp_init_set(&g[0].x, n);                        /* g(0) = n */
+  silc_mp_init_set(&g[1].x, a);                        /* g(1) = a */
+  silc_mp_init(&g[2].x);
+  
+  i = 1;
+  while(silc_mp_cmp_ui(&g[i].x, 0) != 0) {
+    silc_mp_div(&y, &g[minus1].x, &g[i].x);            /* y = n / a */
+    silc_mp_mod(&g[plus1].x, &g[minus1].x, &g[i].x); /* remainder */
+    silc_mp_mul(&x, &y, &v[i].x);
+    silc_mp_set(&v[plus1].x, &v[minus1].x);
+    silc_mp_sub(&v[plus1].x, &v[plus1].x, &x);
+    i = plus1;
+  }
+  
+  /* set the inverse */
+  silc_mp_set(inv, &v[minus1].x);
+  
+  /* if inverse is negative, add n to inverse */
+  if (silc_mp_cmp_ui(inv, 0) < 0)
+    silc_mp_add(inv, inv, n);
+  
+  /* clear the vars */
+  memset(&g, 0, sizeof(g));
+  memset(&v, 0, sizeof(v));
+  silc_mp_clear(&y);
+  silc_mp_clear(&x);
+  silc_mp_clear(&g[0].x);
+  silc_mp_clear(&g[1].x);
+  silc_mp_clear(&g[2].x);
+  silc_mp_clear(&v[0].x);
+  silc_mp_clear(&v[1].x);
+  silc_mp_clear(&v[2].x);
+}
diff --git a/lib/silcmath/modinv.h b/lib/silcmath/modinv.h
new file mode 100644 (file)
index 0000000..4a8cfeb
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+
+  modinv.h
+  
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef MODINV_H
+#define MODINV_H
+
+void silc_mp_modinv(SilcInt *inv, SilcInt *a, SilcInt *n);
+
+#endif
diff --git a/lib/silcmath/silcmp.h b/lib/silcmath/silcmp.h
new file mode 100644 (file)
index 0000000..0b64218
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+
+  silcmp.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCMP_H
+#define SILCMP_H
+
+#include "gmp.h"
+
+/* SILC MP library definitions. We use GNU MP library as default
+   MP library. However, to make possible future changes easier (SILC 
+   might have its own MP library in the future) we implement our own 
+   MP API with simple macros. */ 
+
+typedef MP_INT SilcInt;
+#define silc_mp_abs(a, b) mpz_abs((a), (b))
+#define silc_mp_add(a, b, c) mpz_add((a), (b), (c))
+#define silc_mp_add_ui(a, b, c) mpz_add_ui((a), (b), (c))
+#define silc_mp_and(a, b, c) mpz_and((a), (b), (c))
+#define silc_mp_cdiv_q(a, b, c) mpz_cdiv_q((a), (b), (c))
+#define silc_mp_cdiv_q_ui(a, b, c) mpz_cdiv_q_ui((a), (b), (c))
+#define silc_mp_cdiv_r(a, b, c) mpz_cdiv_r((a), (b), (c))
+#define silc_mp_cdiv_r_ui(a, b, c) mpz_cdiv_r_ui((a), (b), (c))
+#define silc_mp_cdiv_ui(a, b) mpz_cdiv_ui((a), (b))
+#define silc_mp_clear(a) mpz_clear((a))
+#define silc_mp_clrbit(a, b) mpz_clrbit((a), (b))
+#define silc_mp_cmp(a, b) mpz_cmp((a), (b))
+#define silc_mp_cmp_si(a, b) mpz_cmp_si((a), (b))
+#define silc_mp_cmp_ui(a, b) mpz_cmp_ui((a), (b))
+#define silc_mp_com(a, b) mpz_com((a), (b))
+#define silc_mp_divexact(a, b, c) mpz_divexact((a), (b), (c))
+#define silc_mp_div(a, b, c) mpz_div((a), (b), (c))
+#define silc_mp_div_ui(a, b, c) mpz_div_ui((a), (b), (c))
+#define silc_mp_fdiv_ui(a, b) mpz_fdiv_ui((a), (b))
+#define silc_mp_fdiv_q(a, b, c) mpz_fdiv_q((a), (b), (c))
+#define silc_mp_fdiv_q_2exp(a, b, c) mpz_fdiv_q_2exp((a), (b), (c))
+#define silc_mp_fdiv_q_ui(a, b, c) mpz_fdiv_q_ui((a), (b), (c))
+#define silc_mp_fdiv_qr(a, b, c, d) mpz_fdiv_qr((a), (b), (c), (d))
+#define silc_mp_fdiv_qr_ui(a, b, c, d) mpz_fdiv_qr_ui((a), (b), (c), (d))
+#define silc_mp_fdiv_r(a, b, c) mpz_fdiv_r((a), (b), (c))
+#define silc_mp_fdiv_r_2exp(a, b, c) mpz_fdiv_r_2exp((a), (b), (c))
+#define silc_mp_fdiv_r_ui(a, b, c) mpz_fdiv_r_ui((a), (b), (c))
+#define silc_mp_fdiv_ui(a, b) mpz_fdiv_ui((a), (b))
+#define silc_mp_gcd(a, b, c) mpz_gcd((a), (b), (c))
+#define silc_mp_gcd_ui(a, b, c) mpz_gcd_ui((a), (b), (c))
+#define silc_mp_gcdext(a, b, c, d, e) mpz_gcdext((a), (b), (c), (d), (e))
+#define silc_mp_get_ui(a) mpz_get_ui((a))
+#define silc_mp_init(a) mpz_init((a))
+#define silc_mp_init_set(a, b) mpz_init_set((a), (b))
+#define silc_mp_init_set_d(a, b) mpz_init_set_d((a), (b))
+#define silc_mp_init_set_si(a, b) mpz_init_set_si((a), (b))
+#define silc_mp_init_set_str(a, b, c) mpz_init_set_str((a), (b), (c))
+#define silc_mp_init_set_ui(a, b) mpz_init_set_ui((a), (b))
+#define silc_mp_invert(a, b, c) mpz_invert((a), (b), (c))
+#define silc_mp_ior(a, b, c) mpz_ior((a), (b), (c))
+#define silc_mp_mod(a, b, c) mpz_mod((a), (b), (c))
+#define silc_mp_mod_2exp(a, b, c) mpz_mod_2exp((a), (b), (c))
+#define silc_mp_mod_ui(a, b, c) mpz_mod_ui((a), (b), (c))
+#define silc_mp_mul(a, b, c) mpz_mul((a), (b), (c))
+#define silc_mp_mul_2exp(a, b, c) mpz_mul_2exp((a), (b), (c))
+#define silc_mp_mul_ui(a, b, c) mpz_mul_ui((a), (b), (c))
+#define silc_mp_neg(a, b) mpz_neg((a), (b))
+#define silc_mp_pow_ui(a, b, c) mpz_pow_ui((a), (b), (c))
+#define silc_mp_powm(a, b, c, d) mpz_powm((a), (b), (c), (d))
+#define silc_mp_powm_ui(a, b, c, d) mpz_powm_ui((a), (b), (c), (d))
+#define silc_mp_probab_prime_p(a, b) mpz_probab_prime_p((a), (b))
+#define silc_mp_set(a, b) mpz_set((a), (b))
+#define silc_mp_set_d(a, b) mpz_set_d((a), (b))
+#define silc_mp_set_f(a, b) mpz_set_f((a), (b))
+#define silc_mp_set_q(a, b) mpz_set_q((a), (b))
+#define silc_mp_set_si(a, b) mpz_set_si((a), (b))
+#define silc_mp_set_str(a, b, c) mpz_set_str((a), (b), (c))
+#define silc_mp_set_ui(a, b) mpz_set_ui((a), (b))
+#define silc_mp_setbit(a, b) mpz_setbit((a), (b))
+#define silc_mp_size(a) mpz_size((a))
+#define silc_mp_sizeinbase(a, b) mpz_sizeinbase((a), (b))
+#define silc_mp_sqrt(a, b) mpz_sqrt((a), (b))
+#define silc_mp_sqrtrem(a, b, c) mpz_sqrtrem((a), (b), (c))
+#define silc_mp_sub(a, b, c) mpz_sub((a), (b), (c))
+#define silc_mp_sub_ui(a, b, c) mpz_sub_ui((a), (b), (c))
+#define silc_mp_tdiv_ui(a, b) mpz_tdiv_ui((a), (b))
+#define silc_mp_tdiv_q(a, b, c) mpz_tdiv_q((a), (b), (c))
+#define silc_mp_tdiv_q_2exp(a, b, c) mpz_tdiv_q_2exp((a), (b), (c))
+#define silc_mp_tdiv_q_ui(a, b, c) mpz_tdiv_q_ui((a), (b), (c))
+#define silc_mp_tdiv_qr(a, b, c, d) mpz_tdiv_qr((a), (b), (c), (d))
+#define silc_mp_tdiv_qr_ui(a, b, c, d) mpz_tdiv_qr_ui((a), (b), (c), (d))
+#define silc_mp_tdiv_r(a, b, c) mpz_tdiv_r((a), (b), (c))
+#define silc_mp_tdiv_r_2exp(a, b, c) mpz_tdiv_r_2exp((a), (b), (c))
+#define silc_mp_tdiv_r_ui(a, b, c) mpz_tdiv_r_ui((a), (b), (c))
+#define silc_mp_tdiv_ui(a, b) mpz_tdiv_ui((a), (b))
+#define silc_mp_ui_pow_ui(a, b, c) mpz_ui_pow_ui((a), (b), (c))
+#define silc_mp_get_str(a, b, c) mpz_get_str((a), (b), (c))
+#define silc_mp_out_str(a, b, c) mpz_out_str((a), (b), (c))
+
+#endif
diff --git a/lib/silcmath/silcprimegen.c b/lib/silcmath/silcprimegen.c
new file mode 100644 (file)
index 0000000..14719be
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+
+  silcprimegen.c
+  
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * Created: Mon Dec  8 16:35:37 GMT+0200 1997
+ */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:51  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+
+/* XXX This must be temporary solution!! yucky! */
+/* Global random pool used for all prime generation. All primes generated
+   in SILC uses this same pool. Before primes can be generated one must
+   call silc_math_primegen_init. */
+static SilcRng primegen_rng;
+
+/* 
+   Fixed primetable for small prime division. We use this primetable to 
+   test if possible prime is divisible any of these. Primetable is NULL 
+   terminated. This same primetable can be found in SSH and PGP except that 
+   SSH don't have prime 2 in the table. This sort of prime table is easily 
+   created, for example, using sieve of Erastosthenes.
+   
+   Just to include; if somebody is interested about Erastosthenes. Creating a 
+   small prime table using sieve of Erastosthenes would go like this: Write 
+   down a list of integers in range of 2 to n. Here in example n = 20.
+   
+   2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+
+   Then mark all multiples of 2 (Note: 2 is a prime number):
+
+   2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+       x   x   x    x     x     x     x     x     x
+
+   Move to the next unmarked number, 3, then mark all multiples of 3.
+
+   2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+       x   x   x x  x     x     x  x  x     x     x
+
+   And continue doing this, marking all multiples of the next unmarked
+   number until there are now new unmarked numbers. And there you have a 
+   prime table. So in this example, primes between 2 - 20 are:
+   
+   2 3 5 7 11 13 17 19
+
+*/
+
+static unsigned int primetable[] =
+{
+  2, 3, 5, 7, 11, 13, 17, 19,
+  23, 29, 31, 37, 41, 43, 47, 53,
+  59, 61, 67, 71, 73, 79, 83, 89,
+  97, 101, 103, 107, 109, 113, 127, 131,
+  137, 139, 149, 151, 157, 163, 167, 173,
+  179, 181, 191, 193, 197, 199, 211, 223,
+  227, 229, 233, 239, 241, 251, 257, 263,
+  269, 271, 277, 281, 283, 293, 307, 311,
+  313, 317, 331, 337, 347, 349, 353, 359,
+  367, 373, 379, 383, 389, 397, 401, 409,
+  419, 421, 431, 433, 439, 443, 449, 457,
+  461, 463, 467, 479, 487, 491, 499, 503,
+  509, 521, 523, 541, 547, 557, 563, 569,
+  571, 577, 587, 593, 599, 601, 607, 613,
+  617, 619, 631, 641, 643, 647, 653, 659,
+  661, 673, 677, 683, 691, 701, 709, 719,
+  727, 733, 739, 743, 751, 757, 761, 769,
+  773, 787, 797, 809, 811, 821, 823, 827,
+  829, 839, 853, 857, 859, 863, 877, 881,
+  883, 887, 907, 911, 919, 929, 937, 941,
+  947, 953, 967, 971, 977, 983, 991, 997,
+  1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049,
+  1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
+  1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
+  1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
+  1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283,
+  1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321,
+  1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423,
+  1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459,
+  1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
+  1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571,
+  1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619,
+  1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
+  1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747,
+  1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
+  1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
+  1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
+  1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003,
+  2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069,
+  2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
+  2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203,
+  2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267,
+  2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311,
+  2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377,
+  2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
+  2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503,
+  2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579,
+  2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657,
+  2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
+  2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
+  2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801,
+  2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861,
+  2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939,
+  2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011,
+  3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
+  3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167,
+  3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221,
+  3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301,
+  3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347,
+  3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
+  3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491,
+  3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541,
+  3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
+  3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671,
+  3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727,
+  3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797,
+  3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863,
+  3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923,
+  3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003,
+  4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057,
+  4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129,
+  4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211,
+  4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259,
+  4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337,
+  4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
+  4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481,
+  4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547,
+  4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621,
+  4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673,
+  4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751,
+  4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813,
+  4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909,
+  4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967,
+  4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011,
+  5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087,
+  5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167,
+  5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233,
+  5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309,
+  5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399,
+  5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
+  5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507,
+  5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573,
+  5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653,
+  5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711,
+  5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791,
+  5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849,
+  5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897,
+  5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007,
+  6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073,
+  6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133,
+  6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211,
+  6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271,
+  6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329,
+  6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379,
+  6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
+  6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563,
+  6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637,
+  6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701,
+  6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779,
+  6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
+  6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907,
+  6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971,
+  6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027,
+  7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121,
+  7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207,
+  7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253,
+  7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349,
+  7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457,
+  7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517,
+  7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561,
+  7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621,
+  7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691,
+  7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757,
+  7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853,
+  7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,
+  7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009,
+  8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087,
+  8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161,
+  8167, 8171, 8179, 8191, 0
+};
+
+
+/* Find appropriate prime. It generates a number by taking random bytes. 
+   It then tests the number that it's not divisible by any of the small 
+   primes and then it performs Fermat's prime test. I thank Rieks Joosten 
+   (r.joosten@pijnenburg.nl) for such a good help with prime tests. 
+
+   If argument verbose is TRUE this will display some status information
+   about the progress of generation. */
+
+int silc_math_gen_prime(SilcInt *prime, unsigned int bits, int verbose)
+{
+  unsigned char *numbuf;
+  unsigned int i, b, k;
+  unsigned int *spmods;
+  SilcInt r, base, tmp, tmp2, oprime;
+
+  /* XXX */
+  assert(primegen_rng != NULL);
+
+  silc_mp_init(&r);
+  silc_mp_init_set_ui(&base, 2);
+  silc_mp_init(&tmp);
+  silc_mp_init(&tmp2);
+  silc_mp_init(&oprime);
+
+  SILC_LOG_DEBUG(("Generating new prime"));
+
+  /* Get random number */
+  numbuf = silc_rng_get_rn_string(primegen_rng, (bits / 8));
+  if (!numbuf)
+    return FALSE;
+
+  /* Convert into MP and set the size */
+  silc_mp_set_str(prime, numbuf, 16);
+  silc_mp_mod_2exp(prime, prime, bits);
+
+  /* Empty buffer */
+  memset(numbuf, 0, (bits / 8));
+  silc_free(numbuf);
+
+  /* Number could be even number, so we'll make it odd. */
+  silc_mp_set_ui(&tmp, 1);
+  silc_mp_ior(prime, prime, &tmp);             /* OR operator */
+
+  /* Init modulo table with the prime candidate and the primes
+     in the primetable. */
+  spmods = silc_malloc(sizeof(primetable) * sizeof(unsigned int));
+  for (i = 0; primetable[i] != 0; i++) {
+    silc_mp_mod_ui(&tmp, prime, primetable[i]);
+    spmods[i] = silc_mp_get_ui(&tmp);
+  }
+
+  /* k is added by 2, this way we skip all even numbers (prime is odd). */
+  silc_mp_set(&oprime, prime);
+  for (k = 0;; k += 2) {
+    silc_mp_add_ui(&oprime, prime, k);
+    
+    /* See if the prime has a divisor in primetable[].
+     * If it has then it's a composite. We add k to the
+     * original modulo value, k is added by 2 on every roll.
+     * This way we don't have to re-init the whole table if
+     * the number is composite. 
+     */
+    for (b = 0; b < i; b++) {
+      silc_mp_set_ui(&tmp2, spmods[b]);
+      silc_mp_add_ui(&tmp2, &tmp2, k);
+      silc_mp_mod_ui(&tmp, &tmp2, primetable[b]);
+      
+      /* If mod is 0, the number is composite */
+      if (silc_mp_cmp_ui(&tmp, 0) == 0)
+       break;
+    }
+    if (b < i)
+      continue;
+    
+    /* Passed the quick test. */
+    
+    /* Does the prime pass the Fermat's prime test.
+     * r = 2 ^ p mod p, if r == 2, then p is probably a prime. 
+     */
+    silc_mp_powm(&r, &base, &oprime, &oprime);
+    if (silc_mp_cmp_ui(&r, 2) != 0) {
+      if (verbose) {
+       printf(".");
+       fflush(stdout);
+      }
+      continue;
+    }
+    
+    /* Passed the Fermat's test. And I don't think
+     * we have to do more tests. If anyone wants to do more
+     * tests, MP library has probability of prime test:
+     *
+     * if (silc_mp_probab_prime_p(prime, 25))
+     *     break;                          found a probable prime 
+     *
+     * However, this is very slow.
+     */
+    /* XXX: this could be done if some argument, say strict_primes, is
+       TRUE when we are willing to spend more time on the prime test and
+       to get, perhaps, better primes. */
+    silc_mp_set(prime, &oprime);
+    break;
+  }
+
+  silc_free(spmods);
+  silc_mp_clear(&r);
+  silc_mp_clear(&base);
+  silc_mp_clear(&tmp);
+  silc_mp_clear(&tmp2);
+  silc_mp_clear(&oprime);
+
+  return TRUE;
+}
+
+/* Performs primality testings for given number. Returns TRUE if the 
+   number is probably a prime. */
+
+int silc_math_prime_test(SilcInt *p)
+{
+  SilcInt r, base, tmp;
+  int i, ret = 0;
+  
+  silc_mp_init(&r);
+  silc_mp_init(&tmp);
+  silc_mp_init_set_ui(&base, 2);
+  
+  SILC_LOG_DEBUG(("Testing probability of prime"));
+
+  /* See if the number is divisible by any of the
+     small primes in primetable[]. */
+  for (i = 0; primetable[i] != 0; i++) {
+    silc_mp_mod_ui(&tmp, p, primetable[i]);
+    
+    /* If mod is 0, the number is composite */
+    if (silc_mp_cmp_ui(&tmp, 0) == 0)
+      ret = -1;
+  }
+  
+  /* Does the prime pass the Fermat's prime test.
+   * r = 2 ^ p mod p, if r == 2, then p is probably a prime.
+   */
+  silc_mp_powm(&r, &base, p, p);
+  if (silc_mp_cmp_ui(&r, 2) != 0)
+    ret = -1;
+
+  silc_mp_clear(&r);
+  silc_mp_clear(&tmp);
+  silc_mp_clear(&base);
+  
+  if (ret)
+    return FALSE;
+
+  /* Number is probably a prime */
+  return TRUE;
+}
+
+/* XXX This must temporary solution!! */
+/* Initializes the random pool used to generated primes */
+
+void silc_math_primegen_init()
+{
+  SILC_LOG_DEBUG(("Start"));
+
+  if (primegen_rng == NULL) {
+    primegen_rng = silc_rng_alloc();
+    silc_rng_init(primegen_rng);
+  }
+}
+
+/* XXX This must temporary solution!! */
+/* Uninitializes random pool */
+
+void silc_math_primegen_uninit()
+{
+  silc_rng_free(primegen_rng);
+}
diff --git a/lib/silcmath/silcprimegen.h b/lib/silcmath/silcprimegen.h
new file mode 100644 (file)
index 0000000..d34ba67
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+
+  silcprimegen.h
+  
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPRIMEGEN_H
+#define SILCPRIMEGEN_H
+
+int silc_math_gen_prime(SilcInt *prime, unsigned int bits, int verbose);
+int silc_math_prime_test(SilcInt *p);
+void silc_math_primegen_init();
+void silc_math_primegen_uninit();
+
+#endif
diff --git a/lib/silcsim/Makefile.am b/lib/silcsim/Makefile.am
new file mode 100644 (file)
index 0000000..dc920e8
--- /dev/null
@@ -0,0 +1,75 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilcsim.a
+
+libsilcsim_a_SOURCES = \
+       silcsim.c \
+       silcsimutil.c
+
+SIM_CFLAGS = -fPIC -shared
+
+SIM_MODULES_DIR = modules
+
+SUBDIRS = modules
+
+#
+# SILC Ciphers to be compiled as modules
+#
+SIM_CIPHER_OBJS = \
+        none.o \
+        blowfish.o \
+        rc5.o \
+        rc6.o \
+        mars.o \
+        rijndael.o \
+        rsa.o \
+        twofish.o
+
+#
+# SILC Hash Functions to be compiled as modules
+#
+SIM_HASH_OBJS = \
+       md5.o \
+       sha1.o
+
+all: $(SIM_CIPHER_OBJS) $(SIM_HASH_OBJS)
+
+$(SIM_CIPHER_OBJS): ../silccrypt/libsilccrypt.a
+       rm -rf $*.c $*.o
+       $(LN_S) $(srcdir)/../silccrypt/$*.c
+       $(COMPILE) $(SIM_CFLAGS) $*.c -o $(SIM_MODULES_DIR)/$*.sim.so
+       $(LN_S) $(srcdir)/$(SIM_MODULES_DIR)/$*.sim.so $*.o
+       rm -rf $*.c
+
+$(SIM_HASH_OBJS): ../silccrypt/libsilccrypt.a
+       rm -rf $*.c $*.o
+       $(LN_S) $(srcdir)/../silccrypt/$*.c
+       $(COMPILE) $(SIM_CFLAGS) $*.c -o $(SIM_MODULES_DIR)/$*.sim.so
+       $(LN_S) $(srcdir)/$(SIM_MODULES_DIR)/$*.sim.so $*.o
+       rm -rf $*.c
+
+CLEANFILES = $(SIM_MODULES_DIR)/*.sim.so
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
+       -I../silccore -I../.. -I../../includes \
+       -I../silcmath/gmp-3.0.1
diff --git a/lib/silcsim/modules/Makefile.am b/lib/silcsim/modules/Makefile.am
new file mode 100644 (file)
index 0000000..f287498
--- /dev/null
@@ -0,0 +1,22 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+all:
+       -cd ..
diff --git a/lib/silcsim/modules/Makefile.in b/lib/silcsim/modules/Makefile.in
new file mode 100644 (file)
index 0000000..1fa3227
--- /dev/null
@@ -0,0 +1,184 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../../includes/silcdefs.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/silcsim/modules/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib/silcsim/modules
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+all:
+       -cd ..
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/silcsim/silcsim.c b/lib/silcsim/silcsim.c
new file mode 100644 (file)
index 0000000..5afc108
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+
+  silcsim.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+  These routines implement the SILC Module (SIM) support. SIM's are
+  dynamically run-time loaded shared objects that can implement some
+  routines SILC can use to extend its features. Currently all
+  SILC Crypto modules are implemented as SIM's. They all implement
+  the SILC Crypto API and can be loaded run-time into the SILC and
+  used when needed. 
+
+  Basically any SILC API can be implemented as SIM, however, currently
+  only SILC Crypto modules (ciphers and hash functions (PKCS are not
+  supported)) are supported.
+
+  This implementation expects that no SILC specific symbols needs to
+  be exported into the SIM's. This means that SIM's cannot directly
+  use SILC specific symbols or definitions. This feature can be
+  supported with SIM's but currently (with Crypto modules) this is
+  not needed. 
+
+  NOTE: These routines maybe highly system dependant thus I can expect 
+  some heavy #ifdef's here. However, I'm more happy to see some macro 
+  SIM API and restrict the #ifdef's to silcsim.h file.
+
+*/
+
+#include "silcincludes.h"
+
+#ifdef SILC_SIM                        /* SIM upport enabled */
+
+/* Allocates new SIM context. This is later send to all SIM 
+   routines. */
+
+SilcSimContext *silc_sim_alloc()
+{
+  SilcSimContext *new;
+
+  SILC_LOG_DEBUG(("Initializing new SIM context"));
+
+  new = silc_calloc(1, sizeof(*new));
+  if (!new) {
+    SILC_LOG_ERROR(("Could not allocate new SIM context"));
+    return NULL;
+  }
+
+  new->handle = NULL;
+  new->type = SILC_SIM_NONE;
+  new->libname = NULL;
+  new->flags = SILC_SIM_FLAGS;
+
+  return new;
+}
+
+/* Free's SIM context. SIM must be closed with silc_sim_close before
+   calling this. */
+
+void silc_sim_free(SilcSimContext *sim)
+{
+  assert(sim->handle == NULL);
+
+  if (sim)
+    silc_free(sim);
+}
+
+/* Loads SIM into the SILC system. */
+
+int silc_sim_load(SilcSimContext *sim)
+{
+  assert(sim != NULL);
+
+  SILC_LOG_DEBUG(("Loading SIM '%s'", sim->libname));
+
+  /* Load the library */
+  sim->handle = dlopen(sim->libname, sim->flags);
+  if (!sim->handle) {
+    SILC_LOG_ERROR(("Error loading SIM: %s", silc_sim_error()));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Closes SIM. This is called when execution of program is ending or
+   one explicitly wants to remove this SIM from SILC. */
+
+int silc_sim_close(SilcSimContext *sim)
+{
+  assert(sim != NULL);
+
+  SILC_LOG_DEBUG(("Closing SIM '%s'", sim->libname));
+
+  /* Close the library */
+  dlclose(sim->handle);
+
+  return TRUE;
+}
+
+/* Returns error string if error has occured while processing SIM's. */
+
+char *silc_sim_error()
+{
+  return dlerror();
+}
+
+/* Returns opaque pointer for a symbol in SIM. Caller must know the
+   symbols they want to get from SIM and use the returned pointer to
+   what ever it is intended. */
+
+void *silc_sim_getsym(SilcSimContext *sim, const char *symbol)
+{
+  assert(sim != NULL);
+
+  SILC_LOG_DEBUG(("Getting symbol '%s' from SIM", symbol));
+
+  return dlsym(sim->handle, symbol);
+}
+
+#endif /* SILC_SIM */
diff --git a/lib/silcsim/silcsim.h b/lib/silcsim/silcsim.h
new file mode 100644 (file)
index 0000000..99ba428
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+
+  silcsim.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSIM_H
+#define SILCSIM_H
+
+/* All SIM types. New types maybe freely added. */
+typedef enum {
+  SILC_SIM_NONE = 0,
+  SILC_SIM_CIPHER,
+  SILC_SIM_HASH,
+} SilcSimType;
+
+/* 
+   SILC Module (SIM) Context.
+
+   This context holds relevant information about the SIM loaded into
+   the system. Following short description of the fields.
+
+   void *handle
+
+       Pointer to the SIM. This is used to get the symbols out of
+       the SIM. This is initalized by system specific routine.
+
+   SilcSimType type
+
+       Type of the SIM.
+
+   char *libname;
+
+       Filename and path to the SIM library file.
+
+   int flags
+
+       Flags used with the SIM. These are system specific flags.
+       See below for more information.
+
+*/
+typedef struct {
+  void *handle;
+  SilcSimType type;
+  char *libname;
+  int flags;
+} SilcSimContext;
+
+/* Flags used to retrieve the symbols from the library file. Default
+   is that the symbols are resolved as they are loaded. However, if
+   system doesn't support this we have no other choice but to do it lazy
+   thus experience some overhead when using the symbol first time. */
+#define SILC_SIM_FLAGS RTLD_NOW
+/*#define SILC_SIM_FLAGS RTLD_LAZY */
+
+/* Prototypes */
+SilcSimContext *silc_sim_alloc();
+void silc_sim_free(SilcSimContext *sim);
+int silc_sim_load(SilcSimContext *sim);
+int silc_sim_close(SilcSimContext *sim);
+char *silc_sim_error();
+void *silc_sim_getsym(SilcSimContext *sim, const char *symbol);
+
+#endif
diff --git a/lib/silcsim/silcsimutil.c b/lib/silcsim/silcsimutil.c
new file mode 100644 (file)
index 0000000..a47b68a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+
+  silcsimutil.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+#ifdef SILC_SIM                        /* SIM support enabled */
+
+/* This puts two arguments together and returns a new allocated string.
+   This is used to produce the function names that are then get from
+   SIM's. */
+
+char *silc_sim_symname(char *symbol, char *function)
+{
+  char *ret;
+  int len1, len2, len3;
+
+  len1 = strlen(symbol);
+  len2 = strlen(function);
+  len3 = strlen(SILC_SIM_SYMBOL_PREFIX);
+  ret = silc_calloc(len1 + len2 + len3 + 2 + 1, sizeof(char));
+
+  strncpy(ret, SILC_SIM_SYMBOL_PREFIX, len3);
+  strncat(ret, "_", 1);
+  strncat(ret, symbol, len1);
+  strncat(ret, "_", 1);
+  strncat(ret, function, len2);
+
+  return ret;
+}
+
+#endif /* SILC_SIM */
diff --git a/lib/silcsim/silcsimutil.h b/lib/silcsim/silcsimutil.h
new file mode 100644 (file)
index 0000000..70c4be3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+
+  silcsimutil.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSIMUTIL_H
+#define SILCSIMUTIL_H
+
+#define SILC_SIM_SYMBOL_PREFIX "silc"
+
+/* Prototypes */
+
+char *silc_sim_symname(char *symbol, char *function);
+
+#endif
diff --git a/lib/silcske/Makefile.am b/lib/silcske/Makefile.am
new file mode 100644 (file)
index 0000000..dcc56ed
--- /dev/null
@@ -0,0 +1,32 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilcske.a
+
+libsilcske_a_SOURCES = \
+       silcske.c \
+       payload.c \
+        groups.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silccore \
+       -I../silcsim -I../silcmath -I../.. -I../../includes \
+        -I../silcmath/gmp-3.0.1
diff --git a/lib/silcske/groups.c b/lib/silcske/groups.c
new file mode 100644 (file)
index 0000000..647064c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+
+  groups.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "groups_internal.h"
+
+/* Fixed and public Diffie Hellman Groups defined by the SKE
+   protocol. These are equivalent to the OAKLEY Key Determination
+   protocol groups (taken from RFC 2412). */
+const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[] = 
+{
+  /* 1024 bits modulus (Mandatory group) */
+  { 1, "diffie-hellman-group1",
+    "0x"
+    "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
+    "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
+    "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
+    "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
+    "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381"
+    "FFFFFFFF FFFFFFFF",
+    "0x"
+    "7FFFFFFF FFFFFFFF E487ED51 10B4611A 62633145 C06E0E68"
+    "94812704 4533E63A 0105DF53 1D89CD91 28A5043C C71A026E"
+    "F7CA8CD9 E69D218D 98158536 F92F8A1B A7F09AB6 B6A8E122"
+    "F242DABB 312F3F63 7A262174 D31BF6B5 85FFAE5B 7A035BF6"
+    "F71C35FD AD44CFD2 D74F9208 BE258FF3 24943328 F67329C0"
+    "FFFFFFFF FFFFFFFF",
+    "0x2" },
+
+  /* 1536 bits modulus (Optional group) */
+  { 2, "diffie-hellman-group2",
+    "0x"
+    "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
+    "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
+    "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
+    "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
+    "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D"
+    "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F"
+    "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D"
+    "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF",
+    "0x"
+    "7FFFFFFF FFFFFFFF E487ED51 10B4611A 62633145 C06E0E68"
+    "94812704 4533E63A 0105DF53 1D89CD91 28A5043C C71A026E"
+    "F7CA8CD9 E69D218D 98158536 F92F8A1B A7F09AB6 B6A8E122"
+    "F242DABB 312F3F63 7A262174 D31BF6B5 85FFAE5B 7A035BF6"
+    "F71C35FD AD44CFD2 D74F9208 BE258FF3 24943328 F6722D9E"
+    "E1003E5C 50B1DF82 CC6D241B 0E2AE9CD 348B1FD4 7E9267AF"
+    "C1B2AE91 EE51D6CB 0E3179AB 1042A95D CF6A9483 B84B4B36"
+    "B3861AA7 255E4C02 78BA3604 6511B993 FFFFFFFF FFFFFFFF",
+    "0x2" },
+
+  { 0, NULL, NULL, NULL }
+};
+
+/* Returns Diffie Hellman group by group number */
+
+SilcSKEStatus silc_ske_get_group_by_number(int number,
+                                          SilcSKEDiffieHellmanGroup *ret)
+{
+  int i;
+  SilcSKEDiffieHellmanGroup group;
+
+  for (i = 0; silc_ske_groups[i].name; i++) {
+    if (silc_ske_groups[i].number == number)
+      break;
+  }
+
+  if (silc_ske_groups[i].name == NULL)
+    return SILC_SKE_STATUS_UNKNOWN_GROUP;
+
+  /* Return the group */
+  if (ret) {
+    group = silc_calloc(1, sizeof(*group));
+    group->number = number;
+    group->name = silc_ske_groups[i].name;
+    silc_mp_init(&group->group);
+    silc_mp_init(&group->group_order);
+    silc_mp_init(&group->generator);
+    silc_mp_set_str(&group->group, silc_ske_groups[i].group, 0);
+    silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 0);
+    silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 0);
+    
+    *ret = group;
+  }
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Returns Diffie Hellman group by name */
+
+SilcSKEStatus silc_ske_get_group_by_name(const char *name,
+                                        SilcSKEDiffieHellmanGroup *ret)
+{
+  int i;
+  SilcSKEDiffieHellmanGroup group;
+
+  for (i = 0; silc_ske_groups[i].name; i++) {
+    if (!strcmp(silc_ske_groups[i].name, name))
+      break;
+  }
+
+  if (silc_ske_groups[i].name == NULL)
+    return SILC_SKE_STATUS_UNKNOWN_GROUP;
+
+  /* Return the group */
+  if (ret) {
+    group = silc_calloc(1, sizeof(*group));
+    group->number = silc_ske_groups[i].number;
+    group->name = silc_ske_groups[i].name;
+    silc_mp_init(&group->group);
+    silc_mp_init(&group->group_order);
+    silc_mp_init(&group->generator);
+    silc_mp_set_str(&group->group, silc_ske_groups[i].group, 0);
+    silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 0);
+    silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 0);
+    
+    *ret = group;
+  }
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Returns comma separated list of supported groups */
+
+char *silc_ske_get_supported_groups()
+{
+  char *list = NULL;
+  int i, len;
+
+  len = 0;
+  for (i = 0; silc_ske_groups[i].name; i++) {
+    len += strlen(silc_ske_groups[i].name);
+    list = silc_realloc(list, len + 1);
+
+    memcpy(list + (len - strlen(silc_ske_groups[i].name)), 
+          silc_ske_groups[i].name, strlen(silc_ske_groups[i].name));
+    memcpy(list + len, ",", 1);
+    len++;
+  }
+
+  list[len - 1] = 0;
+
+  return list;
+}
diff --git a/lib/silcske/groups.h b/lib/silcske/groups.h
new file mode 100644 (file)
index 0000000..29e33be
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+
+  groups.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef GROUPS_H
+#define GROUPS_H
+
+#include "silcske_status.h"
+#include "groups_internal.h"
+
+/* Forward declaration */
+typedef struct SilcSKEDiffieHellmanGroupStruct *SilcSKEDiffieHellmanGroup;
+
+/* List of defined groups. */
+extern const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[];
+
+/* Prototypes */
+SilcSKEStatus silc_ske_get_group_by_number(int number,
+                                          SilcSKEDiffieHellmanGroup *ret);
+SilcSKEStatus silc_ske_get_group_by_name(const char *name,
+                                        SilcSKEDiffieHellmanGroup *ret);
+char *silc_ske_get_supported_groups();
+
+#endif
diff --git a/lib/silcske/groups_internal.h b/lib/silcske/groups_internal.h
new file mode 100644 (file)
index 0000000..015c125
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+  groups_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef GROUPS_INTERNAL_H
+#define GROUPS_INTERNAL_H
+
+/* Diffie Hellman Group. Defines the group name, prime, largest prime 
+   factor (group order) and generator. */
+struct SilcSKEDiffieHellmanGroupDefStruct {
+  int number;
+  char *name;
+  char *group;
+  char *group_order;
+  char *generator;
+};
+
+struct SilcSKEDiffieHellmanGroupStruct {
+  int number;
+  char *name;
+  SilcInt group;
+  SilcInt group_order;
+  SilcInt generator;
+};
+
+#endif
diff --git a/lib/silcske/payload.c b/lib/silcske/payload.c
new file mode 100644 (file)
index 0000000..07cebf5
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+
+  payload.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* XXX TODO: This is not optimized version and should be optimized! 
+   Use *_ALLOC buffer formatting in payload decodings! */
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "payload_internal.h"
+
+/* Temporary buffer used in payload decoding */
+unsigned char buf[16384];
+
+/* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
+   to the other end. */
+
+SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
+                                           SilcSKEStartPayload *payload,
+                                           SilcBuffer *return_buffer)
+{
+  SilcBuffer buf;
+
+  SILC_LOG_DEBUG(("Encoding KE Start Payload"));
+
+  if (!payload)
+    return SILC_SKE_STATUS_ERROR;
+
+  /* Allocate channel payload buffer. */
+  buf = silc_buffer_alloc(payload->len);
+  if (!buf) {
+    SILC_LOG_ERROR(("Could not allocate encode buffer"));
+    return SILC_SKE_STATUS_ERROR;
+  }
+
+  silc_buffer_pull_tail(buf, payload->len);
+
+  /* Encode the payload */
+  silc_buffer_format(buf,
+                    SILC_STR_UI_CHAR(0),        /* RESERVED field */
+                    SILC_STR_UI_CHAR(payload->flags),
+                    SILC_STR_UI_SHORT(payload->len),
+                    SILC_STR_UI_XNSTRING(payload->cookie, 
+                                         payload->cookie_len),
+                    SILC_STR_UI_SHORT(payload->ke_grp_len),
+                    SILC_STR_UI_XNSTRING(payload->ke_grp_list,
+                                         payload->ke_grp_len),
+                    SILC_STR_UI_SHORT(payload->pkcs_alg_len),
+                    SILC_STR_UI_XNSTRING(payload->pkcs_alg_list,
+                                         payload->pkcs_alg_len),
+                    SILC_STR_UI_SHORT(payload->enc_alg_len),
+                    SILC_STR_UI_XNSTRING(payload->enc_alg_list,
+                                         payload->enc_alg_len),
+                    SILC_STR_UI_SHORT(payload->hash_alg_len),
+                    SILC_STR_UI_XNSTRING(payload->hash_alg_list,
+                                         payload->hash_alg_len),
+                    SILC_STR_UI_SHORT(payload->comp_alg_len),
+                    SILC_STR_UI_XNSTRING(payload->comp_alg_list,
+                                         payload->comp_alg_len),
+                    SILC_STR_END);
+
+  /* Return the encoded buffer */
+  *return_buffer = buf;
+
+  SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len);
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Parses the Key Exchange Start Payload. Parsed data is returned
+   to allocated payload structure. */
+
+SilcSKEStatus 
+silc_ske_payload_start_decode(SilcSKE ske,
+                             SilcBuffer buffer,
+                             SilcSKEStartPayload **return_payload)
+{
+  SilcSKEStartPayload *payload;
+  SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+  unsigned char tmp;
+  int len, len2;
+
+  SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload"));
+
+  SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len);
+
+  payload = silc_calloc(1, sizeof(*payload));
+  memset(buf, 0, sizeof(buf));
+
+  /* Parse the entire payload */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_CHAR(&tmp),     /* RESERVED Field */
+                      SILC_STR_UI_CHAR(&payload->flags),
+                      SILC_STR_UI_SHORT(&payload->len),
+                      SILC_STR_UI_XNSTRING(&buf, SILC_SKE_COOKIE_LEN),
+                      SILC_STR_UI_SHORT(&payload->ke_grp_len),
+                      SILC_STR_END);
+
+  if (tmp != 0) {
+    SILC_LOG_DEBUG(("Bad reserved field"));
+    status = SILC_SKE_STATUS_BAD_RESERVED_FIELD;
+    goto err;
+  }
+
+  if (payload->len != buffer->len) {
+    SILC_LOG_DEBUG(("Bad payload length"));
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  if (payload->ke_grp_len < 1) {
+    SILC_LOG_DEBUG(("Bad payload length"));
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  len2 = len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2;
+  silc_buffer_pull(buffer, len);
+
+  /* Copy cookie from payload */
+  payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, 
+                               sizeof(unsigned char));
+  payload->cookie_len = SILC_SKE_COOKIE_LEN;
+  memcpy(payload->cookie, buf, SILC_SKE_COOKIE_LEN);
+  memset(buf, 0, sizeof(buf));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, payload->ke_grp_len),
+                      SILC_STR_UI_SHORT(&payload->pkcs_alg_len),
+                      SILC_STR_END);
+
+  if (payload->pkcs_alg_len < 1) {
+    SILC_LOG_DEBUG(("Bad payload length"));
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  len2 += len = payload->ke_grp_len + 2;
+  silc_buffer_pull(buffer, len);
+
+  /* Copy KE groups from payload */
+  payload->ke_grp_list = silc_calloc(payload->ke_grp_len + 1, 
+                                    sizeof(unsigned char));
+  memcpy(payload->ke_grp_list, buf, payload->ke_grp_len);
+  memset(buf, 0, sizeof(buf));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, payload->pkcs_alg_len),
+                      SILC_STR_UI_SHORT(&payload->enc_alg_len),
+                      SILC_STR_END);
+
+  if (payload->enc_alg_len < 1) {
+    SILC_LOG_DEBUG(("Bad payload length"));
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  len2 += len = payload->pkcs_alg_len + 2;
+  silc_buffer_pull(buffer, len);
+
+  /* Copy PKCS algs from payload */
+  payload->pkcs_alg_list = silc_calloc(payload->pkcs_alg_len + 1, 
+                                      sizeof(unsigned char));
+  memcpy(payload->pkcs_alg_list, buf, payload->pkcs_alg_len);
+  memset(buf, 0, sizeof(buf));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, payload->enc_alg_len),
+                      SILC_STR_UI_SHORT(&payload->hash_alg_len),
+                      SILC_STR_END);
+
+  if (payload->hash_alg_len < 1) {
+    SILC_LOG_DEBUG(("Bad payload length"));
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  len2 += len = payload->enc_alg_len + 2;
+  silc_buffer_pull(buffer, len);
+
+  /* Copy encryption algs from payload */
+  payload->enc_alg_list = silc_calloc(payload->enc_alg_len + 1, 
+                                     sizeof(unsigned char));
+  memcpy(payload->enc_alg_list, buf, payload->enc_alg_len);
+  memset(buf, 0, sizeof(buf));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, payload->hash_alg_len),
+                      SILC_STR_UI_SHORT(&payload->comp_alg_len),
+                      SILC_STR_END);
+
+  len2 += len = payload->hash_alg_len + 2;
+  silc_buffer_pull(buffer, len);
+
+  /* Copy hash algs from payload */
+  payload->hash_alg_list = silc_calloc(payload->hash_alg_len + 1, 
+                                      sizeof(unsigned char));
+  memcpy(payload->hash_alg_list, buf, payload->hash_alg_len);
+  memset(buf, 0, sizeof(buf));
+
+  if (payload->comp_alg_len) {
+    silc_buffer_unformat(buffer,
+                        SILC_STR_UI_XNSTRING(&buf, payload->comp_alg_len),
+                        SILC_STR_END);
+
+    /* Copy compression algs from payload */
+    payload->comp_alg_list = silc_calloc(payload->comp_alg_len + 1, 
+                                        sizeof(unsigned char));
+    memcpy(payload->comp_alg_list, buf, payload->comp_alg_len);
+    memset(buf, 0, sizeof(buf));
+  }
+
+  silc_buffer_push(buffer, len2);
+
+  /* Return the payload */
+  *return_payload = payload;
+
+  return SILC_SKE_STATUS_OK;
+
+ err:
+  silc_ske_payload_start_free(payload);
+
+  return status;
+}
+
+/* Free's Start Payload */
+
+void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
+{
+  if (payload) {
+    if (payload->cookie)
+      silc_free(payload->cookie);
+    if (payload->ke_grp_list)
+      silc_free(payload->ke_grp_list);
+    if (payload->pkcs_alg_list)
+      silc_free(payload->pkcs_alg_list);
+    if (payload->enc_alg_list)
+      silc_free(payload->enc_alg_list);
+    if (payload->hash_alg_list)
+      silc_free(payload->hash_alg_list);
+    if (payload->comp_alg_list)
+      silc_free(payload->comp_alg_list);
+    silc_free(payload);
+  }
+}
+
+/* Encodes Key Exchange 1 Payload into a SILC Buffer to be sent
+   to the other end. */
+
+SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
+                                         SilcSKEOnePayload *payload,
+                                         SilcBuffer *return_buffer)
+{
+  SilcBuffer buf;
+  unsigned char *e_str;
+  unsigned short e_len;
+
+  SILC_LOG_DEBUG(("Encoding KE 1 Payload"));
+
+  if (!payload)
+    return SILC_SKE_STATUS_ERROR;
+
+  /* Encode the integer into HEX string */
+  e_len = silc_mp_sizeinbase(&payload->e, 16);
+  e_str = silc_calloc(e_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(e_str, 16, &payload->e);
+
+  /* Allocate channel payload buffer. The length of the buffer
+     is 2 + e. */
+  buf = silc_buffer_alloc(e_len + 2);
+  if (!buf) {
+    SILC_LOG_ERROR(("Could not allocate encode buffer"));
+    return SILC_SKE_STATUS_ERROR;
+  }
+
+  silc_buffer_pull_tail(buf, e_len + 2);
+
+  /* Encode the payload */
+  silc_buffer_format(buf, 
+                    SILC_STR_UI_SHORT(e_len + 2),
+                    SILC_STR_UI_XNSTRING(e_str, e_len),
+                    SILC_STR_END);
+
+  /* Return encoded buffer */
+  *return_buffer = buf;
+
+  memset(e_str, 'F', e_len);
+  silc_free(e_str);
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Parses the Key Exchange 1 Payload. Parsed data is returned
+   to allocated payload structure. */
+
+SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
+                                         SilcBuffer buffer,
+                                         SilcSKEOnePayload **return_payload)
+{
+  SilcSKEOnePayload *payload;
+  SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+  unsigned short e_len;
+
+  SILC_LOG_DEBUG(("Decoding Key Exchange 1 Payload"));
+
+  SILC_LOG_HEXDUMP(("KE 1 Payload"), buffer->data, buffer->len);
+
+  payload = silc_calloc(1, sizeof(*payload));
+
+  memset(buf, 0, sizeof(buf));
+
+  /* Parse the payload */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&e_len),
+                      SILC_STR_END);
+                      
+  if (e_len < 1) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  if (e_len != buffer->len) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  /* Length includes the length field length as well. Remove it. */
+  e_len -= 2;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(NULL),
+                      SILC_STR_UI_XNSTRING(&buf, e_len),
+                      SILC_STR_END);
+
+  /* Decode the HEX string to integer */
+  silc_mp_init(&payload->e);
+  silc_mp_set_str(&payload->e, buf, 16);
+  memset(buf, 0, sizeof(buf));
+
+  /* Return the payload */
+  *return_payload = payload;
+
+  return SILC_SKE_STATUS_OK;
+
+ err:
+  silc_free(payload);
+
+  return status;
+}
+
+/* Free's KE1 Payload */
+
+void silc_ske_payload_one_free(SilcSKEOnePayload *payload)
+{
+  if (payload) {
+    silc_mp_clear(&payload->e);
+    silc_free(payload);
+  }
+}
+
+/* Encodes Key Exchange 2 Payload into a SILC Buffer to be sent
+   to the other end. */
+
+SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
+                                         SilcSKETwoPayload *payload,
+                                         SilcBuffer *return_buffer)
+{
+  SilcBuffer buf;
+  unsigned char *f_str;
+  unsigned int f_len;
+  unsigned int len;
+
+  SILC_LOG_DEBUG(("Encoding KE 2 Payload"));
+
+  if (!payload)
+    return SILC_SKE_STATUS_ERROR;
+
+  /* Encode the integer into HEX string */
+  f_len = silc_mp_sizeinbase(&payload->f, 16);
+  f_str = silc_calloc(f_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(f_str, 16, &payload->f);
+
+  /* Allocate channel payload buffer. The length of the buffer
+     is 2 + 2 + public key + 2 + f + 2 + signature. */
+  len = payload->pk_len + 2 + 2 + f_len + 2 + payload->sign_len + 2;
+  buf = silc_buffer_alloc(len);
+  if (!buf) {
+    SILC_LOG_ERROR(("Could not allocate encode buffer"));
+    return SILC_SKE_STATUS_ERROR;
+  }
+
+  silc_buffer_pull_tail(buf, len);
+
+  /* Encode the payload */
+  silc_buffer_format(buf, 
+                    SILC_STR_UI_SHORT(payload->pk_len + 4),
+                    SILC_STR_UI_SHORT(payload->pk_type),
+                    SILC_STR_UI_XNSTRING(payload->pk_data, 
+                                         payload->pk_len),
+                    SILC_STR_UI_SHORT(f_len + 2),
+                    SILC_STR_UI_XNSTRING(f_str, f_len),
+                    SILC_STR_UI_SHORT(payload->sign_len + 2),
+                    SILC_STR_UI_XNSTRING(payload->sign_data, 
+                                         payload->sign_len),
+                    SILC_STR_END);
+
+  /* Return encoded buffer */
+  *return_buffer = buf;
+
+  memset(f_str, 'F', f_len);
+  silc_free(f_str);
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Parses the Key Exchange 2 Payload. Parsed data is returned
+   to allocated payload structure. */
+
+SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
+                                         SilcBuffer buffer,
+                                         SilcSKETwoPayload **return_payload)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+  SilcSKETwoPayload *payload;
+  unsigned short f_len;
+  unsigned int tot_len = 0, len2;
+
+  SILC_LOG_DEBUG(("Decoding Key Exchange 2 Payload"));
+
+  SILC_LOG_HEXDUMP(("KE 2 Payload"), buffer->data, buffer->len);
+
+  payload = silc_calloc(1, sizeof(*payload));
+  memset(buf, 0, sizeof(buf));
+
+  len2 = buffer->len;
+
+  /* Parse the payload */
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&payload->pk_len),
+                      SILC_STR_UI_SHORT(&payload->pk_type),
+                      SILC_STR_END);
+
+  if (payload->pk_len < 5) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  tot_len += payload->pk_len;
+
+  payload->pk_len -= 4;
+  silc_buffer_pull(buffer, 4);
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, payload->pk_len),
+                      SILC_STR_UI_SHORT(&f_len),
+                      SILC_STR_END);
+
+  if (f_len < 3) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  tot_len += f_len;
+
+  payload->pk_data = silc_calloc(payload->pk_len + 1, 
+                                sizeof(unsigned char));
+  memcpy(payload->pk_data, buf, payload->pk_len);
+  memset(buf, 0, sizeof(buf));
+
+  f_len -= 2;
+  silc_buffer_pull(buffer, payload->pk_len + 2);
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, f_len),
+                      SILC_STR_UI_SHORT(&payload->sign_len),
+                      SILC_STR_END);
+
+  if (payload->sign_len < 3) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+
+  tot_len += payload->sign_len;
+
+  if (tot_len != len2) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    goto err;
+  }
+  
+  /* Decode the HEX string to integer */
+  silc_mp_init(&payload->f);
+  silc_mp_set_str(&payload->f, buf, 16);
+  memset(buf, 0, sizeof(buf));
+
+  payload->sign_len -= 2;
+  silc_buffer_pull(buffer, f_len + 2);
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING(&buf, payload->sign_len),
+                      SILC_STR_END);
+
+  payload->sign_data = silc_calloc(payload->sign_len + 1, 
+                                sizeof(unsigned char));
+  memcpy(payload->sign_data, buf, payload->sign_len);
+  memset(buf, 0, sizeof(buf));
+
+  /* Return the payload */
+  *return_payload = payload;
+
+  return SILC_SKE_STATUS_OK;
+
+ err:
+  if (payload->pk_data)
+    silc_free(payload->pk_data);
+  if (payload->sign_data)
+    silc_free(payload->sign_data);
+  silc_free(payload);
+
+  return status;
+}
+
+/* Free's KE2 Payload */
+
+void silc_ske_payload_two_free(SilcSKETwoPayload *payload)
+{
+  if (payload) {
+    if (payload->pk_data)
+      silc_free(payload->pk_data);
+    if (payload->sign_data)
+      silc_free(payload->sign_data);
+    silc_mp_clear(&payload->f);
+    silc_free(payload);
+  }
+}
diff --git a/lib/silcske/payload.h b/lib/silcske/payload.h
new file mode 100644 (file)
index 0000000..fa88e41
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+
+  payload.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef PAYLOAD_H
+#define PAYLOAD_H
+
+#include "silcske_status.h"
+#include "payload_internal.h"
+
+/* Prototypes */
+SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
+                                           SilcSKEStartPayload *payload,
+                                           SilcBuffer *return_buffer);
+SilcSKEStatus 
+silc_ske_payload_start_decode(SilcSKE ske,
+                             SilcBuffer buffer,
+                             SilcSKEStartPayload **return_payload);
+void silc_ske_payload_start_free(SilcSKEStartPayload *payload);
+SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
+                                         SilcSKEOnePayload *payload,
+                                         SilcBuffer *return_buffer);
+SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
+                                         SilcBuffer buffer,
+                                         SilcSKEOnePayload **return_payload);
+void silc_ske_payload_one_free(SilcSKEOnePayload *payload);
+SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
+                                         SilcSKETwoPayload *payload,
+                                         SilcBuffer *return_buffer);
+SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
+                                         SilcBuffer buffer,
+                                         SilcSKETwoPayload **return_payload);
+void silc_ske_payload_two_free(SilcSKETwoPayload *payload);
+
+#endif
diff --git a/lib/silcske/payload_internal.h b/lib/silcske/payload_internal.h
new file mode 100644 (file)
index 0000000..f866f46
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+
+  payload_internal.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef PAYLOAD_INTERNAL_H
+#define PAYLOAD_INTERNAL_H
+
+/* SILC Key Exchange Start Payload */
+typedef struct {
+  unsigned char flags;
+  unsigned int len;
+
+  unsigned char *cookie;
+  unsigned short cookie_len;
+
+  unsigned short ke_grp_len;
+  unsigned char *ke_grp_list;
+
+  unsigned short pkcs_alg_len;
+  unsigned char *pkcs_alg_list;
+
+  unsigned short enc_alg_len;
+  unsigned char *enc_alg_list;
+  
+  unsigned short hash_alg_len;
+  unsigned char *hash_alg_list;
+
+  unsigned short comp_alg_len;
+  unsigned char *comp_alg_list;
+} SilcSKEStartPayload;
+
+/* SILC Key Exchange 1 Payload */
+typedef struct {
+  SilcInt e;
+} SilcSKEOnePayload;
+
+/* SILC Key Exchange 2 Payload */
+typedef struct {
+  unsigned short pk_len;
+  unsigned char *pk_data;
+  unsigned short pk_type;
+
+  SilcInt f;
+
+  unsigned short sign_len;
+  unsigned char *sign_data;
+} SilcSKETwoPayload;
+
+#endif
diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c
new file mode 100644 (file)
index 0000000..db3f24d
--- /dev/null
@@ -0,0 +1,1314 @@
+/*
+
+  silcske.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
+ *
+ *
+ */
+
+#include "silcincludes.h"
+#include "payload_internal.h"
+#include "groups_internal.h"
+
+/* Allocates new SKE object. */
+
+SilcSKE silc_ske_alloc()
+{
+  SilcSKE ske;
+
+  SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
+
+  ske = silc_calloc(1, sizeof(*ske));
+  if (!ske) {
+    SILC_LOG_ERROR(("Could not allocate new SKE object"));
+    return NULL;
+  }
+
+  return ske;
+}
+
+/* Free's SKE object. */
+
+void silc_ske_free(SilcSKE ske)
+{
+  SILC_LOG_DEBUG(("Freeing Key Exchange object"));
+
+  if (ske) {
+    /* Free start payload */
+    if (ske->start_payload)
+      silc_ske_payload_start_free(ske->start_payload);
+
+    /* Free KE1 payload */
+    if (ske->ke1_payload)
+      silc_ske_payload_one_free(ske->ke1_payload);
+
+    /* Free KE2 payload */
+    if (ske->ke2_payload)
+      silc_ske_payload_two_free(ske->ke2_payload);
+
+    /* Free rest */
+    if (ske->prop) {
+      if (ske->prop->group)
+       silc_free(ske->prop->group);
+      if (ske->prop->pkcs)
+       silc_pkcs_free(ske->prop->pkcs);
+      if (ske->prop->cipher)
+       silc_cipher_free(ske->prop->cipher);
+      if (ske->prop->hash)
+       silc_hash_free(ske->prop->hash);
+      silc_free(ske->prop);
+    }
+    if (ske->start_payload_copy)
+      silc_buffer_free(ske->start_payload_copy);
+    if (ske->pk)
+      silc_free(ske->pk);
+    silc_mp_clear(&ske->x);
+    silc_mp_clear(&ske->KEY);
+    if (ske->hash)
+      silc_free(ske->hash);
+    silc_free(ske);
+  }
+}
+
+/* Starts the SILC Key Exchange protocol for initiator. The connection
+   to the remote end must be established before calling this function
+   and the connecting socket must be sent as argument. This function
+   creates the Key Exchange Start Paload which includes all our
+   configured security properties. This payload is then sent to the
+   remote end for further processing. This payload must be sent as
+   argument to the function, however, it must not be encoded
+   already, it is done by this function.
+
+   The packet sending is done by calling a callback function. Caller
+   must provide a routine to send the packet. */
+
+SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+                                      SilcSocketConnection sock,
+                                      SilcSKEStartPayload *start_payload,
+                                      SilcSKESendPacketCb send_packet,
+                                      void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer payload_buf;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  ske->sock = sock;
+  ske->rng = rng;
+
+  /* Encode the payload */
+  status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
+  if (status != SILC_SKE_STATUS_OK)
+    return status;
+
+  /* Take a copy of the payload buffer for future use. It is used to
+     compute the HASH value. */
+  ske->start_payload_copy = silc_buffer_copy(payload_buf);
+
+  /* Send the packet. */
+  if (send_packet)
+    (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
+
+  silc_buffer_free(payload_buf);
+
+  return status;
+}
+
+/* Function called after ske_initiator_start fuction. This receives
+   the remote ends Key Exchange Start payload which includes the
+   security properties selected by the responder from our payload
+   sent in the silc_ske_initiator_start function. */
+
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
+                                        SilcBuffer start_payload,
+                                        SilcSKECb callback,
+                                        void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcSKEStartPayload *payload;
+  SilcSKESecurityProperties prop;
+  SilcSKEDiffieHellmanGroup group;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Decode the payload */
+  status = silc_ske_payload_start_decode(ske, start_payload, &payload);
+  if (status != SILC_SKE_STATUS_OK)
+    return status;
+
+  /* Take the selected security properties into use while doing
+     the key exchange. This is used only while doing the key 
+     exchange. The same data is returned to upper levels by calling
+     the callback function. */
+  ske->prop = prop = silc_calloc(1, sizeof(*prop));
+  prop->flags = payload->flags;
+  status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  prop->group = group;
+
+  if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+    goto err;
+  }
+
+  if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+    goto err;
+  }
+
+  if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+    goto err;
+  }
+
+  ske->start_payload = payload;
+
+  /* Return the received payload by calling the callback function. */
+  if (callback)
+    (*callback)(ske, context);
+
+  return status;
+
+ err:
+  if (payload)
+    silc_ske_payload_start_free(payload);
+
+  silc_free(group);
+
+  if (prop->pkcs)
+    silc_pkcs_free(prop->pkcs);
+  if (prop->cipher)
+    silc_cipher_free(prop->cipher);
+  if (prop->hash)
+    silc_hash_free(prop->hash);
+  silc_free(prop);
+  ske->prop = NULL;
+
+  if (status == SILC_SKE_STATUS_OK)
+    return SILC_SKE_STATUS_ERROR;
+
+  return status;
+}
+
+/* This function creates random number x, such that 1 < x < q and 
+   computes e = g ^ x mod p and sends the result to the remote end in 
+   Key Exchange 1 Payload. */
+
+SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+                                        SilcSKESendPacketCb send_packet,
+                                        void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer payload_buf;
+  SilcInt x, e;
+  SilcSKEOnePayload *payload;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Create the random number x, 1 < x < q. */
+  silc_mp_init(&x);
+  status = 
+    silc_ske_create_rnd(ske, ske->prop->group->group_order,
+                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
+                       &x);
+  if (status != SILC_SKE_STATUS_OK) {
+    silc_mp_clear(&x);
+    return status;
+  }
+
+  SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
+
+  /* Do the Diffie Hellman computation, e = g ^ x mod p */
+  silc_mp_init(&e);
+  silc_mp_powm(&e, &ske->prop->group->generator, &x, 
+              &ske->prop->group->group);
+  
+  /* Encode the result to Key Exchange 1 Payload. */
+  payload = silc_calloc(1, sizeof(*payload));
+  payload->e = e;
+  status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
+  if (status != SILC_SKE_STATUS_OK) {
+    silc_mp_clear(&x);
+    silc_mp_clear(&e);
+    silc_free(payload);
+    return status;
+  }
+
+  ske->ke1_payload = payload;
+  ske->x = x;
+
+  /* Send the packet. */
+  if (send_packet)
+    (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
+
+  silc_buffer_free(payload_buf);
+
+  return status;
+}
+
+/* Receives Key Exchange 2 Payload from responder consisting responders
+   public key, f, and signature. This function verifies the public key,
+   computes the secret shared key and verifies the signature. */
+
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+                                       SilcBuffer ke2_payload,
+                                       SilcSKECb callback,
+                                       void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcSKETwoPayload *payload;
+  SilcInt KEY;
+  unsigned char hash[32];
+  unsigned int hash_len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Decode the payload */
+  status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
+  if (status != SILC_SKE_STATUS_OK)
+    return status;
+  ske->ke2_payload = payload;
+
+  SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
+
+  /* Compute the shared secret key */
+  silc_mp_init(&KEY);
+  silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
+  ske->KEY = KEY;
+
+  SILC_LOG_DEBUG(("Verifying public key"));
+
+  /* Verify the public key */ /* XXX */
+  status = silc_ske_verify_public_key(ske, payload->pk_data, 
+                                     payload->pk_len);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+  
+  SILC_LOG_DEBUG(("Public key is authentic"));
+
+  /* Compute the hash value */
+  status = silc_ske_make_hash(ske, hash, &hash_len);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
+  memcpy(ske->hash, hash, hash_len);
+  ske->hash_len = hash_len;
+
+  SILC_LOG_DEBUG(("Verifying signature"));
+
+  /* Verify signature */
+  silc_pkcs_set_public_key(ske->prop->pkcs, payload->pk_data, payload->pk_len);
+  if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
+                                   payload->sign_data, payload->sign_len,
+                                   hash, hash_len) == FALSE) {
+
+    SILC_LOG_DEBUG(("Signature don't match"));
+
+    status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
+    goto err;
+  }
+
+  SILC_LOG_DEBUG(("Signature is Ok"));
+
+  memset(hash, 'F', hash_len);
+
+  /* Call the callback. */
+  if (callback)
+    (*callback)(ske, context);
+
+  return status;
+
+ err:
+  memset(hash, 'F', hash_len);
+  silc_ske_payload_two_free(payload);
+
+  silc_mp_clear(&ske->KEY);
+
+  if (ske->hash) {
+    memset(ske->hash, 'F', hash_len);
+    silc_free(ske->hash);
+    ske->hash = NULL;
+  }
+
+  if (status == SILC_SKE_STATUS_OK)
+    return SILC_SKE_STATUS_ERROR;
+
+  return status;
+}
+
+/* Starts Key Exchange protocol for responder. Responder receives
+   Key Exchange Start Payload from initiator consisting of all the
+   security properties the initiator supports. This function decodes
+   the payload and parses the payload further and selects the right 
+   security properties. */
+
+SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+                                      SilcSocketConnection sock,
+                                      SilcBuffer start_payload,
+                                      SilcSKECb callback,
+                                      void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  ske->sock = sock;
+  ske->rng = rng;
+
+  /* Decode the payload */
+  status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
+  if (status != SILC_SKE_STATUS_OK)
+    return status;
+
+  /* Take a copy of the payload buffer for future use. It is used to
+     compute the HASH value. */
+  ske->start_payload_copy = silc_buffer_copy(start_payload);
+
+  /* Parse and select the security properties from the payload */
+  payload = silc_calloc(1, sizeof(*payload));
+  status = silc_ske_select_security_properties(ske, payload, remote_payload);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  ske->start_payload = payload;
+
+  /* Call the callback function. */
+  if (callback)
+    (*callback)(ske, context);
+
+  return status;
+
+ err:
+  if (remote_payload)
+    silc_ske_payload_start_free(remote_payload);
+  if (payload)
+    silc_free(payload);
+
+  if (status == SILC_SKE_STATUS_OK)
+    return SILC_SKE_STATUS_ERROR;
+
+  return status;
+}
+
+/* The selected security properties from the initiator payload is now 
+   encoded into Key Exchange Start Payload and sent to the initiator. */
+
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
+                                        SilcSKEStartPayload *start_payload,
+                                        SilcSKESendPacketCb send_packet,
+                                        void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer payload_buf;
+  SilcSKESecurityProperties prop;
+  SilcSKEDiffieHellmanGroup group;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Allocate security properties from the payload. These are allocated
+     only for this negotiation and will be free'd after KE is over. */
+  ske->prop = prop = silc_calloc(1, sizeof(*prop));
+  prop->flags = start_payload->flags;
+  status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  prop->group = group;
+
+  if (silc_pkcs_alloc(start_payload->pkcs_alg_list, 
+                     &prop->pkcs) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+    goto err;
+  }
+
+  if (silc_cipher_alloc(start_payload->enc_alg_list, 
+                       &prop->cipher) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+    goto err;
+  }
+
+  if (silc_hash_alloc(start_payload->hash_alg_list,
+                     &prop->hash) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+    goto err;
+  }
+
+  /* Encode the payload */
+  status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  /* Send the packet. */
+  if (send_packet)
+    (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
+
+  silc_buffer_free(payload_buf);
+
+  return status;
+
+ err:
+  silc_free(group);
+
+  if (prop->pkcs)
+    silc_pkcs_free(prop->pkcs);
+  if (prop->cipher)
+    silc_cipher_free(prop->cipher);
+  if (prop->hash)
+    silc_hash_free(prop->hash);
+  silc_free(prop);
+  ske->prop = NULL;
+
+  if (status == SILC_SKE_STATUS_OK)
+    return SILC_SKE_STATUS_ERROR;
+
+  return status;
+}
+
+/* This function receives the Key Exchange 1 Payload from the initiator.
+   After processing the payload this then selects random number x,
+   such that 1 < x < q and computes f = g ^ x mod p. This then puts
+   the result f to a Key Exchange 2 Payload which is later processed
+   in ske_responder_finish function. The callback function should
+   not touch the payload (it should merely call the ske_responder_finish
+   function). */
+
+SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+                                        SilcBuffer ke1_payload,
+                                        SilcSKECb callback,
+                                        void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcSKEOnePayload *one_payload;
+  SilcSKETwoPayload *two_payload;
+  SilcInt x, f;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Decode Key Exchange 1 Payload */
+  status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
+  if (status != SILC_SKE_STATUS_OK)
+    return status;
+
+  /* Create the random number x, 1 < x < q. */
+  silc_mp_init(&x);
+  status = 
+    silc_ske_create_rnd(ske, ske->prop->group->group_order,
+                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
+                       &x);
+  if (status != SILC_SKE_STATUS_OK) {
+    silc_mp_clear(&x);
+    return status;
+  }
+
+  SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
+
+  /* Do the Diffie Hellman computation, f = g ^ x mod p */
+  silc_mp_init(&f);
+  silc_mp_powm(&f, &ske->prop->group->generator, &x, 
+              &ske->prop->group->group);
+  
+  /* Save the results for later processing */
+  two_payload = silc_calloc(1, sizeof(*two_payload));
+  two_payload->f = f;
+  ske->x = x;
+  ske->ke1_payload = one_payload;
+  ske->ke2_payload = two_payload;
+
+  /* Call the callback. */
+  if (callback)
+    (*callback)(ske, context);
+
+  return status;
+}
+
+/* This function computes the secret shared key KEY = e ^ x mod p, and, 
+   a hash value to be signed and sent to the other end. This then
+   encodes Key Exchange 2 Payload and sends it to the other end. */
+
+SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+                                       unsigned char *pk,
+                                       unsigned int pk_len,
+                                       unsigned char *prv,
+                                       unsigned int prv_len,
+                                       SilcSKEPKType pk_type,
+                                       SilcSKESendPacketCb send_packet,
+                                       void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer payload_buf;
+  SilcInt KEY;
+  unsigned char hash[32], sign[256];
+  unsigned int hash_len, sign_len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
+
+  /* Compute the shared secret key */
+  silc_mp_init(&KEY);
+  silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x, 
+              &ske->prop->group->group);
+  ske->KEY = KEY;
+
+  SILC_LOG_DEBUG(("Getting public key"));
+
+  /* Get the public key */
+  ske->ke2_payload->pk_data = silc_calloc(pk_len, sizeof(unsigned char));
+  memcpy(ske->ke2_payload->pk_data, pk, pk_len);
+  ske->ke2_payload->pk_len = pk_len;
+  ske->ke2_payload->pk_type = pk_type;
+
+  SILC_LOG_DEBUG(("Computing HASH value"));
+
+  /* Compute the hash value */
+  memset(hash, 0, sizeof(hash));
+  status = silc_ske_make_hash(ske, hash, &hash_len);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
+  memcpy(ske->hash, hash, hash_len);
+  ske->hash_len = hash_len;
+
+  SILC_LOG_DEBUG(("Signing HASH value"));
+
+  /* Sign the hash value */
+  silc_pkcs_set_private_key(ske->prop->pkcs, prv, prv_len);
+  ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
+                             hash, hash_len,
+                             sign, &sign_len);
+  ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
+  memcpy(ske->ke2_payload->sign_data, sign, sign_len);
+  memset(sign, 0, sizeof(sign));
+  ske->ke2_payload->sign_len = sign_len;
+
+  /* Encode the Key Exchange 2 Payload */
+  status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
+                                      &payload_buf);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
+
+  /* Send the packet. */
+  if (send_packet)
+    (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
+
+  silc_buffer_free(payload_buf);
+
+  return status;
+
+ err:
+  silc_mp_clear(&ske->KEY);
+  silc_ske_payload_two_free(ske->ke2_payload);
+
+  if (status == SILC_SKE_STATUS_OK)
+    return SILC_SKE_STATUS_ERROR;
+
+  return status;
+}
+
+/* The Key Exchange protocol is ended by calling this function. This
+   must not be called until the keys are processed like the protocol
+   defines. This function is for both initiator and responder. */
+
+SilcSKEStatus silc_ske_end(SilcSKE ske,
+                          SilcSKESendPacketCb send_packet,
+                          void *context)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer packet;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  packet = silc_buffer_alloc(1);
+  packet->len = 0;
+
+  if (send_packet)
+    (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
+
+  return status;
+}
+
+/* Aborts the Key Exchange protocol. This is called if error occurs
+   while performing the protocol. The status argument is the error
+   status and it is sent to the remote end. */
+
+SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
+                            SilcSKESendPacketCb send_packet,
+                            void *context)
+{
+  SilcBuffer packet;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  packet = silc_buffer_alloc(4);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(status),
+                    SILC_STR_END);
+
+  if (send_packet)
+    (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
+
+  silc_buffer_free(packet);
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Assembles security properties to Key Exchange Start Payload to be
+   sent to the remote end. This checks system wide (SILC system, that is)
+   settings and chooses from those. However, if other properties
+   should be used this function is easy to replace by another function,
+   as, this function is called by the caller of the protocol and not
+   by the protocol itself. */
+
+SilcSKEStatus 
+silc_ske_assemble_security_properties(SilcSKE ske,
+                                     SilcSKEStartPayload **return_payload)
+{
+  SilcSKEStartPayload *rp;
+
+  SILC_LOG_DEBUG(("Assembling KE Start Payload"));
+
+  rp = silc_calloc(1, sizeof(*rp));
+
+  /* XXX */
+  /* Set flags */
+  rp->flags = 0;
+
+  /* XXX */
+  /* Cookie */
+  rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+  rp->cookie_len = SILC_SKE_COOKIE_LEN;
+  memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
+
+  /* Get supported Key Exhange groups */
+  rp->ke_grp_list = silc_ske_get_supported_groups();
+  rp->ke_grp_len = strlen(rp->ke_grp_list);
+
+  /* Get supported PKCS algorithms */
+  rp->pkcs_alg_list = silc_pkcs_get_supported();
+  rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
+
+  /* Get supported encryption algorithms */
+  rp->enc_alg_list = silc_cipher_get_supported();
+  rp->enc_alg_len = strlen(rp->enc_alg_list);
+
+  /* Get supported hash algorithms */
+  rp->hash_alg_list = silc_hash_get_supported();
+  rp->hash_alg_len = strlen(rp->hash_alg_list);
+
+  /* XXX */
+  /* Get supported compression algorithms */
+  rp->comp_alg_list = "";
+  rp->comp_alg_len = 0;
+
+  rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
+    2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
+    2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
+    2 + rp->comp_alg_len;
+
+  *return_payload = rp;
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Selects the supported security properties from the remote end's Key 
+   Exchange Start Payload. */
+
+SilcSKEStatus 
+silc_ske_select_security_properties(SilcSKE ske,
+                                   SilcSKEStartPayload *payload,
+                                   SilcSKEStartPayload *remote_payload)
+{
+  SilcSKEStartPayload *rp;
+  char *cp;
+  int len;
+
+  SILC_LOG_DEBUG(("Parsing KE Start Payload"));
+
+  rp = remote_payload;
+
+  /* Flags are returned unchanged. */
+  payload->flags = rp->flags;
+
+  /* XXX Cookie check?? */
+  payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+  payload->cookie_len = SILC_SKE_COOKIE_LEN;
+  memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
+
+  /* Get supported Key Exchange groups */
+  cp = rp->ke_grp_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
+
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      memcpy(item, cp, len);
+
+      SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
+
+      if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
+       SILC_LOG_DEBUG(("Found KE group `%s'", item));
+
+       payload->ke_grp_len = len;
+       payload->ke_grp_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->ke_grp_len && !payload->ke_grp_list) {
+      SILC_LOG_DEBUG(("Could not find supported KE group"));
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_GROUP;
+    }
+  } else {
+
+    if (!rp->ke_grp_len) {
+      SILC_LOG_DEBUG(("KE group not defined in payload"));
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
+
+    SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
+    SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
+
+    payload->ke_grp_len = rp->ke_grp_len;
+    payload->ke_grp_list = strdup(rp->ke_grp_list);
+  }
+
+  /* Get supported PKCS algorithms */
+  cp = rp->pkcs_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
+
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      memcpy(item, cp, len);
+
+      SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
+
+      if (silc_pkcs_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
+
+       payload->pkcs_alg_len = len;
+       payload->pkcs_alg_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_PKCS;
+    }
+  } else {
+
+    if (!rp->pkcs_alg_len) {
+      SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
+
+    SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
+    SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
+
+    payload->pkcs_alg_len = rp->pkcs_alg_len;
+    payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
+  }
+
+  /* Get supported encryption algorithms */
+  cp = rp->enc_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
+
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      memcpy(item, cp, len);
+
+      SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
+
+      if (silc_cipher_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
+
+       payload->enc_alg_len = len;
+       payload->enc_alg_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->enc_alg_len && !payload->enc_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported encryption alg"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_CIPHER;
+    }
+  } else {
+
+    if (!rp->enc_alg_len) {
+      SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
+
+    SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
+                   rp->enc_alg_list));
+
+    payload->enc_alg_len = rp->enc_alg_len;
+    payload->enc_alg_list = strdup(rp->enc_alg_list);
+  }
+
+  /* Get supported hash algorithms */
+  cp = rp->hash_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
+
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      memcpy(item, cp, len);
+
+      SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
+
+      if (silc_hash_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found hash alg `%s'", item));
+
+       payload->hash_alg_len = len;
+       payload->hash_alg_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->hash_alg_len && !payload->hash_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported hash alg"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+    }
+  } else {
+
+    if (!rp->hash_alg_len) {
+      SILC_LOG_DEBUG(("Hash alg not defined in payload"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
+
+    SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
+                   rp->hash_alg_list));
+
+    payload->hash_alg_len = rp->hash_alg_len;
+    payload->hash_alg_list = strdup(rp->hash_alg_list);
+  }
+
+#if 0
+  /* Get supported compression algorithms */
+  cp = rp->hash_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
+
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      memcpy(item, cp, len);
+
+      SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
+
+      if (silc_hash_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found hash alg `%s'", item));
+
+       payload->hash_alg_len = len;
+       payload->hash_alg_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->hash_alg_len && !payload->hash_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported hash alg"));
+      silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload);
+      return;
+    }
+  } else {
+
+  }
+#endif
+
+  payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
+    2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
+    2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
+    2 + payload->comp_alg_len;
+
+  return SILC_SKE_STATUS_OK;
+}
+
+/* Creates random number such that 1 < rnd < n and at most length
+   of len bits. The rnd sent as argument must be initialized. */
+
+SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
+                                 unsigned int len, 
+                                 SilcInt *rnd)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  unsigned char *string;
+
+  SILC_LOG_DEBUG(("Creating random number"));
+
+  /* Get the random number as string */
+  string = silc_rng_get_rn_string(ske->rng, (len / 8));
+
+  /* Decode the string into a MP integer */
+  silc_mp_set_str(rnd, string, 16);
+  silc_mp_mod_2exp(rnd, rnd, len);
+
+  /* Checks */
+  if (silc_mp_cmp_ui(rnd, 1) < 0)
+    status = SILC_SKE_STATUS_ERROR;
+
+  if (silc_mp_cmp(rnd, &n) >= 0)
+    status = SILC_SKE_STATUS_ERROR;
+
+  memset(string, 'F', (len / 8));
+  silc_free(string);
+
+  return status;
+}
+
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske, 
+                                        unsigned char *pubkey,
+                                        unsigned int pubkey_len)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+
+  return status;
+}
+
+/* Creates a hash value HASH as defined in the SKE protocol. */
+
+SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
+                                unsigned char *return_hash,
+                                unsigned int *return_hash_len)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer buf;
+  unsigned char *e, *f, *KEY;
+  unsigned int e_len, f_len, KEY_len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
+  e = silc_calloc(e_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(e, 16, &ske->ke1_payload->e);
+
+  f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
+  f = silc_calloc(f_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(f, 16, &ske->ke2_payload->f);
+
+  KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
+  KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
+  silc_mp_get_str(KEY, 16, &ske->KEY);
+
+  buf = silc_buffer_alloc(ske->start_payload_copy->len + 
+                         ske->pk_len + e_len + f_len + KEY_len);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+  /* Format the buffer used to compute the hash value */
+  silc_buffer_format(buf,
+                    SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+                                         ske->start_payload_copy->len),
+                    SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
+                    SILC_STR_UI_XNSTRING(e, e_len),
+                    SILC_STR_UI_XNSTRING(f, f_len),
+                    SILC_STR_UI_XNSTRING(KEY, KEY_len),
+                    SILC_STR_END);
+
+#if 0
+  SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
+#endif
+
+  /* Make the hash */
+  silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
+  *return_hash_len = ske->prop->hash->hash->hash_len;
+
+  SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
+
+  silc_buffer_free(buf);
+  memset(e, 0, e_len);
+  memset(f, 0, f_len);
+  memset(KEY, 0, KEY_len);
+  silc_free(e);
+  silc_free(f);
+  silc_free(KEY);
+
+  return status;
+}
+
+/* Processes negotiated key material as protocol specifies. This returns
+   the actual keys to be used in the SILC. */
+
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
+                                           unsigned int req_iv_len,
+                                           unsigned int req_enc_key_len,
+                                           unsigned int req_hmac_key_len,
+                                           SilcSKEKeyMaterial *key)
+{
+  int i, klen;
+  SilcBuffer buf;
+  SilcInt tmp;
+  unsigned char *tmpbuf;
+  unsigned char hash[32];
+  unsigned int hash_len = ske->prop->hash->hash->hash_len;
+  unsigned int enc_key_len = req_enc_key_len / 8;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  silc_mp_init_set(&tmp, &ske->KEY);
+
+  klen = silc_mp_size(&tmp);
+
+  /* Format the KEY material into binary data */
+  tmpbuf = silc_calloc(klen, sizeof(unsigned char));
+  for (i = klen; i > 0; i--) {
+    tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
+    silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
+  }
+
+  buf = silc_buffer_alloc(1 + klen + hash_len);
+
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+  silc_buffer_format(buf,
+                    SILC_STR_UI_CHAR(0),
+                    SILC_STR_UI_XNSTRING(tmpbuf, klen),
+                    SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+                    SILC_STR_END);
+
+  /* Take IVs */
+  memset(hash, 0, sizeof(hash));
+  buf->data[0] = 0;
+  silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+  key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
+  memcpy(key->send_iv, hash, req_iv_len);
+  memset(hash, 0, sizeof(hash));
+  buf->data[0] = 1;
+  silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+  key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
+  memcpy(key->receive_iv, hash, req_iv_len);
+  key->iv_len = req_iv_len;
+
+  /* Take the encryption keys. If requested key size is more than
+     the size of hash length we will distribute more key material
+     as protocol defines. */
+  buf->data[0] = 2;
+  if (enc_key_len > hash_len) {
+    SilcBuffer dist;
+    unsigned char k1[32], k2[32], k3[32];
+    unsigned char *dtmp;
+    
+    /* XXX */
+    if (enc_key_len > (3 * hash_len))
+      return SILC_SKE_STATUS_ERROR;
+    
+    memset(k1, 0, sizeof(k1));
+    silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
+    
+    /* XXX */
+    dist = silc_buffer_alloc(hash_len * 3);
+    
+    silc_buffer_pull_tail(dist, klen + hash_len);
+    silc_buffer_format(dist,
+                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
+                      SILC_STR_UI_XNSTRING(k1, hash_len),
+                      SILC_STR_END);
+    
+    memset(k2, 0, sizeof(k2));
+    silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
+    
+    silc_buffer_pull(dist, klen + hash_len);
+    silc_buffer_format(dist,
+                      SILC_STR_UI_XNSTRING(k2, hash_len),
+                      SILC_STR_END);
+    silc_buffer_push(dist, klen + hash_len);
+    
+    memset(k3, 0, sizeof(k3));
+    silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
+    
+    dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
+    memcpy(dtmp, k1, hash_len);
+    memcpy(dtmp + hash_len, k2, hash_len);
+    memcpy(dtmp + hash_len, k3, hash_len);
+
+    key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+    memcpy(key->send_enc_key, dtmp, enc_key_len);
+    key->enc_key_len = req_enc_key_len;
+
+    memset(dtmp, 0, (3 * hash_len));
+    memset(k1, 0, sizeof(k1));
+    memset(k2, 0, sizeof(k2));
+    memset(k3, 0, sizeof(k3));
+    silc_free(dtmp);
+    silc_buffer_free(dist);
+  } else {
+    /* Take normal hash as key */
+    memset(hash, 0, sizeof(hash));
+    silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+    key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+    memcpy(key->send_enc_key, hash, enc_key_len);
+    key->enc_key_len = req_enc_key_len;
+  }
+
+  buf->data[0] = 3;
+  if (enc_key_len > hash_len) {
+    SilcBuffer dist;
+    unsigned char k1[32], k2[32], k3[32];
+    unsigned char *dtmp;
+    
+    /* XXX */
+    if (enc_key_len > (3 * hash_len))
+      return SILC_SKE_STATUS_ERROR;
+    
+    memset(k1, 0, sizeof(k1));
+    silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
+    
+    /* XXX */
+    dist = silc_buffer_alloc(hash_len * 3);
+    
+    silc_buffer_pull_tail(dist, klen + hash_len);
+    silc_buffer_format(dist,
+                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
+                      SILC_STR_UI_XNSTRING(k1, hash_len),
+                      SILC_STR_END);
+    
+    memset(k2, 0, sizeof(k2));
+    silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
+    
+    silc_buffer_pull(dist, klen + hash_len);
+    silc_buffer_format(dist,
+                      SILC_STR_UI_XNSTRING(k2, hash_len),
+                      SILC_STR_END);
+    silc_buffer_push(dist, klen + hash_len);
+    
+    memset(k3, 0, sizeof(k3));
+    silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
+    
+    dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
+    memcpy(dtmp, k1, hash_len);
+    memcpy(dtmp + hash_len, k2, hash_len);
+    memcpy(dtmp + hash_len, k3, hash_len);
+
+    key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+    memcpy(key->receive_enc_key, dtmp, enc_key_len);
+    key->enc_key_len = req_enc_key_len;
+
+    memset(dtmp, 0, (3 * hash_len));
+    memset(k1, 0, sizeof(k1));
+    memset(k2, 0, sizeof(k2));
+    memset(k3, 0, sizeof(k3));
+    silc_free(dtmp);
+    silc_buffer_free(dist);
+  } else {
+    /* Take normal hash as key */
+    memset(hash, 0, sizeof(hash));
+    silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+    key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+    memcpy(key->receive_enc_key, hash, enc_key_len);
+    key->enc_key_len = req_enc_key_len;
+  }
+
+  /* Take HMAC key */
+  memset(hash, 0, sizeof(hash));
+  buf->data[0] = 4;
+  silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+  key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
+  memcpy(key->hmac_key, hash, req_hmac_key_len);
+  key->hmac_key_len = req_hmac_key_len;
+
+  memset(tmpbuf, 0, klen);
+  silc_free(tmpbuf);
+
+  return SILC_SKE_STATUS_OK;
+}
diff --git a/lib/silcske/silcske.h b/lib/silcske/silcske.h
new file mode 100644 (file)
index 0000000..e429b70
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+
+  silcske.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSKE_H
+#define SILCSKE_H
+
+#include "silcske_status.h"
+
+/* Forward declaration for SKE object. */
+typedef struct SilcSKEStruct *SilcSKE;
+
+/* Forward declaration for security properties. */
+typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties;
+
+/* Packet sending callback. Caller of the SKE routines must provide
+   a routine to send packets to negotiation parties. */
+typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet, 
+                                   SilcPacketType type, void *context);
+
+/* Generic SKE callback function. This is called in various SKE
+   routines. The SilcSKE object sent as argument provides all the data
+   callers routine might need (payloads etc). */
+typedef void (*SilcSKECb)(SilcSKE ske, void *context);
+
+/* Supported Public Key Types, defined by the protocol */
+typedef enum {
+  SILC_SKE_PK_TYPE_SILC = 1,   /* Mandatory type */
+  /* Optional types. These are not implemented currently
+  SILC_SKE_PK_TYPE_SSH2 = 2,
+  SILC_SKE_PK_TYPE_X509V3 = 3,
+  SILC_SKE_PK_TYPE_OPENPGP = 4,
+  SILC_SKE_PK_TYPE_SPKI = 5
+  */
+} SilcSKEPKType;
+
+/* Context passed to key material processing function. The function
+   returns the processed key material into this structure. */
+typedef struct {
+  unsigned char *send_iv;
+  unsigned char *receive_iv;
+  unsigned int iv_len;
+  unsigned char *send_enc_key;
+  unsigned char *receive_enc_key;
+  unsigned int enc_key_len;
+  unsigned char *hmac_key;
+  unsigned int hmac_key_len;
+} SilcSKEKeyMaterial;
+
+#define SILC_SKE_COOKIE_LEN 16
+
+#include "groups.h"
+#include "payload.h"
+
+/* Security Property Flags. */
+typedef enum {
+  SILC_SKE_SP_FLAG_NONE = (1L << 0),
+  SILC_SKE_SP_FLAG_NO_REPLY = (1L << 1),
+  SILC_SKE_SP_FLAG_PFS = (1L << 2),
+} SilcSKESecurityPropertyFlag;
+
+/* Security Properties negotiated between key exchange parties. This
+   structure is filled from the Key Exchange Start Payload which is used
+   to negotiate what security properties should be used in the
+   communication. */
+struct SilcSKESecurityPropertiesStruct {
+  unsigned char flags;
+  SilcSKEDiffieHellmanGroup group;
+  SilcPKCS pkcs;
+  SilcCipher cipher;
+  SilcHash hash;
+  /* XXX SilcCompression comp; */
+};
+
+struct SilcSKEStruct {
+  /* The connection object. This is initialized by the caller. */
+  SilcSocketConnection sock;
+
+  /* Security properties negotiated */
+  SilcSKESecurityProperties prop;
+
+  /* Key Exchange payloads filled during key negotiation with
+     remote data. Responder may save local data here as well. */
+  SilcSKEStartPayload *start_payload;
+  SilcSKEOnePayload *ke1_payload;
+  SilcSKETwoPayload *ke2_payload;
+
+  /* Temporary copy of the KE Start Payload used in the
+     HASH computation. */
+  SilcBuffer start_payload_copy;
+
+  /* If initiator, this is responders public key. If responder this
+     is our own public key. */
+  unsigned char *pk;
+  unsigned int pk_len;
+
+  /* Random number x, 1 < x < q. This is the secret exponent
+     used in Diffie Hellman computations. */
+  SilcInt x;
+  
+  /* The secret shared key */
+  SilcInt KEY;
+  
+  /* The hash value HASH of the key exchange */
+  unsigned char *hash;
+  unsigned int hash_len;
+
+  /* Random Number Generator. This is set by the caller and must
+     be free'd by the caller. */
+  SilcRng rng;
+
+  /* Pointer to the what ever user data. This is set by the caller
+     and is not touched by the SKE. The caller must also free this one. */
+  void *user_data;
+};
+
+/* Prototypes */
+SilcSKE silc_ske_alloc();
+void silc_ske_free(SilcSKE ske);
+SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
+                                      SilcSocketConnection sock,
+                                      SilcSKEStartPayload *start_payload,
+                                      SilcSKESendPacketCb send_packet,
+                                      void *context);
+SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
+                                        SilcBuffer start_payload,
+                                        SilcSKECb callback,
+                                        void *context);
+SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+                                        SilcSKESendPacketCb send_packet,
+                                        void *context);
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+                                       SilcBuffer ke2_payload,
+                                       SilcSKECb callback,
+                                       void *context);
+SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
+                                      SilcSocketConnection sock,
+                                      SilcBuffer start_payload,
+                                      SilcSKECb callback,
+                                      void *context);
+SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske, 
+                                        SilcSKEStartPayload *start_payload,
+                                        SilcSKESendPacketCb send_packet,
+                                        void *context);
+SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
+                                        SilcBuffer ke1_payload,
+                                        SilcSKECb callback,
+                                        void *context);
+SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
+                                       unsigned char *pk,
+                                       unsigned int pk_len,
+                                       unsigned char *prv,
+                                       unsigned int prv_len,
+                                       SilcSKEPKType pk_type,
+                                       SilcSKESendPacketCb send_packet,
+                                       void *context);
+SilcSKEStatus silc_ske_end(SilcSKE ske,
+                          SilcSKESendPacketCb send_packet,
+                          void *context);
+SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
+                            SilcSKESendPacketCb send_packet,
+                            void *context);
+SilcSKEStatus 
+silc_ske_assemble_security_properties(SilcSKE ske,
+                                     SilcSKEStartPayload **return_payload);
+SilcSKEStatus 
+silc_ske_select_security_properties(SilcSKE ske,
+                                   SilcSKEStartPayload *payload,
+                                   SilcSKEStartPayload *remote_payload);
+SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
+                                 unsigned int len, 
+                                 SilcInt *rnd);
+SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske, 
+                                        unsigned char *pubkey,
+                                        unsigned int pubkey_len);
+SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
+                                unsigned char *return_hash,
+                                unsigned int *return_hash_len);
+SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
+                                           unsigned int req_iv_len,
+                                           unsigned int req_enc_key_len,
+                                           unsigned int req_hmac_key_len,
+                                           SilcSKEKeyMaterial *key);
+#endif
diff --git a/lib/silcske/silcske_status.h b/lib/silcske/silcske_status.h
new file mode 100644 (file)
index 0000000..f512354
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+  silcske_status.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCSKE_STATUS_H
+#define SILCSKE_STATUS_H
+
+/* Status flags returned by all SKE routines */
+typedef enum {
+  /* These are defined by the protocol */
+  SILC_SKE_STATUS_OK = 0,
+  SILC_SKE_STATUS_ERROR = 1,
+  SILC_SKE_STATUS_BAD_PAYLOAD = 2,
+  SILC_SKE_STATUS_UNKNOWN_GROUP = 3,
+  SILC_SKE_STATUS_UNKNOWN_CIPHER = 4,
+  SILC_SKE_STATUS_UNKNOWN_PKCS = 5,
+  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION = 6,
+  SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 7,
+  SILC_SKE_STATUS_INCORRECT_SIGNATURE = 8,
+
+  SILC_SKE_STATUS_KEY_EXCHANGE_NOT_ACTIVE,
+  SILC_SKE_STATUS_BAD_RESERVED_FIELD,
+  SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH,
+  SILC_SKE_STATUS_INCORRECT_HASH,
+  SILC_SKE_STATUS_INCORRECT_PUBLIC_KEY,
+} SilcSKEStatus;
+
+#endif
diff --git a/lib/zlib/ChangeLog b/lib/zlib/ChangeLog
new file mode 100644 (file)
index 0000000..57386a2
--- /dev/null
@@ -0,0 +1,471 @@
+
+               ChangeLog file for zlib
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+  occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+  (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+  See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz  (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean"  (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+  . zutil.c, zutil.h: added "const" for zmem*
+  . Make_vms.com: fixed some typos
+  . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+  . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+  . msdos/Makefile.*: use model-dependent name for the built zlib library
+  . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+     new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+  See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+  completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode  (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+  (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+  compression ratio on some files. This also allows inlining _tr_tally for
+  matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+  on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+  the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+  them at run time (thanks to Ken Raeburn for this suggestion). To create
+  trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+  gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occuring only with compression level 0 (thanks to
+  Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+  (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+  (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+  inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+   contrib/asm386/ by Gilles Vollant <info@winimage.com>
+       386 asm code replacing longest_match().
+   contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+        A C++ I/O streams interface to the zlib gz* functions
+   contrib/iostream2/  by Tyge Løvset <Tyge.Lovset@cmr.no>
+       Another C++ I/O streams interface
+   contrib/untgz/  by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+       A very simple tar.gz file extractor using zlib
+   contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+        How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+  level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+  (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)        
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+  
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+  bit, so the decompressor could decompress all the correct data but went
+  on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+  small and medium models; this makes the library incompatible with previous
+  versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+  avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+  Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+  and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+  -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+     warning C4746: 'inflate_mask' : unsized array treated as  '__far'
+     (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+  not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+  (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+  typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+  was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+  pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+  is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+  (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+  TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+  (one's complement) is now done inside crc32(). WARNING: this is
+  incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+  not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+  Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+  if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+  user-provided history buffer. This is supported only in deflateInit2
+  and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
diff --git a/lib/zlib/FAQ b/lib/zlib/FAQ
new file mode 100644 (file)
index 0000000..0feb6d3
--- /dev/null
@@ -0,0 +1,72 @@
+
+               Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page 
+http://www.cdrom.com/pub/infozip/zlib/ which may have more recent information.
+
+
+1) I need a Windows DLL
+2) I need a Visual Basic interface to zlib
+3) compress() returns Z_BUF_ERROR
+4) deflate or inflate returns Z_BUF_ERROR
+5) Where is the zlib documentation (man pages, etc...)?
+6) Why don't you use GNU autoconf, libtool, etc...?
+7) There is a bug in zlib.
+8) I get "undefined reference to gzputc"
+
+
+
+1) I need a Windows DLL
+
+  The zlib sources can be compiled without change to produce a DLL.
+  If you want a precompiled DLL, see http://www.winimage.com/zLibDll
+
+
+2) I need a Visual Basic interface to zlib
+
+  See http://www.tcfb.com/dowseware/cmp-z-it.zip
+      http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm
+  and contrib/visual-basic.txt
+
+3) compress() returns Z_BUF_ERROR
+
+  Make sure that before the call of compress, the length of the
+  compressed buffer is equal to the total size of the compressed buffer
+  and not zero.  For Visual Basic, check that this parameter is passed
+  by reference ("as any"), not by value ("as long").
+
+
+4) deflate or inflate returns Z_BUF_ERROR
+
+  Make sure that before the call avail_in and avail_out are not zero.
+
+
+5) Where is the zlib documentation (man pages, etc...)?
+
+  It's in zlib.h for the moment. Volunteers to transform this
+  to man pages, please contact jloup@gzip.org. Examples of zlib usage
+  are in the files example.c and minigzip.c.
+
+
+6) Why don't you use GNU autoconf, libtool, etc...?
+
+  Because we would like to keep zlib as a very small and simple package.
+  zlib is rather portable and doesn't need much configuration.
+
+
+7) There is a bug in zlib.
+
+  Most of the time, such problems are due to an incorrect usage
+  of zlib. Please try to reproduce the problem with a small
+  program and send us the corresponding source at zlib@quest.jpl.nasa.gov
+  Do not send multi-megabyte data files without prior agreement.
+
+
+8) I get "undefined reference to gzputc"
+
+  If "make test" produces something like
+     example.o(.text+0x174): 
+  check that you don't have old files libz.* in /usr/lib, /usr/local/lib
+  or /usr/X11R6/lib. Remove old versions then do "make install".
+
diff --git a/lib/zlib/INDEX b/lib/zlib/INDEX
new file mode 100644 (file)
index 0000000..8a24576
--- /dev/null
@@ -0,0 +1,86 @@
+ChangeLog              history of changes
+INDEX                  this file
+FAQ                    Frequently Asked Questions about zlib
+Make_vms.com           script for Vax/VMS
+Makefile               makefile for Unix (generated by configure)
+Makefile.in            makefile for Unix (template for configure)
+Makefile.riscos        makefile for RISCOS
+README                 guess what
+algorithm.txt          description of the (de)compression algorithm
+configure              configure script for Unix
+descrip.mms            makefile for Vax/VMS
+zlib.3                 mini man page for zlib (volunteers to write full
+                       man pages from zlib.h welcome. write to jloup@gzip.org)
+
+amiga/Makefile.sas     makefile for Amiga SAS/C
+amiga/Makefile.pup      makefile for Amiga powerUP SAS/C PPC
+
+msdos/Makefile.w32      makefile for Microsoft Visual C++ 32-bit
+msdos/Makefile.b32     makefile for Borland C++   32-bit
+msdos/Makefile.bor     makefile for Borland C/C++ 16-bit
+msdos/Makefile.dj2     makefile for DJGPP 2.x
+msdos/Makefile.emx     makefile for EMX 0.9c (32-bit DOS/OS2)
+msdos/Makefile.msc     makefile for Microsoft C 16-bit
+msdos/Makefile.tc      makefile for Turbo C
+msdos/Makefile.wat     makefile for Watcom C
+msdos/zlib.def         definition file for Windows DLL
+msdos/zlib.rc          definition file for Windows DLL
+
+nt/Makefile.nt         makefile for Windows NT
+nt/zlib.dnt            definition file for Windows NT DLL
+nt/Makefile.emx                makefile for EMX 0.9c/RSXNT 1.41 (Win32 Intel)
+nt/Makefile.gcc                makefile for Windows NT using GCC (mingw32)
+
+
+               zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+               private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+deflate.c
+deflate.h
+gzio.c
+infblock.c
+infblock.h
+infcodes.c
+infcodes.h
+inffast.c
+inffast.h
+inflate.c
+inftrees.c
+inftrees.h
+infutil.c
+infutil.h
+maketree.c
+trees.c
+uncompr.c
+zutil.c
+zutil.h
+
+               source files for sample programs:
+example.c
+minigzip.c
+
+               unsupported contribution by third parties
+
+contrib/asm386/ by Gilles Vollant <info@winimage.com>
+       386 asm code replacing longest_match().
+
+contrib/minizip/ by Gilles Vollant <info@winimage.com>
+       Mini zip and unzip based on zlib
+        See http://www.winimage.com/zLibDll/unzip.html
+
+contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+        A C++ I/O streams interface to the zlib gz* functions
+
+contrib/iostream2/  by Tyge Løvset <Tyge.Lovset@cmr.no>
+       Another C++ I/O streams interface
+
+contrib/untgz/  by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+       A very simple tar.gz extractor using zlib
+
+contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+        How to use compress(), uncompress() and the gz* functions from VB.
diff --git a/lib/zlib/Make_vms.com b/lib/zlib/Make_vms.com
new file mode 100644 (file)
index 0000000..1c57e8f
--- /dev/null
@@ -0,0 +1,115 @@
+$! make libz under VMS
+$! written by Martin P.J. Zinser <m.zinser@gsi.de>
+$!
+$! Look for the compiler used
+$!
+$ ccopt = ""
+$ if f$getsyi("HW_MODEL").ge.1024
+$ then
+$  ccopt = "/prefix=all"+ccopt
+$  comp  = "__decc__=1"
+$  if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ else
+$  if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs.""
+$   then
+$    comp  = "__vaxc__=1"
+$    if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$   else
+$    if f$trnlnm("SYS").eqs."" then define sys decc$library_include:
+$    ccopt = "/decc/prefix=all"+ccopt
+$    comp  = "__decc__=1"
+$  endif
+$ endif
+$!
+$! Build the thing plain or with mms
+$!
+$ write sys$output "Compiling Zlib sources ..."
+$ if f$search("SYS$SYSTEM:MMS.EXE").eqs.""
+$  then
+$   dele example.obj;*,minigzip.obj;*
+$   CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" -
+                adler32.c zlib.h zconf.h
+$   CALL MAKE compress.OBJ "CC ''CCOPT' compress" -
+                compress.c zlib.h zconf.h
+$   CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" -
+                crc32.c zlib.h zconf.h
+$   CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" -
+                deflate.c deflate.h zutil.h zlib.h zconf.h
+$   CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" -
+                gzio.c zutil.h zlib.h zconf.h
+$   CALL MAKE infblock.OBJ "CC ''CCOPT' infblock" -
+                infblock.c zutil.h zlib.h zconf.h infblock.h
+$   CALL MAKE infcodes.OBJ "CC ''CCOPT' infcodes" -
+                infcodes.c zutil.h zlib.h zconf.h inftrees.h
+$   CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" -
+                inffast.c zutil.h zlib.h zconf.h inffast.h
+$   CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" -
+                inflate.c zutil.h zlib.h zconf.h infblock.h
+$   CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" -
+                inftrees.c zutil.h zlib.h zconf.h inftrees.h
+$   CALL MAKE infutil.OBJ "CC ''CCOPT' infutil" -
+                infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+$   CALL MAKE trees.OBJ "CC ''CCOPT' trees" -
+                trees.c deflate.h zutil.h zlib.h zconf.h
+$   CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" -
+                uncompr.c zlib.h zconf.h
+$   CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" -
+                zutil.c zutil.h zlib.h zconf.h
+$   write sys$output "Building Zlib ..."
+$   CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ
+$   write sys$output "Building example..."
+$   CALL MAKE example.OBJ "CC ''CCOPT' example" -
+                example.c zlib.h zconf.h
+$   call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb
+$   write sys$output "Building minigzip..."
+$   CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" -
+                minigzip.c zlib.h zconf.h
+$   call make minigzip.exe - 
+                "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" - 
+                minigzip.obj libz.olb
+$  else
+$   mms/macro=('comp')
+$  endif
+$ write sys$output "Zlib build completed"
+$ exit
+$!
+$!
+$MAKE: SUBROUTINE   !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8  What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$       Argument = P'arg
+$       If Argument .Eqs. "" Then Goto Exit
+$       El=0
+$Loop2:
+$       File = F$Element(El," ",Argument)
+$       If File .Eqs. " " Then Goto Endl
+$       AFile = ""
+$Loop3:
+$       OFile = AFile
+$       AFile = F$Search(File)
+$       If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$       If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$       Goto Loop3
+$NextEL:
+$       El = El + 1
+$       Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
diff --git a/lib/zlib/Makefile b/lib/zlib/Makefile
new file mode 100644 (file)
index 0000000..29052d4
--- /dev/null
@@ -0,0 +1,174 @@
+# Makefile for zlib
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile and test, type:
+#   ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+#    make install
+# To install in $HOME instead of /usr/local, use:
+#    make install prefix=$HOME
+
+CC=gcc
+
+CFLAGS=-fPIC -O3 -DHAVE_UNISTD_H -DUSE_MMAP
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+#           -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=-L. -lz
+LDSHARED=gcc -shared -Wl,-soname,libz.so.1
+CPP=gcc -E
+
+VER=1.1.3
+LIBS=libz.so.1.1.3
+SHAREDLIB=libz.so
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+
+prefix =/usr/local
+exec_prefix =--cache-file=../.././config.cache
+libdir =${exec_prefix}/lib
+includedir =${prefix}/include
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README FAQ INDEX ChangeLog configure Make*[a-z0-9] *.[ch] *.mms \
+  algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+  nt/Make*[a-z0-9] nt/zlib.dnt amiga/Make*.??? os2/M*.os2 os2/zlib.def \
+  contrib/RE*.contrib contrib/*.txt contrib/asm386/*.asm contrib/asm386/*.c \
+  contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/asm[56]86/*.?86 \
+  contrib/asm[56]86/*.S contrib/iostream/*.cpp \
+  contrib/iostream/*.h  contrib/iostream2/*.h contrib/iostream2/*.cpp \
+  contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 \
+  contrib/minizip/[CM]*[pe] contrib/minizip/*.[ch] contrib/minizip/*.[td]?? \
+  contrib/delphi*/*.???
+
+all: example minigzip
+
+test: all
+       @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+       echo hello world | ./minigzip | ./minigzip -d || \
+         echo '                *** minigzip test FAILED ***' ; \
+       if ./example; then \
+         echo '                *** zlib test OK ***'; \
+       else \
+         echo '                *** zlib test FAILED ***'; \
+       fi
+
+libz.a: $(OBJS) $(OBJA)
+       $(AR) $@ $(OBJS) $(OBJA)
+       -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(CC) -c _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+$(SHAREDLIB).$(VER): $(OBJS)
+       $(LDSHARED) -o $@ $(OBJS)
+       rm -f $(SHAREDLIB) $(SHAREDLIB).1
+       ln -s $@ $(SHAREDLIB)
+       ln -s $@ $(SHAREDLIB).1
+
+example: example.o $(LIBS)
+       $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o $(LIBS)
+       $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+       -@if [ ! -d $(includedir)  ]; then mkdir $(includedir); fi
+       -@if [ ! -d $(libdir) ]; then mkdir $(libdir); fi
+       cp zlib.h zconf.h $(includedir)
+       chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+       cp $(LIBS) $(libdir)
+       cd $(libdir); chmod 755 $(LIBS)
+       -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+       cd $(libdir); if test -f $(SHAREDLIB).$(VER); then \
+         rm -f $(SHAREDLIB) $(SHAREDLIB).1; \
+         ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB); \
+         ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB).1; \
+         (ldconfig || true)  >/dev/null 2>&1; \
+       fi
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+       cd $(includedir); \
+       v=$(VER); \
+       if test -f zlib.h; then \
+         v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`; \
+          rm -f zlib.h zconf.h; \
+       fi; \
+       cd $(libdir); rm -f libz.a; \
+       if test -f $(SHAREDLIB).$$v; then \
+         rm -f $(SHAREDLIB).$$v $(SHAREDLIB) $(SHAREDLIB).1; \
+       fi
+
+clean:
+       rm -f *.o *~ example minigzip libz.a libz.so* foo.gz so_locations \
+          _match.s maketree
+
+distclean:     clean
+
+zip:
+       mv Makefile Makefile~; cp -p Makefile.in Makefile
+       rm -f test.c ztest*.c contrib/minizip/test.zip
+       v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+       zip -ul9 zlib$$v $(DISTFILES)
+       mv Makefile~ Makefile
+
+dist:
+       mv Makefile Makefile~; cp -p Makefile.in Makefile
+       rm -f test.c ztest*.c contrib/minizip/test.zip
+       d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+       rm -f $$d.tar.gz; \
+       if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+       files=""; \
+       for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+       cd ..; \
+       GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+       if test ! -d $$d; then rm -f $$d; fi
+       mv Makefile~ Makefile
+
+tags:  
+       etags *.[ch]
+
+depend:
+       makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o:  zlib.h zconf.h 
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h  
diff --git a/lib/zlib/Makefile.in b/lib/zlib/Makefile.in
new file mode 100644 (file)
index 0000000..3a3b116
--- /dev/null
@@ -0,0 +1,174 @@
+# Makefile for zlib
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile and test, type:
+#   ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+#    make install
+# To install in $HOME instead of /usr/local, use:
+#    make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+#           -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=-L. -lz
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+VER=1.1.3
+LIBS=libz.a
+SHAREDLIB=libz.so
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+includedir = ${prefix}/include
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README FAQ INDEX ChangeLog configure Make*[a-z0-9] *.[ch] *.mms \
+  algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+  nt/Make*[a-z0-9] nt/zlib.dnt amiga/Make*.??? os2/M*.os2 os2/zlib.def \
+  contrib/RE*.contrib contrib/*.txt contrib/asm386/*.asm contrib/asm386/*.c \
+  contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/asm[56]86/*.?86 \
+  contrib/asm[56]86/*.S contrib/iostream/*.cpp \
+  contrib/iostream/*.h  contrib/iostream2/*.h contrib/iostream2/*.cpp \
+  contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 \
+  contrib/minizip/[CM]*[pe] contrib/minizip/*.[ch] contrib/minizip/*.[td]?? \
+  contrib/delphi*/*.???
+
+all: example minigzip
+
+test: all
+       @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+       echo hello world | ./minigzip | ./minigzip -d || \
+         echo '                *** minigzip test FAILED ***' ; \
+       if ./example; then \
+         echo '                *** zlib test OK ***'; \
+       else \
+         echo '                *** zlib test FAILED ***'; \
+       fi
+
+libz.a: $(OBJS) $(OBJA)
+       $(AR) $@ $(OBJS) $(OBJA)
+       -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(CC) -c _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+$(SHAREDLIB).$(VER): $(OBJS)
+       $(LDSHARED) -o $@ $(OBJS)
+       rm -f $(SHAREDLIB) $(SHAREDLIB).1
+       ln -s $@ $(SHAREDLIB)
+       ln -s $@ $(SHAREDLIB).1
+
+example: example.o $(LIBS)
+       $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o $(LIBS)
+       $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+       -@if [ ! -d $(includedir)  ]; then mkdir $(includedir); fi
+       -@if [ ! -d $(libdir) ]; then mkdir $(libdir); fi
+       cp zlib.h zconf.h $(includedir)
+       chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+       cp $(LIBS) $(libdir)
+       cd $(libdir); chmod 755 $(LIBS)
+       -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+       cd $(libdir); if test -f $(SHAREDLIB).$(VER); then \
+         rm -f $(SHAREDLIB) $(SHAREDLIB).1; \
+         ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB); \
+         ln -s $(SHAREDLIB).$(VER) $(SHAREDLIB).1; \
+         (ldconfig || true)  >/dev/null 2>&1; \
+       fi
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+       cd $(includedir); \
+       v=$(VER); \
+       if test -f zlib.h; then \
+         v=`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`; \
+          rm -f zlib.h zconf.h; \
+       fi; \
+       cd $(libdir); rm -f libz.a; \
+       if test -f $(SHAREDLIB).$$v; then \
+         rm -f $(SHAREDLIB).$$v $(SHAREDLIB) $(SHAREDLIB).1; \
+       fi
+
+clean:
+       rm -f *.o *~ example minigzip libz.a libz.so* foo.gz so_locations \
+          _match.s maketree
+
+distclean:     clean
+
+zip:
+       mv Makefile Makefile~; cp -p Makefile.in Makefile
+       rm -f test.c ztest*.c contrib/minizip/test.zip
+       v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+       zip -ul9 zlib$$v $(DISTFILES)
+       mv Makefile~ Makefile
+
+dist:
+       mv Makefile Makefile~; cp -p Makefile.in Makefile
+       rm -f test.c ztest*.c contrib/minizip/test.zip
+       d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+       rm -f $$d.tar.gz; \
+       if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+       files=""; \
+       for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+       cd ..; \
+       GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+       if test ! -d $$d; then rm -f $$d; fi
+       mv Makefile~ Makefile
+
+tags:  
+       etags *.[ch]
+
+depend:
+       makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o:  zlib.h zconf.h 
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h  
diff --git a/lib/zlib/Makefile.riscos b/lib/zlib/Makefile.riscos
new file mode 100644 (file)
index 0000000..d97f449
--- /dev/null
@@ -0,0 +1,151 @@
+# Project:   zlib_1_03
+# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430
+# test works out-of-the-box, installs `somewhere' on demand
+
+# Toolflags:
+CCflags = -c -depend !Depend -IC: -g -throwback  -DRISCOS  -fah 
+C++flags = -c -depend !Depend -IC: -throwback
+Linkflags = -aif -c++ -o $@ 
+ObjAsmflags = -throwback -NoCache -depend !Depend
+CMHGflags = 
+LibFileflags = -c -l -o $@ 
+Squeezeflags = -o $@
+
+# change the line below to where _you_ want the library installed.
+libdest = lib:zlib
+
+# Final targets:
+@.lib:   @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \
+        @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \
+        @.o.uncompr @.o.zutil 
+        LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \
+        @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \
+        @.o.trees @.o.uncompr @.o.zutil 
+test:   @.minigzip @.example @.lib
+       @copy @.lib @.libc  A~C~DF~L~N~P~Q~RS~TV
+       @echo running tests: hang on.
+       @/@.minigzip -f -9 libc
+       @/@.minigzip -d libc-gz
+       @/@.minigzip -f -1 libc
+       @/@.minigzip -d libc-gz
+       @/@.minigzip -h -9 libc
+       @/@.minigzip -d libc-gz
+       @/@.minigzip -h -1 libc
+       @/@.minigzip -d libc-gz
+       @/@.minigzip -9 libc
+       @/@.minigzip -d libc-gz
+       @/@.minigzip -1 libc
+       @/@.minigzip -d libc-gz
+       @diff @.lib @.libc
+       @echo that should have reported '@.lib and @.libc identical' if you have diff.
+       @/@.example @.fred @.fred
+       @echo that will have given lots of hello!'s.
+
+@.minigzip:   @.o.minigzip @.lib C:o.Stubs 
+        Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs 
+@.example:   @.o.example @.lib C:o.Stubs 
+        Link $(Linkflags) @.o.example @.lib C:o.Stubs
+
+install: @.lib
+       cdir $(libdest)
+       cdir $(libdest).h
+       @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV
+       @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV
+       @copy @.lib $(libdest).lib  A~C~DF~L~N~P~Q~RS~TV
+       @echo okay, installed zlib in $(libdest)
+
+clean:; remove @.minigzip
+       remove @.example
+       remove @.libc
+       -wipe @.o.* F~r~cV
+       remove @.fred
+
+# User-editable dependencies:
+.c.o:
+        cc $(ccflags) -o $@ $<
+
+# Static dependencies:
+
+# Dynamic dependencies:
+o.example:     c.example
+o.example:     h.zlib
+o.example:     h.zconf
+o.minigzip:    c.minigzip
+o.minigzip:    h.zlib
+o.minigzip:    h.zconf
+o.adler32:     c.adler32
+o.adler32:     h.zlib
+o.adler32:     h.zconf
+o.compress:    c.compress
+o.compress:    h.zlib
+o.compress:    h.zconf
+o.crc32:       c.crc32
+o.crc32:       h.zlib
+o.crc32:       h.zconf
+o.deflate:     c.deflate
+o.deflate:     h.deflate
+o.deflate:     h.zutil
+o.deflate:     h.zlib
+o.deflate:     h.zconf
+o.gzio:        c.gzio
+o.gzio:        h.zutil
+o.gzio:        h.zlib
+o.gzio:        h.zconf
+o.infblock:    c.infblock
+o.infblock:    h.zutil
+o.infblock:    h.zlib
+o.infblock:    h.zconf
+o.infblock:    h.infblock
+o.infblock:    h.inftrees
+o.infblock:    h.infcodes
+o.infblock:    h.infutil
+o.infcodes:    c.infcodes
+o.infcodes:    h.zutil
+o.infcodes:    h.zlib
+o.infcodes:    h.zconf
+o.infcodes:    h.inftrees
+o.infcodes:    h.infblock
+o.infcodes:    h.infcodes
+o.infcodes:    h.infutil
+o.infcodes:    h.inffast
+o.inffast:     c.inffast
+o.inffast:     h.zutil
+o.inffast:     h.zlib
+o.inffast:     h.zconf
+o.inffast:     h.inftrees
+o.inffast:     h.infblock
+o.inffast:     h.infcodes
+o.inffast:     h.infutil
+o.inffast:     h.inffast
+o.inflate:     c.inflate
+o.inflate:     h.zutil
+o.inflate:     h.zlib
+o.inflate:     h.zconf
+o.inflate:     h.infblock
+o.inftrees:    c.inftrees
+o.inftrees:    h.zutil
+o.inftrees:    h.zlib
+o.inftrees:    h.zconf
+o.inftrees:    h.inftrees
+o.inftrees:    h.inffixed
+o.infutil:     c.infutil
+o.infutil:     h.zutil
+o.infutil:     h.zlib
+o.infutil:     h.zconf
+o.infutil:     h.infblock
+o.infutil:     h.inftrees
+o.infutil:     h.infcodes
+o.infutil:     h.infutil
+o.trees:       c.trees
+o.trees:       h.deflate
+o.trees:       h.zutil
+o.trees:       h.zlib
+o.trees:       h.zconf
+o.trees:       h.trees
+o.uncompr:     c.uncompr
+o.uncompr:     h.zlib
+o.uncompr:     h.zconf
+o.zutil:       c.zutil
+o.zutil:       h.zutil
+o.zutil:       h.zlib
+o.zutil:       h.zconf
diff --git a/lib/zlib/README b/lib/zlib/README
new file mode 100644 (file)
index 0000000..8ff4587
--- /dev/null
@@ -0,0 +1,148 @@
+zlib 1.1.3 is a general purpose data compression library.  All the code
+is thread safe.  The data format used by the zlib library
+is described by RFCs (Request for Comments) 1950 to 1952 in the files 
+ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format). These documents are also available in
+other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact jloup@gzip.org). A usage
+example of the library is given in the file example.c which also tests that
+the library is working correctly. Another example is given in the file
+minigzip.c. The compression library itself is composed of all source files
+except example.c and minigzip.c.
+
+To compile all files and run the test program, follow the instructions
+given at the top of Makefile. In short "make test; make install"
+should work for most machines. For Unix: "configure; make test; make install"
+For MSDOS, use one of the special makefiles such as Makefile.msc.
+For VMS, use Make_vms.com or descrip.mms.
+
+Questions about zlib should be sent to <zlib@quest.jpl.nasa.gov>, or to
+Gilles Vollant <info@winimage.com> for the Windows DLL version.
+The zlib home page is http://www.cdrom.com/pub/infozip/zlib/
+The official zlib ftp site is ftp://ftp.cdrom.com/pub/infozip/zlib/
+Before reporting a problem, please check those sites to verify that
+you have the latest version of zlib; otherwise get the latest version and
+check whether the problem still exists or not.
+
+Mark Nelson <markn@tiny.com> wrote an article about zlib for the Jan. 1997
+issue of  Dr. Dobb's Journal; a copy of the article is available in
+http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.1.3 are documented in the file ChangeLog.
+The main changes since 1.1.2 are:
+
+- fix "an inflate input buffer bug that shows up on rare but persistent
+  occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+  (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+  See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+plus many changes for portability.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit 1.1
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+See the zlib home page http://www.cdrom.com/pub/infozip/zlib/ for details.
+
+A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
+is in the CPAN (Comprehensive Perl Archive Network) sites, such as:
+ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib*
+
+A Python interface to zlib written by A.M. Kuchling <amk@magnet.com>
+is available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com>
+is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html
+
+An experimental package to read and write files in .zip format,
+written on top of zlib by Gilles Vollant <info@winimage.com>, is
+available at http://www.winimage.com/zLibDll/unzip.html
+and also in the contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
+  and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
+  The zlib DLL support was initially done by Alessandro Iacopetti and is
+  now maintained by Gilles Vollant <info@winimage.com>. Check the zlib DLL
+  home page at http://www.winimage.com/zLibDll
+
+  From Visual Basic, you can call the DLL functions which do not take
+  a structure as argument: compress, uncompress and all gz* functions.
+  See contrib/visual-basic.txt for more information, or get
+  http://www.tcfb.com/dowseware/cmp-z-it.zip
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization.
+  With -O, one libpng test fails. The test works in 32 bit mode (with
+  the -n32 compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1   
+  it works when compiled with cc.
+
+- on Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1
+  is necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works
+  with other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For Turbo C the small model is supported only with reduced performance to
+  avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+
+- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html
+  Per Harald Myrvang <perm@stud.cs.uit.no>
+
+
+Acknowledgments:
+
+  The deflate format used by zlib was defined by Phil Katz. The deflate
+  and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+  people who reported problems and suggested various improvements in zlib;
+  they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind.  The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes.
diff --git a/lib/zlib/adler32.c b/lib/zlib/adler32.c
new file mode 100644 (file)
index 0000000..16cf9a7
--- /dev/null
@@ -0,0 +1,48 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+           buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+           s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff --git a/lib/zlib/algorithm.txt b/lib/zlib/algorithm.txt
new file mode 100644 (file)
index 0000000..cdc830b
--- /dev/null
@@ -0,0 +1,213 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data.  The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length).  Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes.  (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The real question is, given a Huffman tree, how to decode fast.  The most
+important realization is that shorter codes are much more common than
+longer codes, so pay attention to decoding the short codes fast, and let
+the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code.  It gets that many bits from the
+stream, and looks it up in the table.  The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table.  If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code.  However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table.  What inflate() does is
+simply to make the number of bits in the first table a variable, and set it
+for the maximum speed.
+
+inflate() sends new trees relatively often, so it is possibly set for a
+smaller first level table than an application that has only one tree for
+all the data.  For inflate, which has 286 possible codes for the
+literal/length tree, the size of the first table is nine bits.  Also the
+distance trees have 30 possible values, and the size of the first table is
+six bits.  Note that for each of those cases, the table ended up one bit
+longer than the ``average'' code length, i.e. the code length of an
+approximately flat code which would be a little more than eight bits for
+286 symbols and a little less than five bits for 30 symbols.  It would be
+interesting to see if optimizing the first level table for other
+applications gave values within a bit or two of the flat code size.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually  
+looks like.  You are correct that it's not a Huffman tree.  It is simply a  
+lookup table for the first, let's say, nine bits of a Huffman symbol.  The  
+symbol could be as short as one bit or as long as 15 bits.  If a particular  
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits.  For example, if the  
+symbol is four bits, then it's duplicated 32 times in a nine-bit table.  If a  
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points  
+to another similar table for the remaining bits.  Again, there are duplicated  
+entries as needed.  The idea is that most of the time the symbol will be short
+and there will only be one table look up.  (That's whole idea behind data  
+compression in the first place.)  For the less frequent long symbols, there  
+will be two lookups.  If you had a compression method with really long  
+symbols, you could have as many levels of lookups as is efficient.  For  
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in  
+the above example are gobbled), or it contains the translation for the symbol  
+and the number of bits to gobble.  Then you start again with the next  
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the  
+longest symbol is?  The reason is that if you do that, you end up spending  
+more time filling in duplicate symbol entries than you do actually decoding.   
+At least for deflate's output that generates new trees every several 10's of  
+kbytes.  You can imagine that filling in a 2^15 entry table for a 15-bit code  
+would take too long if you're only decoding several thousand symbols.  At the  
+other extreme, you could make a new table for every bit in the code.  In fact,
+that's essentially a Huffman tree.  But then you spend two much time  
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to  
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode to and how many bits that is, i.e. how  
+many bits to gobble.  Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six  
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to  
+be constructed.  That's compared to 64 entries for a single table.  Or  
+compared to 16 entries for a Huffman tree (six two entry tables and one four  
+entry table).  Assuming that the code ideally represents the probability of  
+the symbols, it takes on the average 1.25 lookups per symbol.  That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the  
+Huffman tree.
+
+There, I think that gives you a picture of what's going on.  For inflate, the  
+meaning of a particular symbol is often more than just a letter.  It can be a  
+byte (a "literal"), or it can be either a length or a distance which  
+indicates a base value and a number of bits to fetch after the code that is  
+added to the base value.  Or it might be the special end-of-block code.  The  
+data structures created in inftrees.c try to encode all that information  
+compactly in the tables.
+
+
+Jean-loup Gailly        Mark Adler
+jloup@gzip.org          madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+ftp://ds.internic.net/rfc/rfc1951.txt
diff --git a/lib/zlib/amiga/Makefile.pup b/lib/zlib/amiga/Makefile.pup
new file mode 100644 (file)
index 0000000..6cfad1d
--- /dev/null
@@ -0,0 +1,66 @@
+# Amiga powerUP (TM) Makefile
+# makefile for libpng and SAS C V6.58/7.00 PPC compiler
+# Copyright (C) 1998 by Andreas R. Kleinert
+
+CC       = scppc
+CFLAGS   = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \
+           OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8
+LIBNAME  = libzip.a
+AR       = ppc-amigaos-ar
+AR_FLAGS = cr
+RANLIB   = ppc-amigaos-ranlib
+LDFLAGS  = -r -o
+LDLIBS   = LIB:scppc.a
+LN       = ppc-amigaos-ld
+RM       = delete quiet
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example minigzip
+
+test: all
+        example
+        echo hello world | minigzip | minigzip -d
+
+$(LIBNAME): $(OBJS)
+            $(AR) $(AR_FLAGS) $@ $(OBJS)
+            $(RANLIB) $@
+
+example: example.o $(LIBNAME)
+        $(LN) $(LDFLAGS) example LIB:c_ppc.o example.o $(LIBNAME) $(LDLIBS) LIB:end.o
+
+minigzip: minigzip.o $(LIBNAME)
+        $(LN) $(LDFLAGS) minigzip LIB:c_ppc.o minigzip.o $(LIBNAME) $(LDLIBS) LIB:end.o
+
+clean:
+        $(RM) *.o example minigzip $(LIBNAME) foo.gz
+
+zip:
+        zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \
+          descrip.mms *.[ch]
+
+tgz:
+        cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \
+          zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zutil.h zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.o: zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/lib/zlib/amiga/Makefile.sas b/lib/zlib/amiga/Makefile.sas
new file mode 100644 (file)
index 0000000..5323e82
--- /dev/null
@@ -0,0 +1,64 @@
+# SMakefile for zlib
+# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
+# Osma Ahvenlampi <Osma.Ahvenlampi@hut.fi>
+# Amiga, SAS/C 6.56 & Smake
+
+CC=sc
+CFLAGS=OPT
+#CFLAGS=OPT CPU=68030
+#CFLAGS=DEBUG=LINE
+LDFLAGS=LIB z.lib
+
+SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
+       NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX 
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: SCOPTIONS example minigzip
+
+test: all
+       `cd`/example
+       echo hello world | minigzip | minigzip -d 
+
+install: z.lib
+       copy zlib.h zconf.h INCLUDE: clone
+       copy z.lib LIB: clone
+
+z.lib: $(OBJS)
+       oml z.lib r $(OBJS)
+
+example: example.o z.lib
+       $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o z.lib
+       $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
+
+clean:
+       -delete force quiet *.o example minigzip z.lib foo.gz *.lnk SCOPTIONS
+
+SCOPTIONS: Smakefile
+        copy to $@ <from <
+$(SCOPTIONS)
+<
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zutil.h zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.o: zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/lib/zlib/compress.c b/lib/zlib/compress.c
new file mode 100644 (file)
index 0000000..1cee470
--- /dev/null
@@ -0,0 +1,68 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
diff --git a/lib/zlib/configure b/lib/zlib/configure
new file mode 100755 (executable)
index 0000000..e894235
--- /dev/null
@@ -0,0 +1,212 @@
+#!/bin/sh
+# configure script for zlib. This script is needed only if
+# you wish to build a shared library and your system supports them,
+# of if you need special compiler, flags or install directory.
+# Otherwise, you can just use directly "make test; make install"
+#
+# To create a shared library, use "configure --shared"; by default a static
+# library is created. If the primitive shared library support provided here
+# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz
+#
+# To impose specific compiler or flags or install directory, use for example:
+#    prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+#    (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+# LDSHARED is the command to be used to create a shared library
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+LIBS=libz.a
+SHAREDLIB=libz.so
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+AR=${AR-"ar rc"}
+RANLIB=${RANLIB-"ranlib"}
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+includedir=${includedir-'${prefix}/include'}
+shared_ext='.so'
+shared=0
+gcc=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+
+while test $# -ge 1
+do
+case "$1" in
+    -h* | --h*)
+      echo 'usage:'
+      echo '  configure [--shared] [--prefix=PREFIX]  [--exec_prefix=EXPREFIX]'
+      echo '     [--libdir=LIBDIR] [--includedir=INCLUDEDIR]'
+        exit 0;;
+    -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+    -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+    -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+    -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;;
+    -p* | --p*) prefix="$2"; shift; shift;;
+    -e* | --e*) exec_prefix="$2"; shift; shift;;
+    -l* | --l*) libdir="$2"; shift; shift;;
+    -i* | --i*) includedir="$2"; shift; shift;;
+    -s* | --s*) shared=1; shift;;
+    esac
+done
+
+test=ztest$$
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+
+test -z "$CC" && echo Checking for gcc...
+cc=${CC-gcc}
+cflags=${CFLAGS-"-O3"}
+# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
+case "$cc" in
+  *gcc*) gcc=1;;
+esac
+
+if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then
+  CC="$cc"
+  SFLAGS=${CFLAGS-"-fPIC -O3"}
+  CFLAGS="$cflags"
+  case `(uname -s || echo unknown) 2>/dev/null` in
+  Linux | linux) LDSHARED=${LDSHARED-"gcc -shared -Wl,-soname,libz.so.1"};;
+  *)             LDSHARED=${LDSHARED-"gcc -shared"};;
+  esac
+else
+  # find system name and corresponding cc options
+  CC=${CC-cc}
+  case `(uname -sr || echo unknown) 2>/dev/null` in
+  HP-UX*)    SFLAGS=${CFLAGS-"-O +z"}
+            CFLAGS=${CFLAGS-"-O"}
+#           LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+            LDSHARED=${LDSHARED-"ld -b"}
+            shared_ext='.sl'
+            SHAREDLIB='libz.sl';;
+  IRIX*)     SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+            CFLAGS=${CFLAGS-"-ansi -O2"}
+            LDSHARED=${LDSHARED-"cc -shared"};;
+  OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+            CFLAGS=${CFLAGS-"-O -std1"}
+            LDSHARED=${LDSHARED-"cc -shared  -Wl,-soname,$SHAREDLIB -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};;
+  OSF1*)     SFLAGS=${CFLAGS-"-O -std1"}
+            CFLAGS=${CFLAGS-"-O -std1"}
+            LDSHARED=${LDSHARED-"cc -shared"};;
+  QNX*)      SFLAGS=${CFLAGS-"-4 -O"}
+             CFLAGS=${CFLAGS-"-4 -O"}
+            LDSHARED=${LDSHARED-"cc"}
+             RANLIB=${RANLIB-"true"}
+             AR="cc -A";;
+  SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+            CFLAGS=${CFLAGS-"-O3"}
+            LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
+  SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
+             CFLAGS=${CFLAGS-"-fast -xcg89"}
+            LDSHARED=${LDSHARED-"cc -G"};;
+  SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+            CFLAGS=${CFLAGS-"-O2"}
+            LDSHARED=${LDSHARED-"ld"};;
+  UNIX_System_V\ 4.2.0) 
+            SFLAGS=${CFLAGS-"-KPIC -O"}
+            CFLAGS=${CFLAGS-"-O"}
+            LDSHARED=${LDSHARED-"cc -G"};;
+  UNIX_SV\ 4.2MP)
+            SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+            CFLAGS=${CFLAGS-"-O"}
+            LDSHARED=${LDSHARED-"cc -G"};;
+  # send working options for other systems to support@gzip.org
+  *)         SFLAGS=${CFLAGS-"-O"}
+            CFLAGS=${CFLAGS-"-O"}
+            LDSHARED=${LDSHARED-"cc -shared"};;
+  esac
+fi
+
+if test $shared -eq 1; then
+  echo Checking for shared library support...
+  # we must test in two steps (cc then ld), required at least on SunOS 4.x
+  if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
+     test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then
+    CFLAGS="$SFLAGS"
+    LIBS="$SHAREDLIB.$VER"
+    echo Building shared library $SHAREDLIB.$VER with $CC.
+  elif test -z "$old_cc" -a -z "$old_cflags"; then
+    echo No shared library suppport.
+    shared=0;
+  else
+    echo 'No shared library suppport; try without defining CC and CFLAGS'
+    shared=0;
+  fi
+fi
+if test $shared -eq 0; then
+  LDSHARED="$CC"
+  echo Building static library $LIBS version $VER with $CC.
+fi
+
+cat > $test.c <<EOF
+#include <unistd.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+  CFLAGS="$CFLAGS -DHAVE_UNISTD_H"
+  echo "Checking for unistd.h... Yes."
+else
+  echo "Checking for unistd.h... No."
+fi
+
+cat > $test.c <<EOF
+#include <errno.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+  echo "Checking for errno.h...         Yes."
+else
+  echo "Checking for errno.h...         No."
+  CFLAGS="$CFLAGS -DNO_ERRNO_H"
+fi
+
+cat > $test.c <<EOF
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+caddr_t hello() {
+  return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0); 
+}
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+  CFLAGS="$CFLAGS -DUSE_MMAP"
+  echo Checking for mmap support... Yes.
+else
+  echo Checking for mmap support... No.
+fi
+
+CPP=${CPP-"$CC -E"}
+case $CFLAGS in
+  *ASMV*)
+    if test "`nm $test.o | grep _hello`" = ""; then
+      CPP="$CPP -DNO_UNDERLINE"
+      echo Checking for underline in external names... No.
+    else
+      echo Checking for underline in external names... Yes.
+    fi;;
+esac
+
+rm -f $test.[co] $test$shared_ext
+
+# udpate Makefile
+sed < Makefile.in "
+/^CC *=/s%=.*%=$CC%
+/^CFLAGS *=/s%=.*%=$CFLAGS%
+/^CPP *=/s%=.*%=$CPP%
+/^LDSHARED *=/s%=.*%=$LDSHARED%
+/^LIBS *=/s%=.*%=$LIBS%
+/^SHAREDLIB *=/s%=.*%=$SHAREDLIB%
+/^AR *=/s%=.*%=$AR%
+/^RANLIB *=/s%=.*%=$RANLIB%
+/^VER *=/s%=.*%=$VER%
+/^prefix *=/s%=.*%=$prefix%
+/^exec_prefix *=/s%=.*%=$exec_prefix%
+/^libdir *=/s%=.*%=$libdir%
+/^includedir *=/s%=.*%=$includedir%
+" > Makefile
diff --git a/lib/zlib/contrib/README.contrib b/lib/zlib/contrib/README.contrib
new file mode 100644 (file)
index 0000000..7ad191c
--- /dev/null
@@ -0,0 +1,34 @@
+All files under this contrib directory are UNSUPPORTED. There were
+provided by users of zlib and were not tested by the authors of zlib.
+Use at your own risk. Please contact the authors of the contributions
+for help about these, not the zlib authors. Thanks.
+
+
+asm386/     by Gilles Vollant <info@winimage.com>
+       386 asm code replacing longest_match(), for Visual C++ 4.2 and ML 6.11c
+
+asm586/ and asm686/    by Brian Raiter <breadbox@muppetlabs.com> 
+        asm code for Pentium and Pentium Pro
+        See http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+delphi/      by Bob Dellaca <bobdl@xtra.co.nz>
+       Support for Delphi
+
+delphi2/     by Davide Moretti <dave@rimini.com>
+        Another support for C++Builder and Delphi
+
+minizip/    by Gilles Vollant <info@winimage.com>
+       Mini zip and unzip based on zlib
+        See http://www.winimage.com/zLibDll/unzip.html
+
+iostream/   by Kevin Ruland <kevin@rodin.wustl.edu>
+        A C++ I/O streams interface to the zlib gz* functions
+
+iostream2/  by Tyge Løvset <Tyge.Lovset@cmr.no>
+       Another C++ I/O streams interface
+
+untgz/      by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+       A very simple tar.gz file extractor using zlib
+
+visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+        How to use compress(), uncompress() and the gz* functions from VB.
diff --git a/lib/zlib/contrib/asm386/gvmat32.asm b/lib/zlib/contrib/asm386/gvmat32.asm
new file mode 100644 (file)
index 0000000..28d527f
--- /dev/null
@@ -0,0 +1,559 @@
+;
+; gvmat32.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.
+; File written by Gilles Vollant, by modifiying the longest_match
+;  from Jean-loup Gailly in deflate.c
+; It need wmask == 0x7fff
+;     (assembly code is faster with a fixed wmask)
+;
+; For Visual C++ 4.2 and ML 6.11c (version in directory \MASM611C of Win95 DDK)
+;   I compile with : "ml /coff /Zi /c gvmat32.asm"
+;
+
+;uInt longest_match_7fff(s, cur_match)
+;    deflate_state *s;
+;    IPos cur_match;                             /* current match */
+
+        NbStack         equ     76
+        cur_match       equ     dword ptr[esp+NbStack-0]
+        str_s           equ     dword ptr[esp+NbStack-4]
+; 5 dword on top (ret,ebp,esi,edi,ebx)
+        adrret          equ     dword ptr[esp+NbStack-8]
+        pushebp         equ     dword ptr[esp+NbStack-12]
+        pushedi         equ     dword ptr[esp+NbStack-16]
+        pushesi         equ     dword ptr[esp+NbStack-20]
+        pushebx         equ     dword ptr[esp+NbStack-24]
+
+        chain_length    equ     dword ptr [esp+NbStack-28]
+        limit           equ     dword ptr [esp+NbStack-32]
+        best_len        equ     dword ptr [esp+NbStack-36]
+        window          equ     dword ptr [esp+NbStack-40]
+        prev            equ     dword ptr [esp+NbStack-44]
+        scan_start      equ      word ptr [esp+NbStack-48]
+        wmask           equ     dword ptr [esp+NbStack-52]
+        match_start_ptr equ     dword ptr [esp+NbStack-56]
+        nice_match      equ     dword ptr [esp+NbStack-60]
+        scan            equ     dword ptr [esp+NbStack-64]
+
+        windowlen       equ     dword ptr [esp+NbStack-68]
+        match_start     equ     dword ptr [esp+NbStack-72]
+        strend          equ     dword ptr [esp+NbStack-76]
+        NbStackAdd      equ     (NbStack-24)
+
+    .386p
+
+    name    gvmatch
+    .MODEL  FLAT
+
+
+
+;  all the +4 offsets are due to the addition of pending_buf_size (in zlib
+;  in the deflate_state structure since the asm code was first written
+;  (if you compile with zlib 1.0.4 or older, remove the +4).
+;  Note : these value are good with a 8 bytes boundary pack structure
+    dep_chain_length    equ     70h+4
+    dep_window          equ     2ch+4
+    dep_strstart        equ     60h+4
+    dep_prev_length     equ     6ch+4
+    dep_nice_match      equ     84h+4
+    dep_w_size          equ     20h+4
+    dep_prev            equ     34h+4
+    dep_w_mask          equ     28h+4
+    dep_good_match      equ     80h+4
+    dep_match_start     equ     64h+4
+    dep_lookahead       equ     68h+4
+
+
+_TEXT                   segment
+
+IFDEF NOUNDERLINE
+                        public  longest_match_7fff
+;                        public  match_init
+ELSE
+                        public  _longest_match_7fff
+;                        public  _match_init
+ENDIF
+
+    MAX_MATCH           equ     258
+    MIN_MATCH           equ     3
+    MIN_LOOKAHEAD       equ     (MAX_MATCH+MIN_MATCH+1)
+
+
+
+IFDEF NOUNDERLINE
+;match_init      proc near
+;                ret
+;match_init      endp
+ELSE
+;_match_init     proc near
+;                ret
+;_match_init     endp
+ENDIF
+
+
+IFDEF NOUNDERLINE
+longest_match_7fff   proc near
+ELSE
+_longest_match_7fff  proc near
+ENDIF
+
+        mov     edx,[esp+4]
+
+
+
+        push    ebp
+        push    edi
+        push    esi
+        push    ebx
+
+        sub     esp,NbStackAdd
+
+; initialize or check the variables used in match.asm.
+        mov     ebp,edx
+
+; chain_length = s->max_chain_length
+; if (prev_length>=good_match) chain_length >>= 2
+        mov     edx,[ebp+dep_chain_length]
+        mov     ebx,[ebp+dep_prev_length]
+        cmp     [ebp+dep_good_match],ebx
+        ja      noshr
+        shr     edx,2
+noshr:
+; we increment chain_length because in the asm, the --chain_lenght is in the beginning of the loop
+        inc     edx
+        mov     edi,[ebp+dep_nice_match]
+        mov     chain_length,edx
+        mov     eax,[ebp+dep_lookahead]
+        cmp     eax,edi
+; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+        jae     nolookaheadnicematch
+        mov     edi,eax
+nolookaheadnicematch:
+; best_len = s->prev_length
+        mov     best_len,ebx
+
+; window = s->window
+        mov     esi,[ebp+dep_window]
+        mov     ecx,[ebp+dep_strstart]
+        mov     window,esi
+
+        mov     nice_match,edi
+; scan = window + strstart
+        add     esi,ecx
+        mov     scan,esi
+; dx = *window
+        mov     dx,word ptr [esi]
+; bx = *(window+best_len-1)
+        mov     bx,word ptr [esi+ebx-1]
+        add     esi,MAX_MATCH-1
+; scan_start = *scan
+        mov     scan_start,dx
+; strend = scan + MAX_MATCH-1
+        mov     strend,esi
+; bx = scan_end = *(window+best_len-1)
+
+;    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;        s->strstart - (IPos)MAX_DIST(s) : NIL;
+
+        mov     esi,[ebp+dep_w_size]
+        sub     esi,MIN_LOOKAHEAD
+; here esi = MAX_DIST(s)
+        sub     ecx,esi
+        ja      nodist
+        xor     ecx,ecx
+nodist:
+        mov     limit,ecx
+
+; prev = s->prev
+        mov     edx,[ebp+dep_prev]
+        mov     prev,edx
+
+;
+        mov     edx,dword ptr [ebp+dep_match_start]
+        mov     bp,scan_start
+        mov     eax,cur_match
+        mov     match_start,edx
+
+        mov     edx,window
+        mov     edi,edx
+        add     edi,best_len
+        mov     esi,prev
+        dec     edi
+; windowlen = window + best_len -1
+        mov     windowlen,edi
+
+        jmp     beginloop2
+        align   4
+
+; here, in the loop
+;       eax = ax = cur_match
+;       ecx = limit
+;        bx = scan_end
+;        bp = scan_start
+;       edi = windowlen (window + best_len -1)
+;       esi = prev
+
+
+;// here; chain_length <=16
+normalbeg0add16:
+        add     chain_length,16
+        jz      exitloop
+normalbeg0:
+        cmp     word ptr[edi+eax],bx
+        je      normalbeg2noroll
+rcontlabnoroll:
+; cur_match = prev[cur_match & wmask]
+        and     eax,7fffh
+        mov     ax,word ptr[esi+eax*2]
+; if cur_match > limit, go to exitloop
+        cmp     ecx,eax
+        jnb     exitloop
+; if --chain_length != 0, go to exitloop
+        dec     chain_length
+        jnz     normalbeg0
+        jmp     exitloop
+
+normalbeg2noroll:
+; if (scan_start==*(cur_match+window)) goto normalbeg2
+        cmp     bp,word ptr[edx+eax]
+        jne     rcontlabnoroll
+        jmp     normalbeg2
+
+contloop3:
+        mov     edi,windowlen
+
+; cur_match = prev[cur_match & wmask]
+        and     eax,7fffh
+        mov     ax,word ptr[esi+eax*2]
+; if cur_match > limit, go to exitloop
+        cmp     ecx,eax
+jnbexitloopshort1:
+        jnb     exitloop
+; if --chain_length != 0, go to exitloop
+
+
+; begin the main loop
+beginloop2:
+        sub     chain_length,16+1
+; if chain_length <=16, don't use the unrolled loop
+        jna     normalbeg0add16
+
+do16:
+        cmp     word ptr[edi+eax],bx
+        je      normalbeg2dc0
+
+maccn   MACRO   lab
+        and     eax,7fffh
+        mov     ax,word ptr[esi+eax*2]
+        cmp     ecx,eax
+        jnb     exitloop
+        cmp     word ptr[edi+eax],bx
+        je      lab
+        ENDM
+
+rcontloop0:
+        maccn   normalbeg2dc1
+
+rcontloop1:
+        maccn   normalbeg2dc2
+
+rcontloop2:
+        maccn   normalbeg2dc3
+
+rcontloop3:
+        maccn   normalbeg2dc4
+
+rcontloop4:
+        maccn   normalbeg2dc5
+
+rcontloop5:
+        maccn   normalbeg2dc6
+
+rcontloop6:
+        maccn   normalbeg2dc7
+
+rcontloop7:
+        maccn   normalbeg2dc8
+
+rcontloop8:
+        maccn   normalbeg2dc9
+
+rcontloop9:
+        maccn   normalbeg2dc10
+
+rcontloop10:
+        maccn   short normalbeg2dc11
+
+rcontloop11:
+        maccn   short normalbeg2dc12
+
+rcontloop12:
+        maccn   short normalbeg2dc13
+
+rcontloop13:
+        maccn   short normalbeg2dc14
+
+rcontloop14:
+        maccn   short normalbeg2dc15
+
+rcontloop15:
+        and     eax,7fffh
+        mov     ax,word ptr[esi+eax*2]
+        cmp     ecx,eax
+        jnb     exitloop
+
+        sub     chain_length,16
+        ja      do16
+        jmp     normalbeg0add16
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+normbeg MACRO   rcontlab,valsub
+; if we are here, we know that *(match+best_len-1) == scan_end
+        cmp     bp,word ptr[edx+eax]
+; if (match != scan_start) goto rcontlab
+        jne     rcontlab
+; calculate the good chain_length, and we'll compare scan and match string
+        add     chain_length,16-valsub
+        jmp     iseq
+        ENDM
+
+
+normalbeg2dc11:
+        normbeg rcontloop11,11
+
+normalbeg2dc12:
+        normbeg short rcontloop12,12
+
+normalbeg2dc13:
+        normbeg short rcontloop13,13
+
+normalbeg2dc14:
+        normbeg short rcontloop14,14
+
+normalbeg2dc15:
+        normbeg short rcontloop15,15
+
+normalbeg2dc10:
+        normbeg rcontloop10,10
+
+normalbeg2dc9:
+        normbeg rcontloop9,9
+
+normalbeg2dc8:
+        normbeg rcontloop8,8
+
+normalbeg2dc7:
+        normbeg rcontloop7,7
+
+normalbeg2dc6:
+        normbeg rcontloop6,6
+
+normalbeg2dc5:
+        normbeg rcontloop5,5
+
+normalbeg2dc4:
+        normbeg rcontloop4,4
+
+normalbeg2dc3:
+        normbeg rcontloop3,3
+
+normalbeg2dc2:
+        normbeg rcontloop2,2
+
+normalbeg2dc1:
+        normbeg rcontloop1,1
+
+normalbeg2dc0:
+        normbeg rcontloop0,0
+
+
+; we go in normalbeg2 because *(ushf*)(match+best_len-1) == scan_end
+
+normalbeg2:
+        mov     edi,window
+
+        cmp     bp,word ptr[edi+eax]
+        jne     contloop3                   ; if *(ushf*)match != scan_start, continue
+
+iseq:
+; if we are here, we know that *(match+best_len-1) == scan_end
+; and (match == scan_start)
+
+        mov     edi,edx
+        mov     esi,scan                    ; esi = scan
+        add     edi,eax                     ; edi = window + cur_match = match
+
+        mov     edx,[esi+3]                 ; compare manually dword at match+3
+        xor     edx,[edi+3]                 ; and scan +3
+
+        jz      begincompare                ; if equal, go to long compare
+
+; we will determine the unmatch byte and calculate len (in esi)
+        or      dl,dl
+        je      eq1rr
+        mov     esi,3
+        jmp     trfinval
+eq1rr:
+        or      dx,dx
+        je      eq1
+
+        mov     esi,4
+        jmp     trfinval
+eq1:
+        and     edx,0ffffffh
+        jz      eq11
+        mov     esi,5
+        jmp     trfinval
+eq11:
+        mov     esi,6
+        jmp     trfinval
+
+begincompare:
+        ; here we now scan and match begin same
+        add     edi,6
+        add     esi,6
+        mov     ecx,(MAX_MATCH-(2+4))/4     ; scan for at most MAX_MATCH bytes
+        repe    cmpsd                       ; loop until mismatch
+
+        je      trfin                       ; go to trfin if not unmatch
+; we determine the unmatch byte
+        sub     esi,4
+        mov     edx,[edi-4]
+        xor     edx,[esi]
+
+        or      dl,dl
+        jnz     trfin
+        inc     esi
+
+        or      dx,dx
+        jnz     trfin
+        inc     esi
+
+        and     edx,0ffffffh
+        jnz     trfin
+        inc     esi
+
+trfin:
+        sub     esi,scan          ; esi = len
+trfinval:
+; here we have finised compare, and esi contain len of equal string
+        cmp     esi,best_len        ; if len > best_len, go newbestlen
+        ja      short newbestlen
+; now we restore edx, ecx and esi, for the big loop
+        mov     esi,prev
+        mov     ecx,limit
+        mov     edx,window
+        jmp     contloop3
+
+newbestlen:
+        mov     best_len,esi        ; len become best_len
+
+        mov     match_start,eax     ; save new position as match_start
+        cmp     esi,nice_match      ; if best_len >= nice_match, exit
+        jae     exitloop
+        mov     ecx,scan
+        mov     edx,window          ; restore edx=window
+        add     ecx,esi
+        add     esi,edx
+
+        dec     esi
+        mov     windowlen,esi       ; windowlen = window + best_len-1
+        mov     bx,[ecx-1]          ; bx = *(scan+best_len-1) = scan_end
+
+; now we restore ecx and esi, for the big loop :
+        mov     esi,prev
+        mov     ecx,limit
+        jmp     contloop3
+
+exitloop:
+; exit : s->match_start=match_start
+        mov     ebx,match_start
+        mov     ebp,str_s
+        mov     ecx,best_len
+        mov     dword ptr [ebp+dep_match_start],ebx        
+        mov     eax,dword ptr [ebp+dep_lookahead]
+        cmp     ecx,eax
+        ja      minexlo
+        mov     eax,ecx
+minexlo:
+; return min(best_len,s->lookahead)
+        
+; restore stack and register ebx,esi,edi,ebp
+        add     esp,NbStackAdd
+
+        pop     ebx
+        pop     esi
+        pop     edi
+        pop     ebp
+        ret
+InfoAuthor:
+; please don't remove this string !
+; Your are free use gvmat32 in any fre or commercial apps if you don't remove the string in the binary!
+        db     0dh,0ah,"GVMat32 optimised assembly code written 1996-98 by Gilles Vollant",0dh,0ah
+
+
+
+IFDEF NOUNDERLINE
+longest_match_7fff   endp
+ELSE
+_longest_match_7fff  endp
+ENDIF
+
+
+IFDEF NOUNDERLINE
+cpudetect32     proc near
+ELSE
+_cpudetect32    proc near
+ENDIF
+
+
+       pushfd                  ; push original EFLAGS
+       pop     eax             ; get original EFLAGS
+       mov     ecx, eax        ; save original EFLAGS
+       xor     eax, 40000h     ; flip AC bit in EFLAGS
+       push    eax             ; save new EFLAGS value on stack
+       popfd                   ; replace current EFLAGS value
+       pushfd                  ; get new EFLAGS
+       pop     eax             ; store new EFLAGS in EAX
+       xor     eax, ecx        ; can\92t toggle AC bit, processor=80386
+       jz      end_cpu_is_386  ; jump if 80386 processor
+       push    ecx
+       popfd                   ; restore AC bit in EFLAGS first
+
+       pushfd
+       pushfd
+       pop     ecx
+                       
+       mov     eax, ecx        ; get original EFLAGS
+       xor     eax, 200000h    ; flip ID bit in EFLAGS
+       push    eax             ; save new EFLAGS value on stack
+       popfd                   ; replace current EFLAGS value
+       pushfd                  ; get new EFLAGS
+       pop             eax                 ; store new EFLAGS in EAX
+       popfd                   ; restore original EFLAGS
+       xor             eax, ecx        ; can\92t toggle ID bit,
+       je              is_old_486              ; processor=old
+
+       mov     eax,1
+       db      0fh,0a2h        ;CPUID   
+
+exitcpudetect:
+       ret
+
+end_cpu_is_386:
+       mov     eax,0300h
+       jmp     exitcpudetect
+
+is_old_486:
+       mov     eax,0400h
+       jmp     exitcpudetect
+
+IFDEF NOUNDERLINE
+cpudetect32     endp
+ELSE
+_cpudetect32    endp
+ENDIF
+
+_TEXT   ends
+end
diff --git a/lib/zlib/contrib/asm386/gvmat32c.c b/lib/zlib/contrib/asm386/gvmat32c.c
new file mode 100644 (file)
index 0000000..d853bb7
--- /dev/null
@@ -0,0 +1,200 @@
+/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86
+ * Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant.
+ * File written by Gilles Vollant, by modifiying the longest_match
+ *  from Jean-loup Gailly in deflate.c
+ *  it prepare all parameters and call the assembly longest_match_gvasm
+ *  longest_match execute standard C code is wmask != 0x7fff
+ *     (assembly code is faster with a fixed wmask)
+ *
+ */
+
+#include "deflate.h"
+
+#undef FAR
+#include <windows.h>
+
+#ifdef ASMV
+#define NIL 0
+
+#define UNALIGNED_OK
+
+
+/* if your C compiler don't add underline before function name,
+               define ADD_UNDERLINE_ASMFUNC */
+#ifdef ADD_UNDERLINE_ASMFUNC
+#define longest_match_7fff _longest_match_7fff
+#endif
+
+
+
+void match_init()
+{
+}
+
+unsigned long cpudetect32();
+
+uInt longest_match_c(
+    deflate_state *s,
+    IPos cur_match);                             /* current match */
+
+
+uInt longest_match_7fff(
+    deflate_state *s,
+    IPos cur_match);                             /* current match */
+
+uInt longest_match(
+    deflate_state *s,
+    IPos cur_match)                             /* current match */
+{
+       static uInt iIsPPro=2;
+
+    if ((s->w_mask == 0x7fff) && (iIsPPro==0))
+        return longest_match_7fff(s,cur_match);
+
+       if (iIsPPro==2)
+               iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0;
+
+       return longest_match_c(s,cur_match);
+}
+
+
+
+uInt longest_match_c(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+
+#endif /* ASMV */
diff --git a/lib/zlib/contrib/asm386/mkgvmt32.bat b/lib/zlib/contrib/asm386/mkgvmt32.bat
new file mode 100644 (file)
index 0000000..6c5ffd7
--- /dev/null
@@ -0,0 +1 @@
+c:\masm611\bin\ml /coff /Zi /c /Flgvmat32.lst gvmat32.asm
diff --git a/lib/zlib/contrib/asm386/zlibvc.def b/lib/zlib/contrib/asm386/zlibvc.def
new file mode 100644 (file)
index 0000000..7e9d60d
--- /dev/null
@@ -0,0 +1,74 @@
+LIBRARY                "zlib"
+
+DESCRIPTION    '"""zlib data compression library"""'
+
+
+VERSION                1.11
+
+
+HEAPSIZE       1048576,8192
+
+EXPORTS
+    adler32                        @1
+    compress                       @2
+    crc32                          @3
+    deflate                        @4
+    deflateCopy                    @5
+    deflateEnd                     @6
+    deflateInit2_                  @7
+    deflateInit_                   @8
+    deflateParams                  @9
+    deflateReset                   @10
+    deflateSetDictionary           @11
+    gzclose                        @12
+    gzdopen                        @13
+    gzerror                        @14
+    gzflush                        @15
+    gzopen                         @16
+    gzread                         @17
+    gzwrite                        @18
+    inflate                        @19
+    inflateEnd                     @20
+    inflateInit2_                  @21
+    inflateInit_                   @22
+    inflateReset                   @23
+    inflateSetDictionary           @24
+    inflateSync                    @25
+    uncompress                     @26
+    zlibVersion                    @27
+    gzprintf                       @28
+    gzputc                         @29
+    gzgetc                         @30
+    gzseek                         @31
+    gzrewind                       @32
+    gztell                         @33
+    gzeof                          @34
+    gzsetparams                    @35
+    zError                         @36
+    inflateSyncPoint               @37
+    get_crc_table                  @38
+    compress2                      @39
+    gzputs                         @40
+    gzgets                         @41
+
+       unzOpen                       @61
+       unzClose                      @62
+       unzGetGlobalInfo              @63
+       unzGetCurrentFileInfo         @64
+       unzGoToFirstFile              @65
+       unzGoToNextFile               @66
+       unzOpenCurrentFile            @67
+       unzReadCurrentFile            @68
+       unztell                       @70
+       unzeof                        @71
+       unzCloseCurrentFile           @72
+       unzGetGlobalComment           @73
+       unzStringFileNameCompare      @74
+       unzLocateFile                 @75
+       unzGetLocalExtrafield         @76
+
+       zipOpen                       @80
+       zipOpenNewFileInZip           @81
+       zipWriteInFileInZip           @82
+       zipCloseFileInZip             @83
+       zipClose                      @84
diff --git a/lib/zlib/contrib/asm386/zlibvc.dsp b/lib/zlib/contrib/asm386/zlibvc.dsp
new file mode 100644 (file)
index 0000000..a70d4d4
--- /dev/null
@@ -0,0 +1,651 @@
+# Microsoft Developer Studio Project File - Name="zlibvc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=zlibvc - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "zlibvc.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "zlibvc.mak" CFG="zlibvc - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "zlibvc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseAxp" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutAsm" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutCrtdll" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\zlib.dll"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc__"
+# PROP BASE Intermediate_Dir "zlibvc__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc__"
+# PROP Intermediate_Dir "zlibvc__"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:"zlibvc__\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_0"
+# PROP BASE Intermediate_Dir "zlibvc_0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_0"
+# PROP Intermediate_Dir "zlibvc_0"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_0\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_1"
+# PROP BASE Intermediate_Dir "zlibvc_1"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_1"
+# PROP Intermediate_Dir "zlibvc_1"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_1\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "zlibvc - Win32 Release"
+# Name "zlibvc - Win32 Debug"
+# Name "zlibvc - Win32 ReleaseAxp"
+# Name "zlibvc - Win32 ReleaseWithoutAsm"
+# Name "zlibvc - Win32 ReleaseWithoutCrtdll"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\adler32.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ADLER=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_COMPR=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_CRC32=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_DEFLA=\
+       ".\deflate.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gvmat32c.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_GZIO_=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFBL=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFCO=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inffast.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFFA=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inffast.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFLA=\
+       ".\infblock.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFTR=\
+       ".\inftrees.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFUT=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_TREES=\
+       ".\deflate.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_UNCOM=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zip.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlibvc.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ZUTIL=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/zlib/contrib/asm386/zlibvc.dsw b/lib/zlib/contrib/asm386/zlibvc.dsw
new file mode 100644 (file)
index 0000000..493cd87
--- /dev/null
@@ -0,0 +1,41 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zlibstat"=.\zlibstat.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlibvc"=.\zlibvc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/zlib/contrib/asm586/README.586 b/lib/zlib/contrib/asm586/README.586
new file mode 100644 (file)
index 0000000..6bb78f3
--- /dev/null
@@ -0,0 +1,43 @@
+This is a patched version of zlib modified to use
+Pentium-optimized assembly code in the deflation algorithm. The files
+changed/added by this patch are:
+
+README.586
+match.S
+
+The effectiveness of these modifications is a bit marginal, as the the
+program's bottleneck seems to be mostly L1-cache contention, for which
+there is no real way to work around without rewriting the basic
+algorithm. The speedup on average is around 5-10% (which is generally
+less than the amount of variance between subsequent executions).
+However, when used at level 9 compression, the cache contention can
+drop enough for the assembly version to achieve 10-20% speedup (and
+sometimes more, depending on the amount of overall redundancy in the
+files). Even here, though, cache contention can still be the limiting
+factor, depending on the nature of the program using the zlib library.
+This may also mean that better improvements will be seen on a Pentium
+with MMX, which suffers much less from L1-cache contention, but I have
+not yet verified this.
+
+Note that this code has been tailored for the Pentium in particular,
+and will not perform well on the Pentium Pro (due to the use of a
+partial register in the inner loop).
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
diff --git a/lib/zlib/contrib/asm586/match.S b/lib/zlib/contrib/asm586/match.S
new file mode 100644 (file)
index 0000000..8f16140
--- /dev/null
@@ -0,0 +1,354 @@
+/* match.s -- Pentium-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define        match_init      _match_init
+#define        longest_match   _longest_match
+#endif
+
+#define        MAX_MATCH       (258)
+#define        MIN_MATCH       (3)
+#define        MIN_LOOKAHEAD   (MAX_MATCH + MIN_MATCH + 1)
+#define        MAX_MATCH_8     ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define        wmask                   0       /* local copy of s->wmask       */
+#define        window                  4       /* local copy of s->window      */
+#define        windowbestlen           8       /* s->window + bestlen          */
+#define        chainlenscanend         12      /* high word: current chain len */
+                                       /* low word: last bytes sought  */
+#define        scanstart               16      /* first two bytes of string    */
+#define        scanalign               20      /* dword-misalignment of string */
+#define        nicematch               24      /* a good enough match size     */
+#define        bestlen                 28      /* size of best match so far    */
+#define        scan                    32      /* ptr to string wanting match  */
+
+#define        LocalVarsSize           (36)
+/*     saved ebx               36 */
+/*     saved edi               40 */
+/*     saved esi               44 */
+/*     saved ebp               48 */
+/*     return address          52 */
+#define        deflatestate            56      /* the function arguments       */
+#define        curmatch                60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+#define        dsWSize                 36
+#define        dsWMask                 44
+#define        dsWindow                48
+#define        dsPrev                  56
+#define        dsMatchLen              88
+#define        dsPrevMatch             92
+#define        dsStrStart              100
+#define        dsMatchStart            104
+#define        dsLookahead             108
+#define        dsPrevLen               112
+#define        dsMaxChainLen           116
+#define        dsGoodMatch             132
+#define        dsNiceMatch             136
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to   */
+/* make room for our stack frame.                                      */
+
+               pushl   %ebp
+               pushl   %edi
+               pushl   %esi
+               pushl   %ebx
+               subl    $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match           */
+/* throughout the entire function. %edx will hold the pointer to the   */
+/* deflate_state structure during the function's setup (before         */
+/* entering the main loop).                                            */
+
+               movl    deflatestate(%esp), %edx
+               movl    curmatch(%esp), %ecx
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;     */
+
+               movl    dsNiceMatch(%edx), %eax
+               movl    dsLookahead(%edx), %ebx
+               cmpl    %eax, %ebx
+               jl      LookaheadLess
+               movl    %eax, %ebx
+LookaheadLess: movl    %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart;                     */
+
+               movl    dsWindow(%edx), %esi
+               movl    %esi, window(%esp)
+               movl    dsStrStart(%edx), %ebp
+               lea     (%esi,%ebp), %edi
+               movl    %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being             */
+/* dword-aligned.                                                      */
+
+               movl    %edi, %eax
+               negl    %eax
+               andl    $3, %eax
+               movl    %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ?                      */
+/*     s->strstart - (IPos)MAX_DIST(s) : NIL;                          */
+
+               movl    dsWSize(%edx), %eax
+               subl    $MIN_LOOKAHEAD, %eax
+               subl    %eax, %ebp
+               jg      LimitPositive
+               xorl    %ebp, %ebp
+LimitPositive:
+
+/* unsigned chain_length = s->max_chain_length;                                */
+/* if (s->prev_length >= s->good_match) {                              */
+/*     chain_length >>= 2;                                             */
+/* }                                                                   */
+
+               movl    dsPrevLen(%edx), %eax
+               movl    dsGoodMatch(%edx), %ebx
+               cmpl    %ebx, %eax
+               movl    dsMaxChainLen(%edx), %ebx
+               jl      LastMatchGood
+               shrl    $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can    */
+/* use the sign flag instead of the zero flag for the exit test.       */
+/* It is then shifted into the high word, to make room for the scanend */
+/* scanend value, which it will always accompany.                      */
+
+               decl    %ebx
+               shll    $16, %ebx
+
+/* int best_len = s->prev_length;                                      */
+
+               movl    dsPrevLen(%edx), %eax
+               movl    %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+               addl    %eax, %esi
+               movl    %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan;                             */
+/* register ush scan_end   = *(ushf*)(scan+best_len-1);                        */
+
+               movw    (%edi), %bx
+               movw    %bx, scanstart(%esp)
+               movw    -1(%edi,%eax), %bx
+               movl    %ebx, chainlenscanend(%esp)
+
+/* Posf *prev = s->prev;                                               */
+/* uInt wmask = s->w_mask;                                             */
+
+               movl    dsPrev(%edx), %edi
+               movl    dsWMask(%edx), %edx
+               mov     %edx, wmask(%esp)
+
+/* Jump into the main loop.                                            */
+
+               jmp     LoopEntry
+
+.balign 16
+
+/* do {
+ *     match = s->window + cur_match;
+ *     if (*(ushf*)(match+best_len-1) != scan_end ||
+ *         *(ushf*)match != scan_start) continue;
+ *     [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ *          && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
+ * %ecx = curmatch
+ * %edx = curmatch & wmask
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ *
+ * Two optimization notes on the choice of instructions:
+ *
+ * The first instruction uses a 16-bit address, which costs an extra,
+ * unpairable cycle. This is cheaper than doing a 32-bit access and
+ * zeroing the high word, due to the 3-cycle misalignment penalty which
+ * would occur half the time. This also turns out to be cheaper than
+ * doing two separate 8-bit accesses, as the memory is so rarely in the
+ * L1 cache.
+ *
+ * The window buffer, however, apparently spends a lot of time in the
+ * cache, and so it is faster to retrieve the word at the end of the
+ * match string with two 8-bit loads. The instructions that test the
+ * word at the beginning of the match string, however, are executed
+ * much less frequently, and there it was cheaper to use 16-bit
+ * instructions, which avoided the necessity of saving off and
+ * subsequently reloading one of the other registers.
+ */
+LookupLoop:
+                                                       /* 1 U & V  */
+               movw    (%edi,%edx,2), %cx              /* 2 U pipe */
+               movl    wmask(%esp), %edx               /* 2 V pipe */
+               cmpl    %ebp, %ecx                      /* 3 U pipe */
+               jbe     LeaveNow                        /* 3 V pipe */
+               subl    $0x00010000, %ebx               /* 4 U pipe */
+               js      LeaveNow                        /* 4 V pipe */
+LoopEntry:     movb    -1(%esi,%ecx), %al              /* 5 U pipe */
+               andl    %ecx, %edx                      /* 5 V pipe */
+               cmpb    %bl, %al                        /* 6 U pipe */
+               jnz     LookupLoop                      /* 6 V pipe */
+               movb    (%esi,%ecx), %ah
+               cmpb    %bh, %ah
+               jnz     LookupLoop
+               movl    window(%esp), %eax
+               movw    (%eax,%ecx), %ax
+               cmpw    scanstart(%esp), %ax
+               jnz     LookupLoop
+
+/* Store the current value of chainlen.                                        */
+
+               movl    %ebx, chainlenscanend(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we  */
+/* are hoping to match it up with. In actuality, %esi and %edi are     */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is     */
+/* initialized to -(MAX_MATCH_8 - scanalign).                          */
+
+               movl    window(%esp), %esi
+               movl    scan(%esp), %edi
+               addl    %ecx, %esi
+               movl    scanalign(%esp), %eax
+               movl    $(-MAX_MATCH_8), %edx
+               lea     MAX_MATCH_8(%edi,%eax), %edi
+               lea     MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+               movl    (%esi,%edx), %eax
+               movl    (%edi,%edx), %ebx
+               xorl    %ebx, %eax
+               jnz     LeaveLoopCmps
+               movl    4(%esi,%edx), %eax
+               movl    4(%edi,%edx), %ebx
+               xorl    %ebx, %eax
+               jnz     LeaveLoopCmps4
+               addl    $8, %edx
+               jnz     LoopCmps
+               jmp     LenMaximum
+LeaveLoopCmps4:        addl    $4, %edx
+LeaveLoopCmps: testl   $0x0000FFFF, %eax
+               jnz     LenLower
+               addl    $2, %edx
+               shrl    $16, %eax
+LenLower:      subb    $1, %al
+               adcl    $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH,  */
+/* then automatically accept it as the best possible match and leave.  */
+
+               lea     (%edi,%edx), %eax
+               movl    scan(%esp), %edi
+               subl    %edi, %eax
+               cmpl    $MAX_MATCH, %eax
+               jge     LenMaximum
+
+/* If the length of the match is not longer than the best match we     */
+/* have so far, then forget it and return to the lookup loop.          */
+
+               movl    deflatestate(%esp), %edx
+               movl    bestlen(%esp), %ebx
+               cmpl    %ebx, %eax
+               jg      LongerMatch
+               movl    chainlenscanend(%esp), %ebx
+               movl    windowbestlen(%esp), %esi
+               movl    dsPrev(%edx), %edi
+               movl    wmask(%esp), %edx
+               andl    %ecx, %edx
+               jmp     LookupLoop
+
+/*         s->match_start = cur_match;                                 */
+/*         best_len = len;                                             */
+/*         if (len >= nice_match) break;                               */
+/*         scan_end = *(ushf*)(scan+best_len-1);                       */
+
+LongerMatch:   movl    nicematch(%esp), %ebx
+               movl    %eax, bestlen(%esp)
+               movl    %ecx, dsMatchStart(%edx)
+               cmpl    %ebx, %eax
+               jge     LeaveNow
+               movl    window(%esp), %esi
+               addl    %eax, %esi
+               movl    %esi, windowbestlen(%esp)
+               movl    chainlenscanend(%esp), %ebx
+               movw    -1(%edi,%eax), %bx
+               movl    dsPrev(%edx), %edi
+               movl    %ebx, chainlenscanend(%esp)
+               movl    wmask(%esp), %edx
+               andl    %ecx, %edx
+               jmp     LookupLoop
+
+/* Accept the current string, with the maximum possible length.                */
+
+LenMaximum:    movl    deflatestate(%esp), %edx
+               movl    $MAX_MATCH, bestlen(%esp)
+               movl    %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len;          */
+/* return s->lookahead;                                                        */
+
+LeaveNow:
+               movl    deflatestate(%esp), %edx
+               movl    bestlen(%esp), %ebx
+               movl    dsLookahead(%edx), %eax
+               cmpl    %eax, %ebx
+               jg      LookaheadRet
+               movl    %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came.                   */
+
+               addl    $LocalVarsSize, %esp
+               popl    %ebx
+               popl    %esi
+               popl    %edi
+               popl    %ebp
+match_init:    ret
diff --git a/lib/zlib/contrib/asm686/README.686 b/lib/zlib/contrib/asm686/README.686
new file mode 100644 (file)
index 0000000..a593f23
--- /dev/null
@@ -0,0 +1,34 @@
+This is a patched version of zlib, modified to use
+Pentium-Pro-optimized assembly code in the deflation algorithm. The
+files changed/added by this patch are:
+
+README.686
+match.S
+
+The speedup that this patch provides varies, depending on whether the
+compiler used to build the original version of zlib falls afoul of the
+PPro's speed traps. My own tests show a speedup of around 10-20% at
+the default compression level, and 20-30% using -9, against a version
+compiled using gcc 2.7.2.3. Your mileage may vary.
+
+Note that this code has been tailored for the PPro/PII in particular,
+and will not perform particuarly well on a Pentium.
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
diff --git a/lib/zlib/contrib/asm686/match.S b/lib/zlib/contrib/asm686/match.S
new file mode 100644 (file)
index 0000000..8e86c33
--- /dev/null
@@ -0,0 +1,327 @@
+/* match.s -- Pentium-Pro-optimized version of longest_match()
+ * Written for zlib 1.1.2
+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License.
+ */
+
+#ifndef NO_UNDERLINE
+#define        match_init      _match_init
+#define        longest_match   _longest_match
+#endif
+
+#define        MAX_MATCH       (258)
+#define        MIN_MATCH       (3)
+#define        MIN_LOOKAHEAD   (MAX_MATCH + MIN_MATCH + 1)
+#define        MAX_MATCH_8     ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define        chainlenwmask           0       /* high word: current chain len */
+                                       /* low word: s->wmask           */
+#define        window                  4       /* local copy of s->window      */
+#define        windowbestlen           8       /* s->window + bestlen          */
+#define        scanstart               16      /* first two bytes of string    */
+#define        scanend                 12      /* last two bytes of string     */
+#define        scanalign               20      /* dword-misalignment of string */
+#define        nicematch               24      /* a good enough match size     */
+#define        bestlen                 28      /* size of best match so far    */
+#define        scan                    32      /* ptr to string wanting match  */
+
+#define        LocalVarsSize           (36)
+/*     saved ebx               36 */
+/*     saved edi               40 */
+/*     saved esi               44 */
+/*     saved ebp               48 */
+/*     return address          52 */
+#define        deflatestate            56      /* the function arguments       */
+#define        curmatch                60
+
+/* Offsets for fields in the deflate_state structure. These numbers
+ * are calculated from the definition of deflate_state, with the
+ * assumption that the compiler will dword-align the fields. (Thus,
+ * changing the definition of deflate_state could easily cause this
+ * program to crash horribly, without so much as a warning at
+ * compile time. Sigh.)
+ */
+#define        dsWSize                 36
+#define        dsWMask                 44
+#define        dsWindow                48
+#define        dsPrev                  56
+#define        dsMatchLen              88
+#define        dsPrevMatch             92
+#define        dsStrStart              100
+#define        dsMatchStart            104
+#define        dsLookahead             108
+#define        dsPrevLen               112
+#define        dsMaxChainLen           116
+#define        dsGoodMatch             132
+#define        dsNiceMatch             136
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+
+/* Save registers that the compiler may be using, and adjust %esp to   */
+/* make room for our stack frame.                                      */
+
+               pushl   %ebp
+               pushl   %edi
+               pushl   %esi
+               pushl   %ebx
+               subl    $LocalVarsSize, %esp
+
+/* Retrieve the function arguments. %ecx will hold cur_match           */
+/* throughout the entire function. %edx will hold the pointer to the   */
+/* deflate_state structure during the function's setup (before         */
+/* entering the main loop).                                            */
+
+               movl    deflatestate(%esp), %edx
+               movl    curmatch(%esp), %ecx
+
+/* uInt wmask = s->w_mask;                                             */
+/* unsigned chain_length = s->max_chain_length;                                */
+/* if (s->prev_length >= s->good_match) {                              */
+/*     chain_length >>= 2;                                             */
+/* }                                                                   */
+
+               movl    dsPrevLen(%edx), %eax
+               movl    dsGoodMatch(%edx), %ebx
+               cmpl    %ebx, %eax
+               movl    dsWMask(%edx), %eax
+               movl    dsMaxChainLen(%edx), %ebx
+               jl      LastMatchGood
+               shrl    $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can    */
+/* use the sign flag instead of the zero flag for the exit test.       */
+/* It is then shifted into the high word, to make room for the wmask   */
+/* value, which it will always accompany.                              */
+
+               decl    %ebx
+               shll    $16, %ebx
+               orl     %eax, %ebx
+               movl    %ebx, chainlenwmask(%esp)
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;     */
+
+               movl    dsNiceMatch(%edx), %eax
+               movl    dsLookahead(%edx), %ebx
+               cmpl    %eax, %ebx
+               jl      LookaheadLess
+               movl    %eax, %ebx
+LookaheadLess: movl    %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart;                     */
+
+               movl    dsWindow(%edx), %esi
+               movl    %esi, window(%esp)
+               movl    dsStrStart(%edx), %ebp
+               lea     (%esi,%ebp), %edi
+               movl    %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being             */
+/* dword-aligned.                                                      */
+
+               movl    %edi, %eax
+               negl    %eax
+               andl    $3, %eax
+               movl    %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ?                      */
+/*     s->strstart - (IPos)MAX_DIST(s) : NIL;                          */
+
+               movl    dsWSize(%edx), %eax
+               subl    $MIN_LOOKAHEAD, %eax
+               subl    %eax, %ebp
+               jg      LimitPositive
+               xorl    %ebp, %ebp
+LimitPositive:
+
+/* int best_len = s->prev_length;                                      */
+
+               movl    dsPrevLen(%edx), %eax
+               movl    %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+               addl    %eax, %esi
+               movl    %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan;                             */
+/* register ush scan_end   = *(ushf*)(scan+best_len-1);                        */
+/* Posf *prev = s->prev;                                               */
+
+               movzwl  (%edi), %ebx
+               movl    %ebx, scanstart(%esp)
+               movzwl  -1(%edi,%eax), %ebx
+               movl    %ebx, scanend(%esp)
+               movl    dsPrev(%edx), %edi
+
+/* Jump into the main loop.                                            */
+
+               movl    chainlenwmask(%esp), %edx
+               jmp     LoopEntry
+
+.balign 16
+
+/* do {
+ *     match = s->window + cur_match;
+ *     if (*(ushf*)(match+best_len-1) != scan_end ||
+ *         *(ushf*)match != scan_start) continue;
+ *     [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ *          && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = scanend
+ * %ecx = curmatch
+ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ */
+LookupLoop:
+               andl    %edx, %ecx
+               movzwl  (%edi,%ecx,2), %ecx
+               cmpl    %ebp, %ecx
+               jbe     LeaveNow
+               subl    $0x00010000, %edx
+               js      LeaveNow
+LoopEntry:     movzwl  -1(%esi,%ecx), %eax
+               cmpl    %ebx, %eax
+               jnz     LookupLoop
+               movl    window(%esp), %eax
+               movzwl  (%eax,%ecx), %eax
+               cmpl    scanstart(%esp), %eax
+               jnz     LookupLoop
+
+/* Store the current value of chainlen.                                        */
+
+               movl    %edx, chainlenwmask(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we  */
+/* are hoping to match it up with. In actuality, %esi and %edi are     */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is     */
+/* initialized to -(MAX_MATCH_8 - scanalign).                          */
+
+               movl    window(%esp), %esi
+               movl    scan(%esp), %edi
+               addl    %ecx, %esi
+               movl    scanalign(%esp), %eax
+               movl    $(-MAX_MATCH_8), %edx
+               lea     MAX_MATCH_8(%edi,%eax), %edi
+               lea     MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+               movl    (%esi,%edx), %eax
+               xorl    (%edi,%edx), %eax
+               jnz     LeaveLoopCmps
+               movl    4(%esi,%edx), %eax
+               xorl    4(%edi,%edx), %eax
+               jnz     LeaveLoopCmps4
+               addl    $8, %edx
+               jnz     LoopCmps
+               jmp     LenMaximum
+LeaveLoopCmps4:        addl    $4, %edx
+LeaveLoopCmps: testl   $0x0000FFFF, %eax
+               jnz     LenLower
+               addl    $2, %edx
+               shrl    $16, %eax
+LenLower:      subb    $1, %al
+               adcl    $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH,  */
+/* then automatically accept it as the best possible match and leave.  */
+
+               lea     (%edi,%edx), %eax
+               movl    scan(%esp), %edi
+               subl    %edi, %eax
+               cmpl    $MAX_MATCH, %eax
+               jge     LenMaximum
+
+/* If the length of the match is not longer than the best match we     */
+/* have so far, then forget it and return to the lookup loop.          */
+
+               movl    deflatestate(%esp), %edx
+               movl    bestlen(%esp), %ebx
+               cmpl    %ebx, %eax
+               jg      LongerMatch
+               movl    windowbestlen(%esp), %esi
+               movl    dsPrev(%edx), %edi
+               movl    scanend(%esp), %ebx
+               movl    chainlenwmask(%esp), %edx
+               jmp     LookupLoop
+
+/*         s->match_start = cur_match;                                 */
+/*         best_len = len;                                             */
+/*         if (len >= nice_match) break;                               */
+/*         scan_end = *(ushf*)(scan+best_len-1);                       */
+
+LongerMatch:   movl    nicematch(%esp), %ebx
+               movl    %eax, bestlen(%esp)
+               movl    %ecx, dsMatchStart(%edx)
+               cmpl    %ebx, %eax
+               jge     LeaveNow
+               movl    window(%esp), %esi
+               addl    %eax, %esi
+               movl    %esi, windowbestlen(%esp)
+               movzwl  -1(%edi,%eax), %ebx
+               movl    dsPrev(%edx), %edi
+               movl    %ebx, scanend(%esp)
+               movl    chainlenwmask(%esp), %edx
+               jmp     LookupLoop
+
+/* Accept the current string, with the maximum possible length.                */
+
+LenMaximum:    movl    deflatestate(%esp), %edx
+               movl    $MAX_MATCH, bestlen(%esp)
+               movl    %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len;          */
+/* return s->lookahead;                                                        */
+
+LeaveNow:
+               movl    deflatestate(%esp), %edx
+               movl    bestlen(%esp), %ebx
+               movl    dsLookahead(%edx), %eax
+               cmpl    %eax, %ebx
+               jg      LookaheadRet
+               movl    %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came.                   */
+
+               addl    $LocalVarsSize, %esp
+               popl    %ebx
+               popl    %esi
+               popl    %edi
+               popl    %ebp
+match_init:    ret
diff --git a/lib/zlib/contrib/delphi/zlib.mak b/lib/zlib/contrib/delphi/zlib.mak
new file mode 100644 (file)
index 0000000..ba557e2
--- /dev/null
@@ -0,0 +1,36 @@
+# Makefile for zlib32bd.lib
+# ------------- Borland C++ 4.5 -------------
+
+# The (32-bit) zlib32bd.lib made with this makefile is intended for use 
+# in making the (32-bit) DLL, png32bd.dll. It uses the "stdcall" calling 
+# convention.
+
+CFLAGS= -ps -O2 -C -K -N- -k- -d -3 -r- -w-par -w-aus -WDE
+CC=f:\bc45\bin\bcc32
+LIBFLAGS= /C
+LIB=f:\bc45\bin\tlib
+ZLIB=zlib32bd.lib
+
+.autodepend
+.c.obj:
+        $(CC) -c $(CFLAGS) $<
+
+OBJ1=adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infblock.obj 
+OBJ2=infcodes.obj inflate.obj inftrees.obj infutil.obj inffast.obj 
+OBJ3=trees.obj uncompr.obj zutil.obj
+pOBJ1=+adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infblock.obj 
+pOBJ2=+infcodes.obj+inflate.obj+inftrees.obj+infutil.obj+inffast.obj 
+pOBJ3=+trees.obj+uncompr.obj+zutil.obj
+
+all: $(ZLIB)
+
+$(ZLIB): $(OBJ1) $(OBJ2) $(OBJ3)
+        @if exist $@ del $@
+        $(LIB) @&&|
+$@ $(LIBFLAGS) &
+$(pOBJ1) &
+$(pOBJ2) &
+$(pOBJ3)
+|
+
+# End of makefile for zlib32bd.lib
diff --git a/lib/zlib/contrib/delphi/zlibdef.pas b/lib/zlib/contrib/delphi/zlibdef.pas
new file mode 100644 (file)
index 0000000..4f96b7d
--- /dev/null
@@ -0,0 +1,169 @@
+unit zlibdef;
+
+interface
+
+uses
+  Windows;
+
+const
+  ZLIB_VERSION = '1.1.3';
+
+type
+  voidpf = Pointer;
+  int    = Integer;
+  uInt   = Cardinal;
+  pBytef = PChar;
+  uLong  = Cardinal;
+
+  alloc_func = function(opaque: voidpf; items, size: uInt): voidpf;
+                    stdcall;
+  free_func  = procedure(opaque, address: voidpf);
+                    stdcall;
+
+  internal_state = Pointer;
+
+  z_streamp = ^z_stream;
+  z_stream = packed record
+    next_in: pBytef;          // next input byte
+    avail_in: uInt;           // number of bytes available at next_in
+    total_in: uLong;          // total nb of input bytes read so far
+
+    next_out: pBytef;         // next output byte should be put there
+    avail_out: uInt;          // remaining free space at next_out
+    total_out: uLong;         // total nb of bytes output so far
+
+    msg: PChar;               // last error message, NULL if no error
+    state: internal_state;    // not visible by applications
+
+    zalloc: alloc_func;       // used to allocate the internal state
+    zfree: free_func;         // used to free the internal state
+    opaque: voidpf;           // private data object passed to zalloc and zfree
+
+    data_type: int;           // best guess about the data type: ascii or binary
+    adler: uLong;             // adler32 value of the uncompressed data
+    reserved: uLong;          // reserved for future use
+    end;
+
+const
+  Z_NO_FLUSH      = 0;
+  Z_SYNC_FLUSH    = 2;
+  Z_FULL_FLUSH    = 3;
+  Z_FINISH        = 4;
+
+  Z_OK            = 0;
+  Z_STREAM_END    = 1;
+
+  Z_NO_COMPRESSION         =  0;
+  Z_BEST_SPEED             =  1;
+  Z_BEST_COMPRESSION       =  9;
+  Z_DEFAULT_COMPRESSION    = -1;
+
+  Z_FILTERED            = 1;
+  Z_HUFFMAN_ONLY        = 2;
+  Z_DEFAULT_STRATEGY    = 0;
+
+  Z_BINARY   = 0;
+  Z_ASCII    = 1;
+  Z_UNKNOWN  = 2;
+
+  Z_DEFLATED    = 8;
+
+  MAX_MEM_LEVEL = 9;
+
+function adler32(adler: uLong; const buf: pBytef; len: uInt): uLong;
+             stdcall;
+function crc32(crc: uLong; const buf: pBytef; len: uInt): uLong;
+             stdcall;
+function deflate(strm: z_streamp; flush: int): int;
+             stdcall;
+function deflateCopy(dest, source: z_streamp): int;
+             stdcall;
+function deflateEnd(strm: z_streamp): int;
+             stdcall;
+function deflateInit2_(strm: z_streamp; level, method,
+                       windowBits, memLevel, strategy: int;
+                       const version: PChar; stream_size: int): int;
+             stdcall;
+function deflateInit_(strm: z_streamp; level: int;
+                      const version: PChar; stream_size: int): int;
+             stdcall;
+function deflateParams(strm: z_streamp; level, strategy: int): int;
+             stdcall;
+function deflateReset(strm: z_streamp): int;
+             stdcall;
+function deflateSetDictionary(strm: z_streamp;
+                              const dictionary: pBytef;
+                              dictLength: uInt): int;
+             stdcall;
+function inflate(strm: z_streamp; flush: int): int;
+             stdcall;
+function inflateEnd(strm: z_streamp): int;
+             stdcall;
+function inflateInit2_(strm: z_streamp; windowBits: int;
+                       const version: PChar; stream_size: int): int;
+             stdcall;
+function inflateInit_(strm: z_streamp; const version: PChar;
+                      stream_size: int): int;
+             stdcall;
+function inflateReset(strm: z_streamp): int;
+             stdcall;
+function inflateSetDictionary(strm: z_streamp;
+                              const dictionary: pBytef;
+                              dictLength: uInt): int;
+             stdcall;
+function inflateSync(strm: z_streamp): int;
+             stdcall;
+
+function deflateInit(strm: z_streamp; level: int): int;
+function deflateInit2(strm: z_streamp; level, method, windowBits,
+                      memLevel, strategy: int): int;
+function inflateInit(strm: z_streamp): int;
+function inflateInit2(strm: z_streamp; windowBits: int): int;
+
+implementation
+
+function deflateInit(strm: z_streamp; level: int): int;
+begin
+  Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function deflateInit2(strm: z_streamp; level, method, windowBits,
+                      memLevel, strategy: int): int;
+begin
+  Result := deflateInit2_(strm, level, method, windowBits, memLevel,
+                          strategy, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit(strm: z_streamp): int;
+begin
+  Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit2(strm: z_streamp; windowBits: int): int;
+begin
+  Result := inflateInit2_(strm, windowBits, ZLIB_VERSION,
+                          sizeof(z_stream));
+end;
+
+const
+  zlibDLL = 'png32bd.dll';
+
+function adler32; external zlibDLL;
+function crc32; external zlibDLL;
+function deflate; external zlibDLL;
+function deflateCopy; external zlibDLL;
+function deflateEnd; external zlibDLL;
+function deflateInit2_; external zlibDLL;
+function deflateInit_; external zlibDLL;
+function deflateParams; external zlibDLL;
+function deflateReset; external zlibDLL;
+function deflateSetDictionary; external zlibDLL;
+function inflate; external zlibDLL;
+function inflateEnd; external zlibDLL;
+function inflateInit2_; external zlibDLL;
+function inflateInit_; external zlibDLL;
+function inflateReset; external zlibDLL;
+function inflateSetDictionary; external zlibDLL;
+function inflateSync; external zlibDLL;
+
+end.
diff --git a/lib/zlib/contrib/delphi2/d_zlib.bpr b/lib/zlib/contrib/delphi2/d_zlib.bpr
new file mode 100644 (file)
index 0000000..78bb254
--- /dev/null
@@ -0,0 +1,224 @@
+# ---------------------------------------------------------------------------
+!if !$d(BCB)
+BCB = $(MAKEDIR)\..
+!endif
+
+# ---------------------------------------------------------------------------
+# IDE SECTION
+# ---------------------------------------------------------------------------
+# The following section of the project makefile is managed by the BCB IDE.
+# It is recommended to use the IDE to change any of the values in this
+# section.
+# ---------------------------------------------------------------------------
+
+VERSION = BCB.03
+# ---------------------------------------------------------------------------
+PROJECT = d_zlib.lib
+OBJFILES = d_zlib.obj adler32.obj deflate.obj infblock.obj infcodes.obj inffast.obj \
+  inflate.obj inftrees.obj infutil.obj trees.obj
+RESFILES =
+RESDEPEN = $(RESFILES)
+LIBFILES =
+LIBRARIES = VCL35.lib
+SPARELIBS = VCL35.lib
+DEFFILE =
+PACKAGES = VCLX35.bpi VCL35.bpi VCLDB35.bpi VCLDBX35.bpi ibsmp35.bpi bcbsmp35.bpi \
+  dclocx35.bpi QRPT35.bpi TEEUI35.bpi TEEDB35.bpi TEE35.bpi DSS35.bpi \
+  NMFAST35.bpi INETDB35.bpi INET35.bpi VCLMID35.bpi
+# ---------------------------------------------------------------------------
+PATHCPP = .;
+PATHASM = .;
+PATHPAS = .;
+PATHRC = .;
+DEBUGLIBPATH = $(BCB)\lib\debug
+RELEASELIBPATH = $(BCB)\lib\release
+# ---------------------------------------------------------------------------
+CFLAG1 = -O2 -Ve -d -k- -vi
+CFLAG2 = -I$(BCB)\include;$(BCB)\include\vcl -H=$(BCB)\lib\vcl35.csm
+CFLAG3 = -ff -pr -5
+PFLAGS = -U;$(DEBUGLIBPATH) -I$(BCB)\include;$(BCB)\include\vcl -H -W -$I- -v -JPHN -M
+RFLAGS = -i$(BCB)\include;$(BCB)\include\vcl 
+AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zn
+LFLAGS =
+IFLAGS = -g -Gn
+# ---------------------------------------------------------------------------
+ALLOBJ = c0w32.obj $(OBJFILES)
+ALLRES = $(RESFILES)
+ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib
+# ---------------------------------------------------------------------------
+!!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include
+Item1=$(BCB)\include;$(BCB)\include\vcl
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+ ---------------------------------------------------------------------------
+# MAKE SECTION
+# ---------------------------------------------------------------------------
+# This section of the project file is not used by the BCB IDE.  It is for
+# the benefit of building from the command-line using the MAKE utility.
+# ---------------------------------------------------------------------------
+
+.autodepend
+# ---------------------------------------------------------------------------
+!if !$d(BCC32)
+BCC32 = bcc32
+!endif
+
+!if !$d(DCC32)
+DCC32 = dcc32
+!endif
+
+!if !$d(TASM32)
+TASM32 = tasm32
+!endif
+
+!if !$d(LINKER)
+LINKER = TLib
+!endif
+
+!if !$d(BRCC32)
+BRCC32 = brcc32
+!endif
+# ---------------------------------------------------------------------------
+!if $d(PATHCPP)
+.PATH.CPP = $(PATHCPP)
+.PATH.C   = $(PATHCPP)
+!endif
+
+!if $d(PATHPAS)
+.PATH.PAS = $(PATHPAS)
+!endif
+
+!if $d(PATHASM)
+.PATH.ASM = $(PATHASM)
+!endif
+
+!if $d(PATHRC)
+.PATH.RC  = $(PATHRC)
+!endif
+# ---------------------------------------------------------------------------
+!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include;$(BCB)\include\vcl
+Item1=$(BCB)\include
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
+    $(BCB)\BIN\$(LINKER) @&&!
+    $(LFLAGS) $(IFLAGS) +
+    $(ALLOBJ), +
+    $(PROJECT),, +
+    $(ALLLIB), +
+    $(DEFFILE), +
+    $(ALLRES)
+!
+# ---------------------------------------------------------------------------
+.pas.hpp:
+    $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.pas.obj:
+    $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.cpp.obj:
+    $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.c.obj:
+    $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.asm.obj:
+    $(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
+
+.rc.res:
+    $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
+# ---------------------------------------------------------------------------
diff --git a/lib/zlib/contrib/delphi2/d_zlib.cpp b/lib/zlib/contrib/delphi2/d_zlib.cpp
new file mode 100644 (file)
index 0000000..f5dea59
--- /dev/null
@@ -0,0 +1,17 @@
+#include <condefs.h>
+#pragma hdrstop
+//---------------------------------------------------------------------------
+USEUNIT("adler32.c");
+USEUNIT("deflate.c");
+USEUNIT("infblock.c");
+USEUNIT("infcodes.c");
+USEUNIT("inffast.c");
+USEUNIT("inflate.c");
+USEUNIT("inftrees.c");
+USEUNIT("infutil.c");
+USEUNIT("trees.c");
+//---------------------------------------------------------------------------
+#define Library
+
+// To add a file to the library use the Project menu 'Add to Project'.
+
diff --git a/lib/zlib/contrib/delphi2/readme.txt b/lib/zlib/contrib/delphi2/readme.txt
new file mode 100644 (file)
index 0000000..cbd3162
--- /dev/null
@@ -0,0 +1,17 @@
+These are files used to compile zlib under Borland C++ Builder 3.
+
+zlib.bpg is the main project group that can be loaded in the BCB IDE and
+loads all other *.bpr projects
+
+zlib.bpr is a project used to create a static zlib.lib library with C calling
+convention for functions.
+
+zlib32.bpr creates a zlib32.dll dynamic link library with Windows standard
+calling convention.
+
+d_zlib.bpr creates a set of .obj files with register calling convention.
+These files are used by zlib.pas to create a Delphi unit containing zlib.
+The d_zlib.lib file generated isn't useful and can be deleted.
+
+zlib.cpp, zlib32.cpp and d_zlib.cpp are used by the above projects.
+
diff --git a/lib/zlib/contrib/delphi2/zlib.bpg b/lib/zlib/contrib/delphi2/zlib.bpg
new file mode 100644 (file)
index 0000000..b6c9acd
--- /dev/null
@@ -0,0 +1,26 @@
+#------------------------------------------------------------------------------
+VERSION = BWS.01
+#------------------------------------------------------------------------------
+!ifndef ROOT
+ROOT = $(MAKEDIR)\..
+!endif
+#------------------------------------------------------------------------------
+MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$**
+DCC = $(ROOT)\bin\dcc32.exe $**
+BRCC = $(ROOT)\bin\brcc32.exe $**
+#------------------------------------------------------------------------------
+PROJECTS = zlib zlib32 d_zlib
+#------------------------------------------------------------------------------
+default: $(PROJECTS)
+#------------------------------------------------------------------------------
+
+zlib: zlib.bpr
+  $(MAKE)
+
+zlib32: zlib32.bpr
+  $(MAKE)
+
+d_zlib: d_zlib.bpr
+  $(MAKE)
+
+
diff --git a/lib/zlib/contrib/delphi2/zlib.bpr b/lib/zlib/contrib/delphi2/zlib.bpr
new file mode 100644 (file)
index 0000000..cf3945b
--- /dev/null
@@ -0,0 +1,225 @@
+# ---------------------------------------------------------------------------
+!if !$d(BCB)
+BCB = $(MAKEDIR)\..
+!endif
+
+# ---------------------------------------------------------------------------
+# IDE SECTION
+# ---------------------------------------------------------------------------
+# The following section of the project makefile is managed by the BCB IDE.
+# It is recommended to use the IDE to change any of the values in this
+# section.
+# ---------------------------------------------------------------------------
+
+VERSION = BCB.03
+# ---------------------------------------------------------------------------
+PROJECT = zlib.lib
+OBJFILES = zlib.obj adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infblock.obj \
+  infcodes.obj inffast.obj inflate.obj inftrees.obj infutil.obj trees.obj \
+  uncompr.obj zutil.obj
+RESFILES =
+RESDEPEN = $(RESFILES)
+LIBFILES =
+LIBRARIES = VCL35.lib
+SPARELIBS = VCL35.lib
+DEFFILE =
+PACKAGES = VCLX35.bpi VCL35.bpi VCLDB35.bpi VCLDBX35.bpi ibsmp35.bpi bcbsmp35.bpi \
+  dclocx35.bpi QRPT35.bpi TEEUI35.bpi TEEDB35.bpi TEE35.bpi DSS35.bpi \
+  NMFAST35.bpi INETDB35.bpi INET35.bpi VCLMID35.bpi
+# ---------------------------------------------------------------------------
+PATHCPP = .;
+PATHASM = .;
+PATHPAS = .;
+PATHRC = .;
+DEBUGLIBPATH = $(BCB)\lib\debug
+RELEASELIBPATH = $(BCB)\lib\release
+# ---------------------------------------------------------------------------
+CFLAG1 = -O2 -Ve -d -k- -vi
+CFLAG2 = -I$(BCB)\include;$(BCB)\include\vcl -H=$(BCB)\lib\vcl35.csm
+CFLAG3 = -ff -5
+PFLAGS = -U;$(DEBUGLIBPATH) -I$(BCB)\include;$(BCB)\include\vcl -H -W -$I- -v -JPHN -M
+RFLAGS = -i$(BCB)\include;$(BCB)\include\vcl 
+AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zn
+LFLAGS =
+IFLAGS = -g -Gn
+# ---------------------------------------------------------------------------
+ALLOBJ = c0w32.obj $(OBJFILES)
+ALLRES = $(RESFILES)
+ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cp32mt.lib
+# ---------------------------------------------------------------------------
+!!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include
+Item1=$(BCB)\include;$(BCB)\include\vcl
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+ ---------------------------------------------------------------------------
+# MAKE SECTION
+# ---------------------------------------------------------------------------
+# This section of the project file is not used by the BCB IDE.  It is for
+# the benefit of building from the command-line using the MAKE utility.
+# ---------------------------------------------------------------------------
+
+.autodepend
+# ---------------------------------------------------------------------------
+!if !$d(BCC32)
+BCC32 = bcc32
+!endif
+
+!if !$d(DCC32)
+DCC32 = dcc32
+!endif
+
+!if !$d(TASM32)
+TASM32 = tasm32
+!endif
+
+!if !$d(LINKER)
+LINKER = TLib
+!endif
+
+!if !$d(BRCC32)
+BRCC32 = brcc32
+!endif
+# ---------------------------------------------------------------------------
+!if $d(PATHCPP)
+.PATH.CPP = $(PATHCPP)
+.PATH.C   = $(PATHCPP)
+!endif
+
+!if $d(PATHPAS)
+.PATH.PAS = $(PATHPAS)
+!endif
+
+!if $d(PATHASM)
+.PATH.ASM = $(PATHASM)
+!endif
+
+!if $d(PATHRC)
+.PATH.RC  = $(PATHRC)
+!endif
+# ---------------------------------------------------------------------------
+!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=2
+Item0=$(BCB)\include;$(BCB)\include\vcl
+Item1=$(BCB)\include
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib\obj;$(BCB)\lib
+
+[HistoryLists\hlDebugSourcePath]
+Count=1
+Item0=$(BCB)\source\vcl
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
+    $(BCB)\BIN\$(LINKER) @&&!
+    $(LFLAGS) $(IFLAGS) +
+    $(ALLOBJ), +
+    $(PROJECT),, +
+    $(ALLLIB), +
+    $(DEFFILE), +
+    $(ALLRES)
+!
+# ---------------------------------------------------------------------------
+.pas.hpp:
+    $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.pas.obj:
+    $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.cpp.obj:
+    $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.c.obj:
+    $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.asm.obj:
+    $(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
+
+.rc.res:
+    $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
+# ---------------------------------------------------------------------------
diff --git a/lib/zlib/contrib/delphi2/zlib.cpp b/lib/zlib/contrib/delphi2/zlib.cpp
new file mode 100644 (file)
index 0000000..bf6953b
--- /dev/null
@@ -0,0 +1,22 @@
+#include <condefs.h>
+#pragma hdrstop
+//---------------------------------------------------------------------------
+USEUNIT("adler32.c");
+USEUNIT("compress.c");
+USEUNIT("crc32.c");
+USEUNIT("deflate.c");
+USEUNIT("gzio.c");
+USEUNIT("infblock.c");
+USEUNIT("infcodes.c");
+USEUNIT("inffast.c");
+USEUNIT("inflate.c");
+USEUNIT("inftrees.c");
+USEUNIT("infutil.c");
+USEUNIT("trees.c");
+USEUNIT("uncompr.c");
+USEUNIT("zutil.c");
+//---------------------------------------------------------------------------
+#define Library
+
+// To add a file to the library use the Project menu 'Add to Project'.
+
diff --git a/lib/zlib/contrib/delphi2/zlib.pas b/lib/zlib/contrib/delphi2/zlib.pas
new file mode 100644 (file)
index 0000000..10ae4ca
--- /dev/null
@@ -0,0 +1,534 @@
+{*******************************************************}
+{                                                       }
+{       Delphi Supplemental Components                  }
+{       ZLIB Data Compression Interface Unit            }
+{                                                       }
+{       Copyright (c) 1997 Borland International        }
+{                                                       }
+{*******************************************************}
+
+{ Modified for zlib 1.1.3 by Davide Moretti <dave@rimini.com }
+
+unit zlib;
+
+interface
+
+uses Sysutils, Classes;
+
+type
+  TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer;
+  TFree = procedure (AppData, Block: Pointer);
+
+  // Internal structure.  Ignore.
+  TZStreamRec = packed record
+    next_in: PChar;       // next input byte
+    avail_in: Integer;    // number of bytes available at next_in
+    total_in: Integer;    // total nb of input bytes read so far
+
+    next_out: PChar;      // next output byte should be put here
+    avail_out: Integer;   // remaining free space at next_out
+    total_out: Integer;   // total nb of bytes output so far
+
+    msg: PChar;           // last error message, NULL if no error
+    internal: Pointer;    // not visible by applications
+
+    zalloc: TAlloc;       // used to allocate the internal state
+    zfree: TFree;         // used to free the internal state
+    AppData: Pointer;     // private data object passed to zalloc and zfree
+
+    data_type: Integer;   //  best guess about the data type: ascii or binary
+    adler: Integer;       // adler32 value of the uncompressed data
+    reserved: Integer;    // reserved for future use
+  end;
+
+  // Abstract ancestor class
+  TCustomZlibStream = class(TStream)
+  private
+    FStrm: TStream;
+    FStrmPos: Integer;
+    FOnProgress: TNotifyEvent;
+    FZRec: TZStreamRec;
+    FBuffer: array [Word] of Char;
+  protected
+    procedure Progress(Sender: TObject); dynamic;
+    property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+    constructor Create(Strm: TStream);
+  end;
+
+{ TCompressionStream compresses data on the fly as data is written to it, and
+  stores the compressed data to another stream.
+
+  TCompressionStream is write-only and strictly sequential. Reading from the
+  stream will raise an exception. Using Seek to move the stream pointer
+  will raise an exception.
+
+  Output data is cached internally, written to the output stream only when
+  the internal output buffer is full.  All pending output data is flushed
+  when the stream is destroyed.
+
+  The Position property returns the number of uncompressed bytes of
+  data that have been written to the stream so far.
+
+  CompressionRate returns the on-the-fly percentage by which the original
+  data has been compressed:  (1 - (CompressedBytes / UncompressedBytes)) * 100
+  If raw data size = 100 and compressed data size = 25, the CompressionRate
+  is 75%
+
+  The OnProgress event is called each time the output buffer is filled and
+  written to the output stream.  This is useful for updating a progress
+  indicator when you are writing a large chunk of data to the compression
+  stream in a single call.}
+
+
+  TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+  TCompressionStream = class(TCustomZlibStream)
+  private
+    function GetCompressionRate: Single;
+  public
+    constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    property CompressionRate: Single read GetCompressionRate;
+    property OnProgress;
+  end;
+
+{ TDecompressionStream decompresses data on the fly as data is read from it.
+
+  Compressed data comes from a separate source stream.  TDecompressionStream
+  is read-only and unidirectional; you can seek forward in the stream, but not
+  backwards.  The special case of setting the stream position to zero is
+  allowed.  Seeking forward decompresses data until the requested position in
+  the uncompressed data has been reached.  Seeking backwards, seeking relative
+  to the end of the stream, requesting the size of the stream, and writing to
+  the stream will raise an exception.
+
+  The Position property returns the number of bytes of uncompressed data that
+  have been read from the stream so far.
+
+  The OnProgress event is called each time the internal input buffer of
+  compressed data is exhausted and the next block is read from the input stream.
+  This is useful for updating a progress indicator when you are reading a
+  large chunk of data from the decompression stream in a single call.}
+
+  TDecompressionStream = class(TCustomZlibStream)
+  public
+    constructor Create(Source: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    property OnProgress;
+  end;
+
+
+
+{ CompressBuf compresses data, buffer to buffer, in one call.
+   In: InBuf = ptr to compressed data
+       InBytes = number of bytes in InBuf
+  Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+       OutBytes = number of bytes in OutBuf   }
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+                      out OutBuf: Pointer; out OutBytes: Integer);
+
+
+{ DecompressBuf decompresses data, buffer to buffer, in one call.
+   In: InBuf = ptr to compressed data
+       InBytes = number of bytes in InBuf
+       OutEstimate = zero, or est. size of the decompressed data
+  Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+       OutBytes = number of bytes in OutBuf   }
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+
+const
+  zlib_version = '1.1.3';
+
+type
+  EZlibError = class(Exception);
+  ECompressionError = class(EZlibError);
+  EDecompressionError = class(EZlibError);
+
+function adler32(adler: Integer; buf: PChar; len: Integer): Integer;
+
+implementation
+
+const
+  Z_NO_FLUSH      = 0;
+  Z_PARTIAL_FLUSH = 1;
+  Z_SYNC_FLUSH    = 2;
+  Z_FULL_FLUSH    = 3;
+  Z_FINISH        = 4;
+
+  Z_OK            = 0;
+  Z_STREAM_END    = 1;
+  Z_NEED_DICT     = 2;
+  Z_ERRNO         = (-1);
+  Z_STREAM_ERROR  = (-2);
+  Z_DATA_ERROR    = (-3);
+  Z_MEM_ERROR     = (-4);
+  Z_BUF_ERROR     = (-5);
+  Z_VERSION_ERROR = (-6);
+
+  Z_NO_COMPRESSION       =   0;
+  Z_BEST_SPEED           =   1;
+  Z_BEST_COMPRESSION     =   9;
+  Z_DEFAULT_COMPRESSION  = (-1);
+
+  Z_FILTERED            = 1;
+  Z_HUFFMAN_ONLY        = 2;
+  Z_DEFAULT_STRATEGY    = 0;
+
+  Z_BINARY   = 0;
+  Z_ASCII    = 1;
+  Z_UNKNOWN  = 2;
+
+  Z_DEFLATED = 8;
+
+  _z_errmsg: array[0..9] of PChar = (
+    'need dictionary',      // Z_NEED_DICT      (2)
+    'stream end',           // Z_STREAM_END     (1)
+    '',                     // Z_OK             (0)
+    'file error',           // Z_ERRNO          (-1)
+    'stream error',         // Z_STREAM_ERROR   (-2)
+    'data error',           // Z_DATA_ERROR     (-3)
+    'insufficient memory',  // Z_MEM_ERROR      (-4)
+    'buffer error',         // Z_BUF_ERROR      (-5)
+    'incompatible version', // Z_VERSION_ERROR  (-6)
+    ''
+  );
+
+{$L deflate.obj}
+{$L inflate.obj}
+{$L inftrees.obj}
+{$L trees.obj}
+{$L adler32.obj}
+{$L infblock.obj}
+{$L infcodes.obj}
+{$L infutil.obj}
+{$L inffast.obj}
+
+procedure _tr_init; external;
+procedure _tr_tally; external;
+procedure _tr_flush_block; external;
+procedure _tr_align; external;
+procedure _tr_stored_block; external;
+function adler32; external;
+procedure inflate_blocks_new; external;
+procedure inflate_blocks; external;
+procedure inflate_blocks_reset; external;
+procedure inflate_blocks_free; external;
+procedure inflate_set_dictionary; external;
+procedure inflate_trees_bits; external;
+procedure inflate_trees_dynamic; external;
+procedure inflate_trees_fixed; external;
+procedure inflate_codes_new; external;
+procedure inflate_codes; external;
+procedure inflate_codes_free; external;
+procedure _inflate_mask; external;
+procedure inflate_flush; external;
+procedure inflate_fast; external;
+
+procedure _memset(P: Pointer; B: Byte; count: Integer);cdecl;
+begin
+  FillChar(P^, count, B);
+end;
+
+procedure _memcpy(dest, source: Pointer; count: Integer);cdecl;
+begin
+  Move(source^, dest^, count);
+end;
+
+
+
+// deflate compresses data
+function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
+  recsize: Integer): Integer; external;
+function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function deflateEnd(var strm: TZStreamRec): Integer; external;
+
+// inflate decompresses data
+function inflateInit_(var strm: TZStreamRec; version: PChar;
+  recsize: Integer): Integer; external;
+function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function inflateEnd(var strm: TZStreamRec): Integer; external;
+function inflateReset(var strm: TZStreamRec): Integer; external;
+
+
+function zcalloc(AppData: Pointer; Items, Size: Integer): Pointer;
+begin
+  GetMem(Result, Items*Size);
+end;
+
+procedure zcfree(AppData, Block: Pointer);
+begin
+  FreeMem(Block);
+end;
+
+function zlibCheck(code: Integer): Integer;
+begin
+  Result := code;
+  if code < 0 then
+    raise EZlibError.Create('error');    //!!
+end;
+
+function CCheck(code: Integer): Integer;
+begin
+  Result := code;
+  if code < 0 then
+    raise ECompressionError.Create('error'); //!!
+end;
+
+function DCheck(code: Integer): Integer;
+begin
+  Result := code;
+  if code < 0 then
+    raise EDecompressionError.Create('error');  //!!
+end;
+
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+                      out OutBuf: Pointer; out OutBytes: Integer);
+var
+  strm: TZStreamRec;
+  P: Pointer;
+begin
+  FillChar(strm, sizeof(strm), 0);
+  OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
+  GetMem(OutBuf, OutBytes);
+  try
+    strm.next_in := InBuf;
+    strm.avail_in := InBytes;
+    strm.next_out := OutBuf;
+    strm.avail_out := OutBytes;
+    CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
+    try
+      while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
+      begin
+        P := OutBuf;
+        Inc(OutBytes, 256);
+        ReallocMem(OutBuf, OutBytes);
+        strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+        strm.avail_out := 256;
+      end;
+    finally
+      CCheck(deflateEnd(strm));
+    end;
+    ReallocMem(OutBuf, strm.total_out);
+    OutBytes := strm.total_out;
+  except
+    FreeMem(OutBuf);
+    raise
+  end;
+end;
+
+
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+  OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+var
+  strm: TZStreamRec;
+  P: Pointer;
+  BufInc: Integer;
+begin
+  FillChar(strm, sizeof(strm), 0);
+  BufInc := (InBytes + 255) and not 255;
+  if OutEstimate = 0 then
+    OutBytes := BufInc
+  else
+    OutBytes := OutEstimate;
+  GetMem(OutBuf, OutBytes);
+  try
+    strm.next_in := InBuf;
+    strm.avail_in := InBytes;
+    strm.next_out := OutBuf;
+    strm.avail_out := OutBytes;
+    DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+    try
+      while DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END do
+      begin
+        P := OutBuf;
+        Inc(OutBytes, BufInc);
+        ReallocMem(OutBuf, OutBytes);
+        strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+        strm.avail_out := BufInc;
+      end;
+    finally
+      DCheck(inflateEnd(strm));
+    end;
+    ReallocMem(OutBuf, strm.total_out);
+    OutBytes := strm.total_out;
+  except
+    FreeMem(OutBuf);
+    raise
+  end;
+end;
+
+
+// TCustomZlibStream
+
+constructor TCustomZLibStream.Create(Strm: TStream);
+begin
+  inherited Create;
+  FStrm := Strm;
+  FStrmPos := Strm.Position;
+end;
+
+procedure TCustomZLibStream.Progress(Sender: TObject);
+begin
+  if Assigned(FOnProgress) then FOnProgress(Sender);
+end;
+
+
+// TCompressionStream
+
+constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
+  Dest: TStream);
+const
+  Levels: array [TCompressionLevel] of ShortInt =
+    (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
+begin
+  inherited Create(Dest);
+  FZRec.next_out := FBuffer;
+  FZRec.avail_out := sizeof(FBuffer);
+  CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
+end;
+
+destructor TCompressionStream.Destroy;
+begin
+  FZRec.next_in := nil;
+  FZRec.avail_in := 0;
+  try
+    if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+    while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
+      and (FZRec.avail_out = 0) do
+    begin
+      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+      FZRec.next_out := FBuffer;
+      FZRec.avail_out := sizeof(FBuffer);
+    end;
+    if FZRec.avail_out < sizeof(FBuffer) then
+      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
+  finally
+    deflateEnd(FZRec);
+  end;
+  inherited Destroy;
+end;
+
+function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+  raise ECompressionError.Create('Invalid stream operation');
+end;
+
+function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+  FZRec.next_in := @Buffer;
+  FZRec.avail_in := Count;
+  if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+  while (FZRec.avail_in > 0) do
+  begin
+    CCheck(deflate(FZRec, 0));
+    if FZRec.avail_out = 0 then
+    begin
+      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+      FZRec.next_out := FBuffer;
+      FZRec.avail_out := sizeof(FBuffer);
+      FStrmPos := FStrm.Position;
+      Progress(Self);
+    end;
+  end;
+  Result := Count;
+end;
+
+function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+  if (Offset = 0) and (Origin = soFromCurrent) then
+    Result := FZRec.total_in
+  else
+    raise ECompressionError.Create('Invalid stream operation');
+end;
+
+function TCompressionStream.GetCompressionRate: Single;
+begin
+  if FZRec.total_in = 0 then
+    Result := 0
+  else
+    Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
+end;
+
+
+// TDecompressionStream
+
+constructor TDecompressionStream.Create(Source: TStream);
+begin
+  inherited Create(Source);
+  FZRec.next_in := FBuffer;
+  FZRec.avail_in := 0;
+  DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
+end;
+
+destructor TDecompressionStream.Destroy;
+begin
+  inflateEnd(FZRec);
+  inherited Destroy;
+end;
+
+function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+  FZRec.next_out := @Buffer;
+  FZRec.avail_out := Count;
+  if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+  while (FZRec.avail_out > 0) do
+  begin
+    if FZRec.avail_in = 0 then
+    begin
+      FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
+      if FZRec.avail_in = 0 then
+        begin
+          Result := Count - FZRec.avail_out;
+          Exit;
+        end;
+      FZRec.next_in := FBuffer;
+      FStrmPos := FStrm.Position;
+      Progress(Self);
+    end;
+    DCheck(inflate(FZRec, 0));
+  end;
+  Result := Count;
+end;
+
+function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+  raise EDecompressionError.Create('Invalid stream operation');
+end;
+
+function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+  I: Integer;
+  Buf: array [0..4095] of Char;
+begin
+  if (Offset = 0) and (Origin = soFromBeginning) then
+  begin
+    DCheck(inflateReset(FZRec));
+    FZRec.next_in := FBuffer;
+    FZRec.avail_in := 0;
+    FStrm.Position := 0;
+    FStrmPos := 0;
+  end
+  else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
+          ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
+  begin
+    if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
+    if Offset > 0 then
+    begin
+      for I := 1 to Offset div sizeof(Buf) do
+        ReadBuffer(Buf, sizeof(Buf));
+      ReadBuffer(Buf, Offset mod sizeof(Buf));
+    end;
+  end
+  else
+    raise EDecompressionError.Create('Invalid stream operation');
+  Result := FZRec.total_out;
+end;
+
+end.
diff --git a/lib/zlib/contrib/delphi2/zlib32.bpr b/lib/zlib/contrib/delphi2/zlib32.bpr
new file mode 100644 (file)
index 0000000..cabcec4
--- /dev/null
@@ -0,0 +1,174 @@
+# ---------------------------------------------------------------------------
+!if !$d(BCB)
+BCB = $(MAKEDIR)\..
+!endif
+
+# ---------------------------------------------------------------------------
+# IDE SECTION
+# ---------------------------------------------------------------------------
+# The following section of the project makefile is managed by the BCB IDE.
+# It is recommended to use the IDE to change any of the values in this
+# section.
+# ---------------------------------------------------------------------------
+
+VERSION = BCB.03
+# ---------------------------------------------------------------------------
+PROJECT = zlib32.dll
+OBJFILES = zlib32.obj adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infblock.obj \
+  infcodes.obj inffast.obj inflate.obj inftrees.obj infutil.obj trees.obj \
+  uncompr.obj zutil.obj
+RESFILES =
+RESDEPEN = $(RESFILES)
+LIBFILES =
+LIBRARIES = 
+SPARELIBS = 
+DEFFILE =
+PACKAGES = VCLX35.bpi VCL35.bpi VCLDB35.bpi VCLDBX35.bpi ibsmp35.bpi bcbsmp35.bpi \
+  dclocx35.bpi QRPT35.bpi TEEUI35.bpi TEEDB35.bpi TEE35.bpi DSS35.bpi \
+  NMFAST35.bpi INETDB35.bpi INET35.bpi VCLMID35.bpi
+# ---------------------------------------------------------------------------
+PATHCPP = .;
+PATHASM = .;
+PATHPAS = .;
+PATHRC = .;
+DEBUGLIBPATH = $(BCB)\lib\debug
+RELEASELIBPATH = $(BCB)\lib\release
+# ---------------------------------------------------------------------------
+CFLAG1 = -WD -O2 -Ve -d -k- -vi -c -tWD
+CFLAG2 = -D_NO_VCL;ZLIB_DLL -I$(BCB)\include
+CFLAG3 = -ff -5
+PFLAGS = -D_NO_VCL;ZLIB_DLL -U$(BCB)\lib;$(RELEASELIBPATH) -I$(BCB)\include -$I- -v \
+  -JPHN -M
+RFLAGS = -D_NO_VCL;ZLIB_DLL -i$(BCB)\include
+AFLAGS = /i$(BCB)\include /d_NO_VCL /dZLIB_DLL /mx /w2 /zn
+LFLAGS = -L$(BCB)\lib;$(RELEASELIBPATH) -aa -Tpd -x -Gi
+IFLAGS = -Gn -g
+# ---------------------------------------------------------------------------
+ALLOBJ = c0d32.obj $(OBJFILES)
+ALLRES = $(RESFILES)
+ALLLIB = $(LIBFILES)  import32.lib cw32mt.lib
+# ---------------------------------------------------------------------------
+!ifdef IDEOPTIONS
+
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=1
+Locale=1040
+CodePage=1252
+
+[Version Info Keys]
+CompanyName=
+FileDescription=DLL (GUI)
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+
+[HistoryLists\hlIncludePath]
+Count=1
+Item0=$(BCB)\include
+
+[HistoryLists\hlLibraryPath]
+Count=1
+Item0=$(BCB)\lib
+
+[HistoryLists\hlConditionals]
+Count=1
+Item0=_NO_VCL;ZLIB_DLL
+
+[Debugging]
+DebugSourceDirs=
+
+[Parameters]
+RunParams=
+HostApplication=
+
+!endif
+
+# ---------------------------------------------------------------------------
+# MAKE SECTION
+# ---------------------------------------------------------------------------
+# This section of the project file is not used by the BCB IDE.  It is for
+# the benefit of building from the command-line using the MAKE utility.
+# ---------------------------------------------------------------------------
+
+.autodepend
+# ---------------------------------------------------------------------------
+!if !$d(BCC32)
+BCC32 = bcc32
+!endif
+
+!if !$d(DCC32)
+DCC32 = dcc32
+!endif
+
+!if !$d(TASM32)
+TASM32 = tasm32
+!endif
+
+!if !$d(LINKER)
+LINKER = ilink32
+!endif
+
+!if !$d(BRCC32)
+BRCC32 = brcc32
+!endif
+# ---------------------------------------------------------------------------
+!if $d(PATHCPP)
+.PATH.CPP = $(PATHCPP)
+.PATH.C   = $(PATHCPP)
+!endif
+
+!if $d(PATHPAS)
+.PATH.PAS = $(PATHPAS)
+!endif
+
+!if $d(PATHASM)
+.PATH.ASM = $(PATHASM)
+!endif
+
+!if $d(PATHRC)
+.PATH.RC  = $(PATHRC)
+!endif
+# ---------------------------------------------------------------------------
+$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
+    $(BCB)\BIN\$(LINKER) @&&!
+    $(LFLAGS) $(IFLAGS) +
+    $(ALLOBJ), +
+    $(PROJECT),, +
+    $(ALLLIB), +
+    $(DEFFILE), +
+    $(ALLRES)
+!
+# ---------------------------------------------------------------------------
+.pas.hpp:
+    $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.pas.obj:
+    $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< }
+
+.cpp.obj:
+    $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.c.obj:
+    $(BCB)\BIN\$(BCC32) $(CFLAG1) $(CFLAG2) $(CFLAG3) -n$(@D) {$< }
+
+.asm.obj:
+    $(BCB)\BIN\$(TASM32) $(AFLAGS) $<, $@
+
+.rc.res:
+    $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $<
+# ---------------------------------------------------------------------------
diff --git a/lib/zlib/contrib/delphi2/zlib32.cpp b/lib/zlib/contrib/delphi2/zlib32.cpp
new file mode 100644 (file)
index 0000000..7372f6b
--- /dev/null
@@ -0,0 +1,42 @@
+
+#include <windows.h>
+#pragma hdrstop
+#include <condefs.h>
+
+
+//---------------------------------------------------------------------------
+//   Important note about DLL memory management in a VCL DLL:
+//
+//
+//
+// If your DLL uses VCL and exports any functions that pass VCL String objects
+// (or structs/classes containing nested Strings) as parameter or function
+// results, you will need to build both your DLL project and any EXE projects
+// that use your DLL with the dynamic RTL (the RTL DLL).  This will change your
+// DLL and its calling EXE's to use BORLNDMM.DLL as their memory manager. In
+// these cases, the file BORLNDMM.DLL should be deployed along with your DLL
+// and the RTL DLL (CP3240MT.DLL). To avoid the requiring BORLNDMM.DLL in
+// these situations, pass string information using "char *" or ShortString
+// parameters and then link with the static RTL.
+//
+//---------------------------------------------------------------------------
+USEUNIT("adler32.c");
+USEUNIT("compress.c");
+USEUNIT("crc32.c");
+USEUNIT("deflate.c");
+USEUNIT("gzio.c");
+USEUNIT("infblock.c");
+USEUNIT("infcodes.c");
+USEUNIT("inffast.c");
+USEUNIT("inflate.c");
+USEUNIT("inftrees.c");
+USEUNIT("infutil.c");
+USEUNIT("trees.c");
+USEUNIT("uncompr.c");
+USEUNIT("zutil.c");
+//---------------------------------------------------------------------------
+#pragma argsused
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+{
+        return 1;
+}
diff --git a/lib/zlib/contrib/iostream/test.cpp b/lib/zlib/contrib/iostream/test.cpp
new file mode 100644 (file)
index 0000000..7d265b3
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include "zfstream.h"
+
+int main() {
+
+  // Construct a stream object with this filebuffer.  Anything sent
+  // to this stream will go to standard out.
+  gzofstream os( 1, ios::out );
+
+  // This text is getting compressed and sent to stdout.
+  // To prove this, run 'test | zcat'.
+  os << "Hello, Mommy" << endl;
+
+  os << setcompressionlevel( Z_NO_COMPRESSION );
+  os << "hello, hello, hi, ho!" << endl;
+
+  setcompressionlevel( os, Z_DEFAULT_COMPRESSION )
+    << "I'm compressing again" << endl;
+
+  os.close();
+
+  return 0;
+
+}
diff --git a/lib/zlib/contrib/iostream/zfstream.cpp b/lib/zlib/contrib/iostream/zfstream.cpp
new file mode 100644 (file)
index 0000000..a690bbe
--- /dev/null
@@ -0,0 +1,329 @@
+
+#include <memory.h>
+#include "zfstream.h"
+
+gzfilebuf::gzfilebuf() :
+  file(NULL),
+  mode(0),
+  own_file_descriptor(0)
+{ }
+
+gzfilebuf::~gzfilebuf() {
+
+  sync();
+  if ( own_file_descriptor )
+    close();
+
+}
+
+gzfilebuf *gzfilebuf::open( const char *name,
+                           int io_mode ) {
+
+  if ( is_open() )
+    return NULL;
+
+  char char_mode[10];
+  char *p;
+  memset(char_mode,'\0',10);
+  p = char_mode;
+
+  if ( io_mode & ios::in ) {
+    mode = ios::in;
+    *p++ = 'r';
+  } else if ( io_mode & ios::app ) {
+    mode = ios::app;
+    *p++ = 'a';
+  } else {
+    mode = ios::out;
+    *p++ = 'w';
+  }
+
+  if ( io_mode & ios::binary ) {
+    mode |= ios::binary;
+    *p++ = 'b';
+  }
+
+  // Hard code the compression level
+  if ( io_mode & (ios::out|ios::app )) {
+    *p++ = '9';
+  }
+
+  if ( (file = gzopen(name, char_mode)) == NULL )
+    return NULL;
+
+  own_file_descriptor = 1;
+
+  return this;
+
+}
+
+gzfilebuf *gzfilebuf::attach( int file_descriptor,
+                             int io_mode ) {
+
+  if ( is_open() )
+    return NULL;
+
+  char char_mode[10];
+  char *p;
+  memset(char_mode,'\0',10);
+  p = char_mode;
+
+  if ( io_mode & ios::in ) {
+    mode = ios::in;
+    *p++ = 'r';
+  } else if ( io_mode & ios::app ) {
+    mode = ios::app;
+    *p++ = 'a';
+  } else {
+    mode = ios::out;
+    *p++ = 'w';
+  }
+
+  if ( io_mode & ios::binary ) {
+    mode |= ios::binary;
+    *p++ = 'b';
+  }
+
+  // Hard code the compression level
+  if ( io_mode & (ios::out|ios::app )) {
+    *p++ = '9';
+  }
+
+  if ( (file = gzdopen(file_descriptor, char_mode)) == NULL )
+    return NULL;
+
+  own_file_descriptor = 0;
+
+  return this;
+
+}
+
+gzfilebuf *gzfilebuf::close() {
+
+  if ( is_open() ) {
+
+    sync();
+    gzclose( file );
+    file = NULL;
+
+  }
+
+  return this;
+
+}
+
+int gzfilebuf::setcompressionlevel( short comp_level ) {
+
+  return gzsetparams(file, comp_level, -2);
+
+}
+
+int gzfilebuf::setcompressionstrategy( short comp_strategy ) {
+
+  return gzsetparams(file, -2, comp_strategy);
+
+}
+
+
+streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) {
+
+  return streampos(EOF);
+
+}
+
+int gzfilebuf::underflow() {
+
+  // If the file hasn't been opened for reading, error.
+  if ( !is_open() || !(mode & ios::in) )
+    return EOF;
+
+  // if a buffer doesn't exists, allocate one.
+  if ( !base() ) {
+
+    if ( (allocate()) == EOF )
+      return EOF;
+    setp(0,0);
+
+  } else {
+
+    if ( in_avail() )
+      return (unsigned char) *gptr();
+
+    if ( out_waiting() ) {
+      if ( flushbuf() == EOF )
+       return EOF;
+    }
+
+  }
+
+  // Attempt to fill the buffer.
+
+  int result = fillbuf();
+  if ( result == EOF ) {
+    // disable get area
+    setg(0,0,0);
+    return EOF;
+  }
+
+  return (unsigned char) *gptr();
+
+}
+
+int gzfilebuf::overflow( int c ) {
+
+  if ( !is_open() || !(mode & ios::out) )
+    return EOF;
+
+  if ( !base() ) {
+    if ( allocate() == EOF )
+      return EOF;
+    setg(0,0,0);
+  } else {
+    if (in_avail()) {
+       return EOF;
+    }
+    if (out_waiting()) {
+      if (flushbuf() == EOF)
+       return EOF;
+    }
+  }
+
+  int bl = blen();
+  setp( base(), base() + bl);
+
+  if ( c != EOF ) {
+
+    *pptr() = c;
+    pbump(1);
+
+  }
+
+  return 0;
+
+}
+
+int gzfilebuf::sync() {
+
+  if ( !is_open() )
+    return EOF;
+
+  if ( out_waiting() )
+    return flushbuf();
+
+  return 0;
+
+}
+
+int gzfilebuf::flushbuf() {
+
+  int n;
+  char *q;
+
+  q = pbase();
+  n = pptr() - q;
+
+  if ( gzwrite( file, q, n) < n )
+    return EOF;
+
+  setp(0,0);
+
+  return 0;
+
+}
+
+int gzfilebuf::fillbuf() {
+
+  int required;
+  char *p;
+
+  p = base();
+
+  required = blen();
+
+  int t = gzread( file, p, required );
+
+  if ( t <= 0) return EOF;
+
+  setg( base(), base(), base()+t);
+
+  return t;
+
+}
+
+gzfilestream_common::gzfilestream_common() :
+  ios( gzfilestream_common::rdbuf() )
+{ }
+
+gzfilestream_common::~gzfilestream_common()
+{ }
+
+void gzfilestream_common::attach( int fd, int io_mode ) {
+
+  if ( !buffer.attach( fd, io_mode) )
+    clear( ios::failbit | ios::badbit );
+  else
+    clear();
+
+}
+
+void gzfilestream_common::open( const char *name, int io_mode ) {
+
+  if ( !buffer.open( name, io_mode ) )
+    clear( ios::failbit | ios::badbit );
+  else
+    clear();
+
+}
+
+void gzfilestream_common::close() {
+
+  if ( !buffer.close() )
+    clear( ios::failbit | ios::badbit );
+
+}
+
+gzfilebuf *gzfilestream_common::rdbuf() {
+
+  return &buffer;
+
+}
+     
+gzifstream::gzifstream() :
+  ios( gzfilestream_common::rdbuf() )
+{
+  clear( ios::badbit );
+}
+
+gzifstream::gzifstream( const char *name, int io_mode ) :
+  ios( gzfilestream_common::rdbuf() )
+{
+  gzfilestream_common::open( name, io_mode );
+}
+
+gzifstream::gzifstream( int fd, int io_mode ) :
+  ios( gzfilestream_common::rdbuf() )
+{
+  gzfilestream_common::attach( fd, io_mode );
+}
+
+gzifstream::~gzifstream() { }
+
+gzofstream::gzofstream() :
+  ios( gzfilestream_common::rdbuf() )
+{
+  clear( ios::badbit );
+}
+
+gzofstream::gzofstream( const char *name, int io_mode ) :
+  ios( gzfilestream_common::rdbuf() )
+{
+  gzfilestream_common::open( name, io_mode );
+}
+
+gzofstream::gzofstream( int fd, int io_mode ) :
+  ios( gzfilestream_common::rdbuf() )
+{
+  gzfilestream_common::attach( fd, io_mode );
+}
+
+gzofstream::~gzofstream() { }
diff --git a/lib/zlib/contrib/iostream/zfstream.h b/lib/zlib/contrib/iostream/zfstream.h
new file mode 100644 (file)
index 0000000..c87fa08
--- /dev/null
@@ -0,0 +1,142 @@
+
+#ifndef _zfstream_h
+#define _zfstream_h
+
+#include <fstream.h>
+#include "zlib.h"
+
+class gzfilebuf : public streambuf {
+
+public:
+
+  gzfilebuf( );
+  virtual ~gzfilebuf();
+
+  gzfilebuf *open( const char *name, int io_mode );
+  gzfilebuf *attach( int file_descriptor, int io_mode );
+  gzfilebuf *close();
+
+  int setcompressionlevel( short comp_level );
+  int setcompressionstrategy( short comp_strategy );
+
+  inline int is_open() const { return (file !=NULL); }
+
+  virtual streampos seekoff( streamoff, ios::seek_dir, int );
+
+  virtual int sync();
+
+protected:
+
+  virtual int underflow();
+  virtual int overflow( int = EOF );
+
+private:
+
+  gzFile file;
+  short mode;
+  short own_file_descriptor;
+
+  int flushbuf();
+  int fillbuf();
+
+};
+
+class gzfilestream_common : virtual public ios {
+
+  friend class gzifstream;
+  friend class gzofstream;
+  friend gzofstream &setcompressionlevel( gzofstream &, int );
+  friend gzofstream &setcompressionstrategy( gzofstream &, int );
+
+public:
+  virtual ~gzfilestream_common();
+
+  void attach( int fd, int io_mode );
+  void open( const char *name, int io_mode );
+  void close();
+
+protected:
+  gzfilestream_common();
+
+private:
+  gzfilebuf *rdbuf();
+
+  gzfilebuf buffer;
+
+};
+
+class gzifstream : public gzfilestream_common, public istream {
+
+public:
+
+  gzifstream();
+  gzifstream( const char *name, int io_mode = ios::in );
+  gzifstream( int fd, int io_mode = ios::in );
+
+  virtual ~gzifstream();
+
+};
+
+class gzofstream : public gzfilestream_common, public ostream {
+
+public:
+
+  gzofstream();
+  gzofstream( const char *name, int io_mode = ios::out );
+  gzofstream( int fd, int io_mode = ios::out );
+
+  virtual ~gzofstream();
+
+};
+
+template<class T> class gzomanip {
+  friend gzofstream &operator<<(gzofstream &, const gzomanip<T> &);
+public:
+  gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { }
+private:
+  gzofstream &(*func)(gzofstream &, T);
+  T val;
+};
+
+template<class T> gzofstream &operator<<(gzofstream &s,
+                                        const gzomanip<T> &m) {
+  return (*m.func)(s, m.val);
+  
+}
+
+inline gzofstream &setcompressionlevel( gzofstream &s, int l ) {
+  (s.rdbuf())->setcompressionlevel(l);
+  return s;
+}
+
+inline gzofstream &setcompressionstrategy( gzofstream &s, int l ) {
+  (s.rdbuf())->setcompressionstrategy(l);
+  return s;
+}
+
+inline gzomanip<int> setcompressionlevel(int l)
+{
+  return gzomanip<int>(&setcompressionlevel,l);
+}
+
+inline gzomanip<int> setcompressionstrategy(int l)
+{
+  return gzomanip<int>(&setcompressionstrategy,l);
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/zlib/contrib/iostream2/zstream.h b/lib/zlib/contrib/iostream2/zstream.h
new file mode 100644 (file)
index 0000000..861ef2b
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ *
+ * Copyright (c) 1997
+ * Christian Michelsen Research AS
+ * Advanced Computing
+ * Fantoftvegen 38, 5036 BERGEN, Norway
+ * http://www.cmr.no
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  Christian Michelsen Research AS makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef ZSTREAM__H
+#define ZSTREAM__H
+
+/*
+ * zstream.h - C++ interface to the 'zlib' general purpose compression library
+ * $Id$
+ */
+
+#include <strstream.h>
+#include <string.h>
+#include <stdio.h>
+#include "zlib.h"
+
+#if defined(_WIN32)
+#   include <fcntl.h>
+#   include <io.h>
+#   define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+#   define SET_BINARY_MODE(file)
+#endif
+
+class zstringlen {
+public:
+    zstringlen(class izstream&);
+    zstringlen(class ozstream&, const char*);
+    size_t value() const { return val.word; }
+private:
+    struct Val { unsigned char byte; size_t word; } val;
+};
+
+//  ----------------------------- izstream -----------------------------
+
+class izstream
+{
+    public:
+        izstream() : m_fp(0) {}
+        izstream(FILE* fp) : m_fp(0) { open(fp); }
+        izstream(const char* name) : m_fp(0) { open(name); }
+        ~izstream() { close(); }
+
+        /* Opens a gzip (.gz) file for reading.
+         * open() can be used to read a file which is not in gzip format;
+         * in this case read() will directly read from the file without
+         * decompression. errno can be checked to distinguish two error
+         * cases (if errno is zero, the zlib error is Z_MEM_ERROR).
+         */
+        void open(const char* name) {
+            if (m_fp) close();
+            m_fp = ::gzopen(name, "rb");
+        }
+
+        void open(FILE* fp) {
+            SET_BINARY_MODE(fp);
+            if (m_fp) close();
+            m_fp = ::gzdopen(fileno(fp), "rb");
+        }
+
+        /* Flushes all pending input if necessary, closes the compressed file
+         * and deallocates all the (de)compression state. The return value is
+         * the zlib error number (see function error() below).
+         */
+        int close() {
+            int r = ::gzclose(m_fp);
+            m_fp = 0; return r;
+        }
+
+        /* Binary read the given number of bytes from the compressed file.
+         */
+        int read(void* buf, size_t len) {
+            return ::gzread(m_fp, buf, len);
+        }
+
+        /* Returns the error message for the last error which occurred on the
+         * given compressed file. errnum is set to zlib error number. If an
+         * error occurred in the file system and not in the compression library,
+         * errnum is set to Z_ERRNO and the application may consult errno
+         * to get the exact error code.
+         */
+        const char* error(int* errnum) {
+            return ::gzerror(m_fp, errnum);
+        }
+
+        gzFile fp() { return m_fp; }
+
+    private:
+        gzFile m_fp;
+};
+
+/*
+ * Binary read the given (array of) object(s) from the compressed file.
+ * If the input file was not in gzip format, read() copies the objects number
+ * of bytes into the buffer.
+ * returns the number of uncompressed bytes actually read
+ * (0 for end of file, -1 for error).
+ */
+template <class T, class Items>
+inline int read(izstream& zs, T* x, Items items) {
+    return ::gzread(zs.fp(), x, items*sizeof(T));
+}
+
+/*
+ * Binary input with the '>' operator.
+ */
+template <class T>
+inline izstream& operator>(izstream& zs, T& x) {
+    ::gzread(zs.fp(), &x, sizeof(T));
+    return zs;
+}
+
+
+inline zstringlen::zstringlen(izstream& zs) {
+    zs > val.byte;
+    if (val.byte == 255) zs > val.word;
+    else val.word = val.byte;
+}
+
+/*
+ * Read length of string + the string with the '>' operator.
+ */
+inline izstream& operator>(izstream& zs, char* x) {
+    zstringlen len(zs);
+    ::gzread(zs.fp(), x, len.value());
+    x[len.value()] = '\0';
+    return zs;
+}
+
+inline char* read_string(izstream& zs) {
+    zstringlen len(zs);
+    char* x = new char[len.value()+1];
+    ::gzread(zs.fp(), x, len.value());
+    x[len.value()] = '\0';
+    return x;
+}
+
+// ----------------------------- ozstream -----------------------------
+
+class ozstream
+{
+    public:
+        ozstream() : m_fp(0), m_os(0) {
+        }
+        ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION)
+            : m_fp(0), m_os(0) {
+            open(fp, level);
+        }
+        ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION)
+            : m_fp(0), m_os(0) {
+            open(name, level);
+        }
+        ~ozstream() {
+            close();
+        }
+
+        /* Opens a gzip (.gz) file for writing.
+         * The compression level parameter should be in 0..9
+         * errno can be checked to distinguish two error cases
+         * (if errno is zero, the zlib error is Z_MEM_ERROR).
+         */
+        void open(const char* name, int level = Z_DEFAULT_COMPRESSION) {
+            char mode[4] = "wb\0";
+            if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+            if (m_fp) close();
+            m_fp = ::gzopen(name, mode);
+        }
+
+        /* open from a FILE pointer.
+         */
+        void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) {
+            SET_BINARY_MODE(fp);
+            char mode[4] = "wb\0";
+            if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+            if (m_fp) close();
+            m_fp = ::gzdopen(fileno(fp), mode);
+        }
+
+        /* Flushes all pending output if necessary, closes the compressed file
+         * and deallocates all the (de)compression state. The return value is
+         * the zlib error number (see function error() below).
+         */
+        int close() {
+            if (m_os) {
+                ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+                delete[] m_os->str(); delete m_os; m_os = 0;
+            }
+            int r = ::gzclose(m_fp); m_fp = 0; return r;
+        }
+
+        /* Binary write the given number of bytes into the compressed file.
+         */
+        int write(const void* buf, size_t len) {
+            return ::gzwrite(m_fp, (voidp) buf, len);
+        }
+
+        /* Flushes all pending output into the compressed file. The parameter
+         * _flush is as in the deflate() function. The return value is the zlib
+         * error number (see function gzerror below). flush() returns Z_OK if
+         * the flush_ parameter is Z_FINISH and all output could be flushed.
+         * flush() should be called only when strictly necessary because it can
+         * degrade compression.
+         */
+        int flush(int _flush) {
+            os_flush();
+            return ::gzflush(m_fp, _flush);
+        }
+
+        /* Returns the error message for the last error which occurred on the
+         * given compressed file. errnum is set to zlib error number. If an
+         * error occurred in the file system and not in the compression library,
+         * errnum is set to Z_ERRNO and the application may consult errno
+         * to get the exact error code.
+         */
+        const char* error(int* errnum) {
+            return ::gzerror(m_fp, errnum);
+        }
+
+        gzFile fp() { return m_fp; }
+
+        ostream& os() {
+            if (m_os == 0) m_os = new ostrstream;
+            return *m_os;
+        }
+
+        void os_flush() {
+            if (m_os && m_os->pcount()>0) {
+                ostrstream* oss = new ostrstream;
+                oss->fill(m_os->fill());
+                oss->flags(m_os->flags());
+                oss->precision(m_os->precision());
+                oss->width(m_os->width());
+                ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+                delete[] m_os->str(); delete m_os; m_os = oss;
+            }
+        }
+
+    private:
+        gzFile m_fp;
+        ostrstream* m_os;
+};
+
+/*
+ * Binary write the given (array of) object(s) into the compressed file.
+ * returns the number of uncompressed bytes actually written
+ * (0 in case of error).
+ */
+template <class T, class Items>
+inline int write(ozstream& zs, const T* x, Items items) {
+    return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T));
+}
+
+/*
+ * Binary output with the '<' operator.
+ */
+template <class T>
+inline ozstream& operator<(ozstream& zs, const T& x) {
+    ::gzwrite(zs.fp(), (voidp) &x, sizeof(T));
+    return zs;
+}
+
+inline zstringlen::zstringlen(ozstream& zs, const char* x) {
+    val.byte = 255;  val.word = ::strlen(x);
+    if (val.word < 255) zs < (val.byte = val.word);
+    else zs < val;
+}
+
+/*
+ * Write length of string + the string with the '<' operator.
+ */
+inline ozstream& operator<(ozstream& zs, const char* x) {
+    zstringlen len(zs, x);
+    ::gzwrite(zs.fp(), (voidp) x, len.value());
+    return zs;
+}
+
+#ifdef _MSC_VER
+inline ozstream& operator<(ozstream& zs, char* const& x) {
+    return zs < (const char*) x;
+}
+#endif
+
+/*
+ * Ascii write with the << operator;
+ */
+template <class T>
+inline ostream& operator<<(ozstream& zs, const T& x) {
+    zs.os_flush();
+    return zs.os() << x;
+}
+
+#endif
diff --git a/lib/zlib/contrib/iostream2/zstream_test.cpp b/lib/zlib/contrib/iostream2/zstream_test.cpp
new file mode 100644 (file)
index 0000000..5bbd56c
--- /dev/null
@@ -0,0 +1,25 @@
+#include "zstream.h"
+#include <math.h>
+#include <stdlib.h>
+#include <iomanip.h>
+
+void main() {
+       char h[256] = "Hello";
+       char* g = "Goodbye";
+       ozstream out("temp.gz");
+    out < "This works well" < h < g;
+    out.close();
+
+    izstream in("temp.gz"); // read it back
+    char *x = read_string(in), *y = new char[256], z[256];
+    in > y > z;
+    in.close();
+    cout << x << endl << y << endl << z << endl;
+
+    out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results
+    out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl;
+    out << z << endl << y << endl << x << endl;
+    out << 1.1234567890123456789 << endl;
+
+    delete[] x; delete[] y;
+}
diff --git a/lib/zlib/contrib/minizip/ChangeLogUnzip b/lib/zlib/contrib/minizip/ChangeLogUnzip
new file mode 100644 (file)
index 0000000..9987c54
--- /dev/null
@@ -0,0 +1,38 @@
+Change in 0.15: (19 Mar 98)
+- fix memory leak in minizip.c
+
+Change in 0.14: (10 Mar 98)
+- fix bugs in minizip.c sample for zipping big file
+- fix problem in month in date handling
+- fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for 
+    comment handling
+
+Change in 0.13: (6 Mar 98)
+- fix bugs in zip.c
+- add real minizip sample
+
+Change in 0.12: (4 Mar 98)
+- add zip.c and zip.h for creates .zip file
+- fix change_file_date in miniunz.c for Unix (Jean-loup Gailly)
+- fix miniunz.c for file without specific record for directory
+
+Change in 0.11: (3 Mar 98)
+- fix bug in unzGetCurrentFileInfo for get extra field and comment
+- enhance miniunz sample, remove the bad unztst.c sample
+
+Change in 0.10: (2 Mar 98)
+- fix bug in unzReadCurrentFile
+- rename unzip* to unz* function and structure
+- remove Windows-like hungary notation variable name
+- modify some structure in unzip.h
+- add somes comment in source
+- remove unzipGetcCurrentFile function
+- replace ZUNZEXPORT by ZEXPORT
+- add unzGetLocalExtrafield for get the local extrafield info
+- add a new sample, miniunz.c
+
+Change in 0.4: (25 Feb 98)
+- suppress the type unzipFileInZip. 
+  Only on file in the zipfile can be open at the same time
+- fix somes typo in code
+- added tm_unz structure in unzip_file_info (date/time in readable format)
diff --git a/lib/zlib/contrib/minizip/Makefile b/lib/zlib/contrib/minizip/Makefile
new file mode 100644 (file)
index 0000000..a1dfc16
--- /dev/null
@@ -0,0 +1,25 @@
+CC=cc
+CFLAGS=-O -I../..
+
+UNZ_OBJS = miniunz.o unzip.o ../../libz.a
+ZIP_OBJS = minizip.o zip.o   ../../libz.a
+
+.c.o:
+       $(CC) -c $(CFLAGS) $*.c
+
+all: miniunz minizip
+
+miniunz:  $(UNZ_OBJS)
+       $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
+
+minizip:  $(ZIP_OBJS)
+       $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
+
+test:  miniunz minizip
+       ./minizip test readme.txt
+       ./miniunz -l test.zip
+       mv readme.txt readme.old
+       ./miniunz test.zip
+
+clean:
+       /bin/rm -f *.o *~ minizip miniunz
diff --git a/lib/zlib/contrib/minizip/miniunz.c b/lib/zlib/contrib/minizip/miniunz.c
new file mode 100644 (file)
index 0000000..f3b7832
--- /dev/null
@@ -0,0 +1,508 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "unzip.h"
+
+#define CASESENSITIVITY (0)
+#define WRITEBUFFERSIZE (8192)
+
+/*
+  mini unzip, demo of unzip package
+
+  usage :
+  Usage : miniunz [-exvlo] file.zip [file_to_extract]
+
+  list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
+    if it exists
+*/
+
+
+/* change_file_date : change the date/time of a file
+    filename : the filename of the file where date/time must be modified
+    dosdate : the new date at the MSDos format (4 bytes)
+    tmu_date : the SAME new date at the tm_unz format */
+void change_file_date(filename,dosdate,tmu_date)
+       const char *filename;
+       uLong dosdate;
+       tm_unz tmu_date;
+{
+#ifdef WIN32
+  HANDLE hFile;
+  FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
+
+  hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE,
+                      0,NULL,OPEN_EXISTING,0,NULL);
+  GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
+  DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
+  LocalFileTimeToFileTime(&ftLocal,&ftm);
+  SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
+  CloseHandle(hFile);
+#else
+#ifdef unix
+  struct utimbuf ut;
+  struct tm newdate;
+  newdate.tm_sec = tmu_date.tm_sec;
+  newdate.tm_min=tmu_date.tm_min;
+  newdate.tm_hour=tmu_date.tm_hour;
+  newdate.tm_mday=tmu_date.tm_mday;
+  newdate.tm_mon=tmu_date.tm_mon;
+  if (tmu_date.tm_year > 1900)
+      newdate.tm_year=tmu_date.tm_year - 1900;
+  else
+      newdate.tm_year=tmu_date.tm_year ;
+  newdate.tm_isdst=-1;
+
+  ut.actime=ut.modtime=mktime(&newdate);
+  utime(filename,&ut);
+#endif
+#endif
+}
+
+
+/* mymkdir and change_file_date are not 100 % portable
+   As I don't know well Unix, I wait feedback for the unix portion */
+
+int mymkdir(dirname)
+       const char* dirname;
+{
+    int ret=0;
+#ifdef WIN32
+       ret = mkdir(dirname);
+#else
+#ifdef unix
+       ret = mkdir (dirname,0775);
+#endif
+#endif
+       return ret;
+}
+
+int makedir (newdir)
+    char *newdir;
+{
+  char *buffer ;
+  char *p;
+  int  len = strlen(newdir);  
+
+  if (len <= 0) 
+    return 0;
+
+  buffer = (char*)malloc(len+1);
+  strcpy(buffer,newdir);
+  
+  if (buffer[len-1] == '/') {
+    buffer[len-1] = '\0';
+  }
+  if (mymkdir(buffer) == 0)
+    {
+      free(buffer);
+      return 1;
+    }
+
+  p = buffer+1;
+  while (1)
+    {
+      char hold;
+
+      while(*p && *p != '\\' && *p != '/')
+        p++;
+      hold = *p;
+      *p = 0;
+      if ((mymkdir(buffer) == -1) && (errno == ENOENT))
+        {
+          printf("couldn't create directory %s\n",buffer);
+          free(buffer);
+          return 0;
+        }
+      if (hold == 0)
+        break;
+      *p++ = hold;
+    }
+  free(buffer);
+  return 1;
+}
+
+void do_banner()
+{
+       printf("MiniUnz 0.15, demo of zLib + Unz package written by Gilles Vollant\n");
+       printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n");
+}
+
+void do_help()
+{      
+       printf("Usage : miniunz [-exvlo] file.zip [file_to_extract]\n\n") ;
+}
+
+
+int do_list(uf)
+       unzFile uf;
+{
+       uLong i;
+       unz_global_info gi;
+       int err;
+
+       err = unzGetGlobalInfo (uf,&gi);
+       if (err!=UNZ_OK)
+               printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+    printf(" Length  Method   Size  Ratio   Date    Time   CRC-32     Name\n");
+    printf(" ------  ------   ----  -----   ----    ----   ------     ----\n");
+       for (i=0;i<gi.number_entry;i++)
+       {
+               char filename_inzip[256];
+               unz_file_info file_info;
+               uLong ratio=0;
+               const char *string_method;
+               err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+               if (err!=UNZ_OK)
+               {
+                       printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+                       break;
+               }
+               if (file_info.uncompressed_size>0)
+                       ratio = (file_info.compressed_size*100)/file_info.uncompressed_size;
+
+               if (file_info.compression_method==0)
+                       string_method="Stored";
+               else
+               if (file_info.compression_method==Z_DEFLATED)
+               {
+                       uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
+                       if (iLevel==0)
+                         string_method="Defl:N";
+                       else if (iLevel==1)
+                         string_method="Defl:X";
+                       else if ((iLevel==2) || (iLevel==3))
+                         string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
+               }
+               else
+                       string_method="Unkn. ";
+
+               printf("%7lu  %6s %7lu %3lu%%  %2.2lu-%2.2lu-%2.2lu  %2.2lu:%2.2lu  %8.8lx   %s\n",
+                           file_info.uncompressed_size,string_method,file_info.compressed_size,
+                               ratio,
+                               (uLong)file_info.tmu_date.tm_mon + 1,
+                (uLong)file_info.tmu_date.tm_mday,
+                               (uLong)file_info.tmu_date.tm_year % 100,
+                               (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
+                               (uLong)file_info.crc,filename_inzip);
+               if ((i+1)<gi.number_entry)
+               {
+                       err = unzGoToNextFile(uf);
+                       if (err!=UNZ_OK)
+                       {
+                               printf("error %d with zipfile in unzGoToNextFile\n",err);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite)
+       unzFile uf;
+       const int* popt_extract_without_path;
+    int* popt_overwrite;
+{
+       char filename_inzip[256];
+       char* filename_withoutpath;
+       char* p;
+    int err=UNZ_OK;
+    FILE *fout=NULL;
+    void* buf;
+    uInt size_buf;
+       
+       unz_file_info file_info;
+       uLong ratio=0;
+       err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+
+       if (err!=UNZ_OK)
+       {
+               printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+               return err;
+       }
+
+    size_buf = WRITEBUFFERSIZE;
+    buf = (void*)malloc(size_buf);
+    if (buf==NULL)
+    {
+        printf("Error allocating memory\n");
+        return UNZ_INTERNALERROR;
+    }
+
+       p = filename_withoutpath = filename_inzip;
+       while ((*p) != '\0')
+       {
+               if (((*p)=='/') || ((*p)=='\\'))
+                       filename_withoutpath = p+1;
+               p++;
+       }
+
+       if ((*filename_withoutpath)=='\0')
+       {
+               if ((*popt_extract_without_path)==0)
+               {
+                       printf("creating directory: %s\n",filename_inzip);
+                       mymkdir(filename_inzip);
+               }
+       }
+       else
+       {
+               const char* write_filename;
+               int skip=0;
+
+               if ((*popt_extract_without_path)==0)
+                       write_filename = filename_inzip;
+               else
+                       write_filename = filename_withoutpath;
+
+               err = unzOpenCurrentFile(uf);
+               if (err!=UNZ_OK)
+               {
+                       printf("error %d with zipfile in unzOpenCurrentFile\n",err);
+               }
+
+               if (((*popt_overwrite)==0) && (err==UNZ_OK))
+               {
+                       char rep;
+                       FILE* ftestexist;
+                       ftestexist = fopen(write_filename,"rb");
+                       if (ftestexist!=NULL)
+                       {
+                               fclose(ftestexist);
+                               do
+                               {
+                                       char answer[128];
+                                       printf("The file %s exist. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
+                                       scanf("%1s",answer);
+                                       rep = answer[0] ;
+                                       if ((rep>='a') && (rep<='z'))
+                                               rep -= 0x20;
+                               }
+                               while ((rep!='Y') && (rep!='N') && (rep!='A'));
+                       }
+
+                       if (rep == 'N')
+                               skip = 1;
+
+                       if (rep == 'A')
+                               *popt_overwrite=1;
+               }
+
+               if ((skip==0) && (err==UNZ_OK))
+               {
+                       fout=fopen(write_filename,"wb");
+
+            /* some zipfile don't contain directory alone before file */
+            if ((fout==NULL) && ((*popt_extract_without_path)==0) && 
+                                (filename_withoutpath!=(char*)filename_inzip))
+            {
+                char c=*(filename_withoutpath-1);
+                *(filename_withoutpath-1)='\0';
+                makedir(write_filename);
+                *(filename_withoutpath-1)=c;
+                fout=fopen(write_filename,"wb");
+            }
+
+                       if (fout==NULL)
+                       {
+                               printf("error opening %s\n",write_filename);
+                       }
+               }
+
+               if (fout!=NULL)
+               {
+                       printf(" extracting: %s\n",write_filename);
+
+                       do
+                       {
+                               err = unzReadCurrentFile(uf,buf,size_buf);
+                               if (err<0)      
+                               {
+                                       printf("error %d with zipfile in unzReadCurrentFile\n",err);
+                                       break;
+                               }
+                               if (err>0)
+                                       if (fwrite(buf,err,1,fout)!=1)
+                                       {
+                                               printf("error in writing extracted file\n");
+                        err=UNZ_ERRNO;
+                                               break;
+                                       }
+                       }
+                       while (err>0);
+                       fclose(fout);
+                       if (err==0) 
+                               change_file_date(write_filename,file_info.dosDate,
+                                                    file_info.tmu_date);
+               }
+
+        if (err==UNZ_OK)
+        {
+                   err = unzCloseCurrentFile (uf);
+                   if (err!=UNZ_OK)
+                   {
+                           printf("error %d with zipfile in unzCloseCurrentFile\n",err);
+                   }
+        }
+        else
+            unzCloseCurrentFile(uf); /* don't lose the error */       
+       }
+
+    free(buf);    
+    return err;
+}
+
+
+int do_extract(uf,opt_extract_without_path,opt_overwrite)
+       unzFile uf;
+       int opt_extract_without_path;
+    int opt_overwrite;
+{
+       uLong i;
+       unz_global_info gi;
+       int err;
+       FILE* fout=NULL;        
+
+       err = unzGetGlobalInfo (uf,&gi);
+       if (err!=UNZ_OK)
+               printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+
+       for (i=0;i<gi.number_entry;i++)
+       {
+        if (do_extract_currentfile(uf,&opt_extract_without_path,
+                                      &opt_overwrite) != UNZ_OK)
+            break;
+
+               if ((i+1)<gi.number_entry)
+               {
+                       err = unzGoToNextFile(uf);
+                       if (err!=UNZ_OK)
+                       {
+                               printf("error %d with zipfile in unzGoToNextFile\n",err);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite)
+       unzFile uf;
+       const char* filename;
+       int opt_extract_without_path;
+    int opt_overwrite;
+{
+    int err = UNZ_OK;
+    if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
+    {
+        printf("file %s not found in the zipfile\n",filename);
+        return 2;
+    }
+
+    if (do_extract_currentfile(uf,&opt_extract_without_path,
+                                      &opt_overwrite) == UNZ_OK)
+        return 0;
+    else
+        return 1;
+}
+
+
+int main(argc,argv)
+       int argc;
+       char *argv[];
+{
+       const char *zipfilename=NULL;
+    const char *filename_to_extract=NULL;
+       int i;
+       int opt_do_list=0;
+       int opt_do_extract=1;
+       int opt_do_extract_withoutpath=0;
+       int opt_overwrite=0;
+       char filename_try[512];
+       unzFile uf=NULL;
+
+       do_banner();
+       if (argc==1)
+       {
+               do_help();
+               exit(0);
+       }
+       else
+       {
+               for (i=1;i<argc;i++)
+               {
+                       if ((*argv[i])=='-')
+                       {
+                               const char *p=argv[i]+1;
+                               
+                               while ((*p)!='\0')
+                               {                       
+                                       char c=*(p++);;
+                                       if ((c=='l') || (c=='L'))
+                                               opt_do_list = 1;
+                                       if ((c=='v') || (c=='V'))
+                                               opt_do_list = 1;
+                                       if ((c=='x') || (c=='X'))
+                                               opt_do_extract = 1;
+                                       if ((c=='e') || (c=='E'))
+                                               opt_do_extract = opt_do_extract_withoutpath = 1;
+                                       if ((c=='o') || (c=='O'))
+                                               opt_overwrite=1;
+                               }
+                       }
+                       else
+            {
+                               if (zipfilename == NULL)
+                                       zipfilename = argv[i];
+                else if (filename_to_extract==NULL)
+                        filename_to_extract = argv[i] ;
+            }
+               }
+       }
+
+       if (zipfilename!=NULL)
+       {
+               strcpy(filename_try,zipfilename);
+               uf = unzOpen(zipfilename);
+               if (uf==NULL)
+               {
+                       strcat(filename_try,".zip");
+                       uf = unzOpen(filename_try);
+               }
+       }
+
+       if (uf==NULL)
+       {
+               printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
+               exit (1);
+       }
+    printf("%s opened\n",filename_try);
+
+       if (opt_do_list==1)
+               return do_list(uf);
+       else if (opt_do_extract==1)
+    {
+        if (filename_to_extract == NULL)
+                   return do_extract(uf,opt_do_extract_withoutpath,opt_overwrite);
+        else
+            return do_extract_onefile(uf,filename_to_extract,
+                                      opt_do_extract_withoutpath,opt_overwrite);
+    }
+       unzCloseCurrentFile(uf);
+
+       return 0;  /* to avoid warning */
+}
diff --git a/lib/zlib/contrib/minizip/minizip.c b/lib/zlib/contrib/minizip/minizip.c
new file mode 100644 (file)
index 0000000..5e492d2
--- /dev/null
@@ -0,0 +1,302 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "zip.h"
+
+
+#define WRITEBUFFERSIZE (16384)
+#define MAXFILENAME (256)
+
+#ifdef WIN32
+uLong filetime(f, tmzip, dt)
+    char *f;                /* name of file to get info on */
+    tm_zip *tmzip;             /* return value: access, modific. and creation times */
+    uLong *dt;             /* dostime */
+{
+  int ret = 0;
+  {
+      FILETIME ftLocal;
+      HANDLE hFind;
+      WIN32_FIND_DATA  ff32;
+
+      hFind = FindFirstFile(f,&ff32);
+      if (hFind != INVALID_HANDLE_VALUE)
+      {
+        FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
+        FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
+        FindClose(hFind);
+        ret = 1;
+      }
+  }
+  return ret;
+}
+#else
+#ifdef unix
+uLong filetime(f, tmzip, dt)
+    char *f;                /* name of file to get info on */
+    tm_zip *tmzip;             /* return value: access, modific. and creation times */
+    uLong *dt;             /* dostime */
+{
+  int ret=0;
+  struct stat s;        /* results of stat() */
+  struct tm* filedate;
+  time_t tm_t=0;
+  
+  if (strcmp(f,"-")!=0)
+  {
+    char name[MAXFILENAME];
+    int len = strlen(f);
+    strcpy(name, f);
+    if (name[len - 1] == '/')
+      name[len - 1] = '\0';
+    /* not all systems allow stat'ing a file with / appended */
+    if (stat(name,&s)==0)
+    {
+      tm_t = s.st_mtime;
+      ret = 1;
+    }
+  }
+  filedate = localtime(&tm_t);
+
+  tmzip->tm_sec  = filedate->tm_sec;
+  tmzip->tm_min  = filedate->tm_min;
+  tmzip->tm_hour = filedate->tm_hour;
+  tmzip->tm_mday = filedate->tm_mday;
+  tmzip->tm_mon  = filedate->tm_mon ;
+  tmzip->tm_year = filedate->tm_year;
+
+  return ret;
+}
+#else
+uLong filetime(f, tmzip, dt)
+    char *f;                /* name of file to get info on */
+    tm_zip *tmzip;             /* return value: access, modific. and creation times */
+    uLong *dt;             /* dostime */
+{
+    return 0;
+}
+#endif
+#endif
+
+
+
+
+int check_exist_file(filename)
+    const char* filename;
+{
+       FILE* ftestexist;
+    int ret = 1;
+       ftestexist = fopen(filename,"rb");
+       if (ftestexist==NULL)
+        ret = 0;
+    else
+        fclose(ftestexist);
+    return ret;
+}
+
+void do_banner()
+{
+       printf("MiniZip 0.15, demo of zLib + Zip package written by Gilles Vollant\n");
+       printf("more info at http://wwww.winimage/zLibDll/unzip.htm\n\n");
+}
+
+void do_help()
+{      
+       printf("Usage : minizip [-o] file.zip [files_to_add]\n\n") ;
+}
+
+int main(argc,argv)
+       int argc;
+       char *argv[];
+{
+       int i;
+       int opt_overwrite=0;
+    int opt_compress_level=Z_DEFAULT_COMPRESSION;
+    int zipfilenamearg = 0;
+       char filename_try[MAXFILENAME];
+    int zipok;
+    int err=0;
+    int size_buf=0;
+    void* buf=NULL,
+
+
+       do_banner();
+       if (argc==1)
+       {
+               do_help();
+               exit(0);
+        return 0;
+       }
+       else
+       {
+               for (i=1;i<argc;i++)
+               {
+                       if ((*argv[i])=='-')
+                       {
+                               const char *p=argv[i]+1;
+                               
+                               while ((*p)!='\0')
+                               {                       
+                                       char c=*(p++);;
+                                       if ((c=='o') || (c=='O'))
+                                               opt_overwrite = 1;
+                    if ((c>='0') && (c<='9'))
+                        opt_compress_level = c-'0';
+                               }
+                       }
+                       else
+                               if (zipfilenamearg == 0)
+                    zipfilenamearg = i ;
+               }
+       }
+
+    size_buf = WRITEBUFFERSIZE;
+    buf = (void*)malloc(size_buf);
+    if (buf==NULL)
+    {
+        printf("Error allocating memory\n");
+        return ZIP_INTERNALERROR;
+    }
+
+       if (zipfilenamearg==0)
+        zipok=0;
+    else
+       {
+        int i,len;
+        int dot_found=0;
+
+        zipok = 1 ;
+               strcpy(filename_try,argv[zipfilenamearg]);
+        len=strlen(filename_try);
+        for (i=0;i<len;i++)
+            if (filename_try[i]=='.')
+                dot_found=1;
+
+        if (dot_found==0)
+            strcat(filename_try,".zip");
+
+        if (opt_overwrite==0)
+            if (check_exist_file(filename_try)!=0)
+                       {
+                char rep;
+                               do
+                               {
+                                       char answer[128];
+                                       printf("The file %s exist. Overwrite ? [y]es, [n]o : ",filename_try);
+                                       scanf("%1s",answer);
+                                       rep = answer[0] ;
+                                       if ((rep>='a') && (rep<='z'))
+                                               rep -= 0x20;
+                               }
+                               while ((rep!='Y') && (rep!='N'));
+                if (rep=='N')
+                    zipok = 0;
+                       }
+    }
+
+    if (zipok==1)
+    {
+        zipFile zf;
+        int errclose;
+        zf = zipOpen(filename_try,0);
+        if (zf == NULL)
+        {
+            printf("error opening %s\n",filename_try);
+            err= ZIP_ERRNO;
+        }
+        else 
+            printf("creating %s\n",filename_try);
+
+        for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
+        {
+            if (((*(argv[i]))!='-') && ((*(argv[i]))!='/'))
+            {
+                FILE * fin;
+                int size_read;
+                const char* filenameinzip = argv[i];
+                zip_fileinfo zi;
+
+                zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 
+                zi.tmz_date.tm_mday = zi.tmz_date.tm_min = zi.tmz_date.tm_year = 0;
+                zi.dosDate = 0;
+                zi.internal_fa = 0;
+                zi.external_fa = 0;
+                filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
+
+
+                err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
+                                 NULL,0,NULL,0,NULL /* comment*/,
+                                 (opt_compress_level != 0) ? Z_DEFLATED : 0,
+                                 opt_compress_level);
+
+                if (err != ZIP_OK)
+                    printf("error in opening %s in zipfile\n",filenameinzip);
+                else
+                {
+                    fin = fopen(filenameinzip,"rb");
+                    if (fin==NULL)
+                    {
+                        err=ZIP_ERRNO;
+                        printf("error in opening %s for reading\n",filenameinzip);
+                    }
+                }
+
+                if (err == ZIP_OK)
+                    do
+                    {
+                        err = ZIP_OK;
+                        size_read = fread(buf,1,size_buf,fin);
+                        if (size_read < size_buf)
+                            if (feof(fin)==0)
+                        {
+                            printf("error in reading %s\n",filenameinzip);
+                            err = ZIP_ERRNO;
+                        }
+
+                        if (size_read>0)
+                        {
+                            err = zipWriteInFileInZip (zf,buf,size_read);
+                            if (err<0)
+                            {
+                                printf("error in writing %s in the zipfile\n",
+                                                 filenameinzip);
+                            }
+                                
+                        }
+                    } while ((err == ZIP_OK) && (size_read>0));
+
+                fclose(fin);
+                if (err<0)
+                    err=ZIP_ERRNO;
+                else
+                {                    
+                    err = zipCloseFileInZip(zf);
+                    if (err!=ZIP_OK)
+                        printf("error in closing %s in the zipfile\n",
+                                    filenameinzip);
+                }
+            }
+        }
+        errclose = zipClose(zf,NULL);
+        if (errclose != ZIP_OK)
+            printf("error in closing %s\n",filename_try);
+   }
+
+    free(buf);
+    exit(0);
+       return 0;  /* to avoid warning */
+}
diff --git a/lib/zlib/contrib/minizip/readme.txt b/lib/zlib/contrib/minizip/readme.txt
new file mode 100644 (file)
index 0000000..1fc023c
--- /dev/null
@@ -0,0 +1,37 @@
+
+UnZip 0.15 additionnal library
+
+
+  This unzip package allow extract file from .ZIP file, compatible with 
+PKZip 2.04g, WinZip, InfoZip tools and compatible.
+
+  Multi volume ZipFile (span) are not supported, and old compression used by old 
+PKZip 1.x are not supported.
+
+See probdesc.zip from PKWare for specification of .ZIP format.
+
+What is Unzip
+  The Zlib library support the deflate compression and the creation of gzip (.gz) 
+file. Zlib is free and small.
+  The .Zip format, which can contain several compressed files (.gz can containt
+only one file) is a very popular format. This is why I've written a package for reading file compressed in Zipfile.
+
+Using Unzip package
+
+You need source of Zlib (get zlib111.zip and read zlib.h).
+Get unzlb015.zip and read unzip.h (whith documentation of unzip functions)
+
+The Unzip package is only two file : unzip.h and unzip.c. But it use the Zlib 
+  files.
+unztst.c is a simple sample program, which list file in a zipfile and display
+  README.TXT or FILE_ID.DIZ (if these files are found).
+miniunz.c is a mini unzip program.
+
+I'm also currenlyt writing a zipping portion (zip.h, zip.c and test with minizip.c)
+
+Please email me for feedback.
+I hope my source is compatible with Unix system, but I need your help for be sure
+
+Latest revision : Mar 04th, 1998
+
+Check http://www.winimage.com/zLibDll/unzip.html for up to date info.
diff --git a/lib/zlib/contrib/minizip/unzip.c b/lib/zlib/contrib/minizip/unzip.c
new file mode 100644 (file)
index 0000000..ff71a47
--- /dev/null
@@ -0,0 +1,1294 @@
+/* unzip.c -- IO on .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Read unzip.h for more info
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+
+#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
+                      !defined(CASESENSITIVITYDEFAULT_NO)
+#define CASESENSITIVITYDEFAULT_NO
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR    1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END    2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET    0
+#endif
+
+const char unz_copyright[] =
+   " unzip 0.15 Copyright 1998 Gilles Vollant ";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info_internal_s
+{
+    uLong offset_curfile;/* relative offset of local header 4 bytes */
+} unz_file_info_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+    when reading and decompress it */
+typedef struct
+{
+       char  *read_buffer;         /* internal buffer for compressed data */
+       z_stream stream;            /* zLib stream structure for inflate */
+
+       uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
+       uLong stream_initialised;   /* flag set if stream structure is initialised*/
+
+       uLong offset_local_extrafield;/* offset of the local extra field */
+       uInt  size_local_extrafield;/* size of the local extra field */
+       uLong pos_local_extrafield;   /* position in the local extra field in read*/
+
+       uLong crc32;                /* crc32 of all data uncompressed */
+       uLong crc32_wait;           /* crc32 we must obtain after decompress all */
+       uLong rest_read_compressed; /* number of byte to be decompressed */
+       uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+       FILE* file;                 /* io structore of the zipfile */
+       uLong compression_method;   /* compression method (0==store) */
+       uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+} file_in_zip_read_info_s;
+
+
+/* unz_s contain internal information about the zipfile
+*/
+typedef struct
+{
+       FILE* file;                 /* io structore of the zipfile */
+       unz_global_info gi;       /* public global information */
+       uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+       uLong num_file;             /* number of the current file in the zipfile*/
+       uLong pos_in_central_dir;   /* pos of the current file in the central dir*/
+       uLong current_file_ok;      /* flag about the usability of the current file*/
+       uLong central_pos;          /* position of the beginning of the central dir*/
+
+       uLong size_central_dir;     /* size of the central directory  */
+       uLong offset_central_dir;   /* offset of start of central directory with
+                                                                  respect to the starting disk number */
+
+       unz_file_info cur_file_info; /* public info about the current file in zip*/
+       unz_file_info_internal cur_file_info_internal; /* private info about it*/
+    file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
+                                           file if we are decompressing it */
+} unz_s;
+
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unzlocal_getByte(fin,pi)
+       FILE *fin;
+       int *pi;
+{
+    unsigned char c;
+       int err = fread(&c, 1, 1, fin);
+    if (err==1)
+    {
+        *pi = (int)c;
+        return UNZ_OK;
+    }
+    else
+    {
+        if (ferror(fin)) 
+            return UNZ_ERRNO;
+        else
+            return UNZ_EOF;
+    }
+}
+
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets 
+*/
+local int unzlocal_getShort (fin,pX)
+       FILE* fin;
+    uLong *pX;
+{
+    uLong x ;
+    int i;
+    int err;
+
+    err = unzlocal_getByte(fin,&i);
+    x = (uLong)i;
+    
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<8;
+   
+    if (err==UNZ_OK)
+        *pX = x;
+    else
+        *pX = 0;
+    return err;
+}
+
+local int unzlocal_getLong (fin,pX)
+       FILE* fin;
+    uLong *pX;
+{
+    uLong x ;
+    int i;
+    int err;
+
+    err = unzlocal_getByte(fin,&i);
+    x = (uLong)i;
+    
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<8;
+
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<16;
+
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<24;
+   
+    if (err==UNZ_OK)
+        *pX = x;
+    else
+        *pX = 0;
+    return err;
+}
+
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (fileName1,fileName2)
+       const char* fileName1;
+       const char* fileName2;
+{
+       for (;;)
+       {
+               char c1=*(fileName1++);
+               char c2=*(fileName2++);
+               if ((c1>='a') && (c1<='z'))
+                       c1 -= 0x20;
+               if ((c2>='a') && (c2<='z'))
+                       c2 -= 0x20;
+               if (c1=='\0')
+                       return ((c2=='\0') ? 0 : -1);
+               if (c2=='\0')
+                       return 1;
+               if (c1<c2)
+                       return -1;
+               if (c1>c2)
+                       return 1;
+       }
+}
+
+
+#ifdef  CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/* 
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                                                or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+        (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
+       const char* fileName1;
+       const char* fileName2;
+       int iCaseSensitivity;
+{
+       if (iCaseSensitivity==0)
+               iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+       if (iCaseSensitivity==1)
+               return strcmp(fileName1,fileName2);
+
+       return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+} 
+
+#define BUFREADCOMMENT (0x400)
+
+/*
+  Locate the Central directory of a zipfile (at the end, just before
+    the global comment)
+*/
+local uLong unzlocal_SearchCentralDir(fin)
+       FILE *fin;
+{
+       unsigned char* buf;
+       uLong uSizeFile;
+       uLong uBackRead;
+       uLong uMaxBack=0xffff; /* maximum size of global comment */
+       uLong uPosFound=0;
+       
+       if (fseek(fin,0,SEEK_END) != 0)
+               return 0;
+
+
+       uSizeFile = ftell( fin );
+       
+       if (uMaxBack>uSizeFile)
+               uMaxBack = uSizeFile;
+
+       buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+       if (buf==NULL)
+               return 0;
+
+       uBackRead = 4;
+       while (uBackRead<uMaxBack)
+       {
+               uLong uReadSize,uReadPos ;
+               int i;
+               if (uBackRead+BUFREADCOMMENT>uMaxBack) 
+                       uBackRead = uMaxBack;
+               else
+                       uBackRead+=BUFREADCOMMENT;
+               uReadPos = uSizeFile-uBackRead ;
+               
+               uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? 
+                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+               if (fseek(fin,uReadPos,SEEK_SET)!=0)
+                       break;
+
+               if (fread(buf,(uInt)uReadSize,1,fin)!=1)
+                       break;
+
+                for (i=(int)uReadSize-3; (i--)>0;)
+                       if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && 
+                               ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+                       {
+                               uPosFound = uReadPos+i;
+                               break;
+                       }
+
+               if (uPosFound!=0)
+                       break;
+       }
+       TRYFREE(buf);
+       return uPosFound;
+}
+
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
+        "zlib/zlib109.zip".
+        If the zipfile cannot be opened (file don't exist or in not valid), the
+          return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+          of this unzip package.
+*/
+extern unzFile ZEXPORT unzOpen (path)
+       const char *path;
+{
+       unz_s us;
+       unz_s *s;
+       uLong central_pos,uL;
+       FILE * fin ;
+
+       uLong number_disk;          /* number of the current dist, used for 
+                                                                  spaning ZIP, unsupported, always 0*/
+       uLong number_disk_with_CD;  /* number the the disk with central dir, used
+                                                                  for spaning ZIP, unsupported, always 0*/
+       uLong number_entry_CD;      /* total number of entries in
+                                      the central dir 
+                                      (same than number_entry on nospan) */
+
+       int err=UNZ_OK;
+
+    if (unz_copyright[0]!=' ')
+        return NULL;
+
+    fin=fopen(path,"rb");
+       if (fin==NULL)
+               return NULL;
+
+       central_pos = unzlocal_SearchCentralDir(fin);
+       if (central_pos==0)
+               err=UNZ_ERRNO;
+
+       if (fseek(fin,central_pos,SEEK_SET)!=0)
+               err=UNZ_ERRNO;
+
+       /* the signature, already checked */
+       if (unzlocal_getLong(fin,&uL)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* number of this disk */
+       if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* number of the disk with the start of the central directory */
+       if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* total number of entries in the central dir on this disk */
+       if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* total number of entries in the central dir */
+       if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if ((number_entry_CD!=us.gi.number_entry) ||
+               (number_disk_with_CD!=0) ||
+               (number_disk!=0))
+               err=UNZ_BADZIPFILE;
+
+       /* size of the central directory */
+       if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* offset of start of central directory with respect to the 
+             starting disk number */
+       if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* zipfile comment length */
+       if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if ((central_pos<us.offset_central_dir+us.size_central_dir) && 
+               (err==UNZ_OK))
+               err=UNZ_BADZIPFILE;
+
+       if (err!=UNZ_OK)
+       {
+               fclose(fin);
+               return NULL;
+       }
+
+       us.file=fin;
+       us.byte_before_the_zipfile = central_pos -
+                                   (us.offset_central_dir+us.size_central_dir);
+       us.central_pos = central_pos;
+    us.pfile_in_zip_read = NULL;
+       
+
+       s=(unz_s*)ALLOC(sizeof(unz_s));
+       *s=us;
+       unzGoToFirstFile((unzFile)s);   
+       return (unzFile)s;      
+}
+
+
+/*
+  Close a ZipFile opened with unzipOpen.
+  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (file)
+       unzFile file;
+{
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+
+    if (s->pfile_in_zip_read!=NULL)
+        unzCloseCurrentFile(file);
+
+       fclose(s->file);
+       TRYFREE(s);
+       return UNZ_OK;
+}
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
+       unzFile file;
+       unz_global_info *pglobal_info;
+{
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       *pglobal_info=s->gi;
+       return UNZ_OK;
+}
+
+
+/*
+   Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
+    uLong ulDosDate;
+    tm_unz* ptm;
+{
+    uLong uDate;
+    uDate = (uLong)(ulDosDate>>16);
+    ptm->tm_mday = (uInt)(uDate&0x1f) ;
+    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;
+    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+  Get Info about the current file in the zipfile, with internal only info
+*/
+local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
+                                                  unz_file_info *pfile_info,
+                                                  unz_file_info_internal 
+                                                  *pfile_info_internal,
+                                                  char *szFileName,
+                                                                                                 uLong fileNameBufferSize,
+                                                  void *extraField,
+                                                                                                 uLong extraFieldBufferSize,
+                                                  char *szComment,
+                                                                                                 uLong commentBufferSize));
+
+local int unzlocal_GetCurrentFileInfoInternal (file,
+                                              pfile_info,
+                                              pfile_info_internal,
+                                              szFileName, fileNameBufferSize,
+                                              extraField, extraFieldBufferSize,
+                                              szComment,  commentBufferSize)
+       unzFile file;
+       unz_file_info *pfile_info;
+       unz_file_info_internal *pfile_info_internal;
+       char *szFileName;
+       uLong fileNameBufferSize;
+       void *extraField;
+       uLong extraFieldBufferSize;
+       char *szComment;
+       uLong commentBufferSize;
+{
+       unz_s* s;
+       unz_file_info file_info;
+       unz_file_info_internal file_info_internal;
+       int err=UNZ_OK;
+       uLong uMagic;
+       long lSeek=0;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
+               err=UNZ_ERRNO;
+
+
+       /* we check the magic */
+       if (err==UNZ_OK)
+               if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+                       err=UNZ_ERRNO;
+               else if (uMagic!=0x02014b50)
+                       err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+       if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       lSeek+=file_info.size_filename;
+       if ((err==UNZ_OK) && (szFileName!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_filename<fileNameBufferSize)
+               {
+                       *(szFileName+file_info.size_filename)='\0';
+                       uSizeRead = file_info.size_filename;
+               }
+               else
+                       uSizeRead = fileNameBufferSize;
+
+               if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+                       if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek -= uSizeRead;
+       }
+
+       
+       if ((err==UNZ_OK) && (extraField!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_file_extra<extraFieldBufferSize)
+                       uSizeRead = file_info.size_file_extra;
+               else
+                       uSizeRead = extraFieldBufferSize;
+
+               if (lSeek!=0)
+                       if (fseek(s->file,lSeek,SEEK_CUR)==0)
+                               lSeek=0;
+                       else
+                               err=UNZ_ERRNO;
+               if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+                       if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek += file_info.size_file_extra - uSizeRead;
+       }
+       else
+               lSeek+=file_info.size_file_extra; 
+
+       
+       if ((err==UNZ_OK) && (szComment!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_file_comment<commentBufferSize)
+               {
+                       *(szComment+file_info.size_file_comment)='\0';
+                       uSizeRead = file_info.size_file_comment;
+               }
+               else
+                       uSizeRead = commentBufferSize;
+
+               if (lSeek!=0)
+                       if (fseek(s->file,lSeek,SEEK_CUR)==0)
+                               lSeek=0;
+                       else
+                               err=UNZ_ERRNO;
+               if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+                       if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek+=file_info.size_file_comment - uSizeRead;
+       }
+       else
+               lSeek+=file_info.size_file_comment;
+
+       if ((err==UNZ_OK) && (pfile_info!=NULL))
+               *pfile_info=file_info;
+
+       if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+               *pfile_info_internal=file_info_internal;
+
+       return err;
+}
+
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo (file,
+                                                  pfile_info,
+                                                  szFileName, fileNameBufferSize,
+                                                  extraField, extraFieldBufferSize,
+                                                  szComment,  commentBufferSize)
+       unzFile file;
+       unz_file_info *pfile_info;
+       char *szFileName;
+       uLong fileNameBufferSize;
+       void *extraField;
+       uLong extraFieldBufferSize;
+       char *szComment;
+       uLong commentBufferSize;
+{
+       return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+                                                                                               szFileName,fileNameBufferSize,
+                                                                                               extraField,extraFieldBufferSize,
+                                                                                               szComment,commentBufferSize);
+}
+
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       s->pos_in_central_dir=s->offset_central_dir;
+       s->num_file=0;
+       err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                                                                        &s->cur_file_info_internal,
+                                                                                        NULL,0,NULL,0,NULL,0);
+       s->current_file_ok = (err == UNZ_OK);
+       return err;
+}
+
+
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (file)
+       unzFile file;
+{
+       unz_s* s;       
+       int err;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_END_OF_LIST_OF_FILE;
+       if (s->num_file+1==s->gi.number_entry)
+               return UNZ_END_OF_LIST_OF_FILE;
+
+       s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+                       s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+       s->num_file++;
+       err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                                                                          &s->cur_file_info_internal,
+                                                                                          NULL,0,NULL,0,NULL,0);
+       s->current_file_ok = (err == UNZ_OK);
+       return err;
+}
+
+
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
+       unzFile file;
+       const char *szFileName;
+       int iCaseSensitivity;
+{
+       unz_s* s;       
+       int err;
+
+       
+       uLong num_fileSaved;
+       uLong pos_in_central_dirSaved;
+
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+
+    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+        return UNZ_PARAMERROR;
+
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_END_OF_LIST_OF_FILE;
+
+       num_fileSaved = s->num_file;
+       pos_in_central_dirSaved = s->pos_in_central_dir;
+
+       err = unzGoToFirstFile(file);
+
+       while (err == UNZ_OK)
+       {
+               char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+               unzGetCurrentFileInfo(file,NULL,
+                                                               szCurrentFileName,sizeof(szCurrentFileName)-1,
+                                                               NULL,0,NULL,0);
+               if (unzStringFileNameCompare(szCurrentFileName,
+                                                                               szFileName,iCaseSensitivity)==0)
+                       return UNZ_OK;
+               err = unzGoToNextFile(file);
+       }
+
+       s->num_file = num_fileSaved ;
+       s->pos_in_central_dir = pos_in_central_dirSaved ;
+       return err;
+}
+
+
+/*
+  Read the local header of the current zipfile
+  Check the coherency of the local header and info in the end of central
+        directory about this file
+  store in *piSizeVar the size of extra info in local header
+        (filename and size of extra field data)
+*/
+local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
+                                                                                                       poffset_local_extrafield,
+                                                                                                       psize_local_extrafield)
+       unz_s* s;
+       uInt* piSizeVar;
+       uLong *poffset_local_extrafield;
+       uInt  *psize_local_extrafield;
+{
+       uLong uMagic,uData,uFlags;
+       uLong size_filename;
+       uLong size_extra_field;
+       int err=UNZ_OK;
+
+       *piSizeVar = 0;
+       *poffset_local_extrafield = 0;
+       *psize_local_extrafield = 0;
+
+       if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
+                                                               s->byte_before_the_zipfile,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+
+       if (err==UNZ_OK)
+               if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+                       err=UNZ_ERRNO;
+               else if (uMagic!=0x04034b50)
+                       err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+               err=UNZ_ERRNO;
+/*
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+               err=UNZ_BADZIPFILE;
+*/
+       if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+               err=UNZ_BADZIPFILE;
+
+    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+                         (s->cur_file_info.compression_method!=Z_DEFLATED))
+        err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
+                                     ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
+                                                         ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 
+                                                         ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+
+       if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+               err=UNZ_BADZIPFILE;
+
+       *piSizeVar += (uInt)size_filename;
+
+       if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
+               err=UNZ_ERRNO;
+       *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+                                                                       SIZEZIPLOCALHEADER + size_filename;
+       *psize_local_extrafield = (uInt)size_extra_field;
+
+       *piSizeVar += (uInt)size_extra_field;
+
+       return err;
+}
+                                                                                               
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+       int Store;
+       uInt iSizeVar;
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       uLong offset_local_extrafield;  /* offset of the local extra field */
+       uInt  size_local_extrafield;    /* size of the local extra field */
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_PARAMERROR;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+       if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
+                               &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+               return UNZ_BADZIPFILE;
+
+       pfile_in_zip_read_info = (file_in_zip_read_info_s*)
+                                                                           ALLOC(sizeof(file_in_zip_read_info_s));
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_INTERNALERROR;
+
+       pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+       pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+       pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+       pfile_in_zip_read_info->pos_local_extrafield=0;
+
+       if (pfile_in_zip_read_info->read_buffer==NULL)
+       {
+               TRYFREE(pfile_in_zip_read_info);
+               return UNZ_INTERNALERROR;
+       }
+
+       pfile_in_zip_read_info->stream_initialised=0;
+       
+       if ((s->cur_file_info.compression_method!=0) &&
+        (s->cur_file_info.compression_method!=Z_DEFLATED))
+               err=UNZ_BADZIPFILE;
+       Store = s->cur_file_info.compression_method==0;
+
+       pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+       pfile_in_zip_read_info->crc32=0;
+       pfile_in_zip_read_info->compression_method =
+            s->cur_file_info.compression_method;
+       pfile_in_zip_read_info->file=s->file;
+       pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+    pfile_in_zip_read_info->stream.total_out = 0;
+
+       if (!Store)
+       {
+         pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+         pfile_in_zip_read_info->stream.zfree = (free_func)0;
+         pfile_in_zip_read_info->stream.opaque = (voidpf)0; 
+      
+         err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+         if (err == Z_OK)
+           pfile_in_zip_read_info->stream_initialised=1;
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. 
+         * In unzip, i don't wait absolutely Z_STREAM_END because I known the 
+         * size of both compressed and uncompressed data
+         */
+       }
+       pfile_in_zip_read_info->rest_read_compressed = 
+            s->cur_file_info.compressed_size ;
+       pfile_in_zip_read_info->rest_read_uncompressed = 
+            s->cur_file_info.uncompressed_size ;
+
+       
+       pfile_in_zip_read_info->pos_in_zipfile = 
+            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 
+                         iSizeVar;
+       
+       pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+
+       s->pfile_in_zip_read = pfile_in_zip_read_info;
+    return UNZ_OK;
+}
+
+
+/*
+  Read bytes from the current file.
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile  (file, buf, len)
+       unzFile file;
+       voidp buf;
+       unsigned len;
+{
+       int err=UNZ_OK;
+       uInt iRead = 0;
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+
+       if ((pfile_in_zip_read_info->read_buffer == NULL))
+               return UNZ_END_OF_LIST_OF_FILE;
+       if (len==0)
+               return 0;
+
+       pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+       pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+       
+       if (len>pfile_in_zip_read_info->rest_read_uncompressed)
+               pfile_in_zip_read_info->stream.avail_out = 
+                 (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+       while (pfile_in_zip_read_info->stream.avail_out>0)
+       {
+               if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+            (pfile_in_zip_read_info->rest_read_compressed>0))
+               {
+                       uInt uReadThis = UNZ_BUFSIZE;
+                       if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+                               uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+                       if (uReadThis == 0)
+                               return UNZ_EOF;
+                       if (fseek(pfile_in_zip_read_info->file,
+                      pfile_in_zip_read_info->pos_in_zipfile + 
+                         pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
+                               return UNZ_ERRNO;
+                       if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
+                         pfile_in_zip_read_info->file)!=1)
+                               return UNZ_ERRNO;
+                       pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+                       pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+                       
+                       pfile_in_zip_read_info->stream.next_in = 
+                (Bytef*)pfile_in_zip_read_info->read_buffer;
+                       pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+               }
+
+               if (pfile_in_zip_read_info->compression_method==0)
+               {
+                       uInt uDoCopy,i ;
+                       if (pfile_in_zip_read_info->stream.avail_out < 
+                            pfile_in_zip_read_info->stream.avail_in)
+                               uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+                       else
+                               uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+                               
+                       for (i=0;i<uDoCopy;i++)
+                               *(pfile_in_zip_read_info->stream.next_out+i) =
+                        *(pfile_in_zip_read_info->stream.next_in+i);
+                                       
+                       pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+                                                               pfile_in_zip_read_info->stream.next_out,
+                                                               uDoCopy);
+                       pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+                       pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+                       pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+                       pfile_in_zip_read_info->stream.next_out += uDoCopy;
+                       pfile_in_zip_read_info->stream.next_in += uDoCopy;
+            pfile_in_zip_read_info->stream.total_out += uDoCopy;
+                       iRead += uDoCopy;
+               }
+               else
+               {
+                       uLong uTotalOutBefore,uTotalOutAfter;
+                       const Bytef *bufBefore;
+                       uLong uOutThis;
+                       int flush=Z_SYNC_FLUSH;
+
+                       uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+                       bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+                       /*
+                       if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+                                pfile_in_zip_read_info->stream.avail_out) &&
+                               (pfile_in_zip_read_info->rest_read_compressed == 0))
+                               flush = Z_FINISH;
+                       */
+                       err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+                       uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+                       uOutThis = uTotalOutAfter-uTotalOutBefore;
+                       
+                       pfile_in_zip_read_info->crc32 = 
+                crc32(pfile_in_zip_read_info->crc32,bufBefore,
+                        (uInt)(uOutThis));
+
+                       pfile_in_zip_read_info->rest_read_uncompressed -=
+                uOutThis;
+
+                       iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+            
+                       if (err==Z_STREAM_END)
+                               return (iRead==0) ? UNZ_EOF : iRead;
+                       if (err!=Z_OK) 
+                               break;
+               }
+       }
+
+       if (err==Z_OK)
+               return iRead;
+       return err;
+}
+
+
+/*
+  Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (file)
+       unzFile file;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+       return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+
+/*
+  return 1 if the end of file was reached, 0 elsewhere 
+*/
+extern int ZEXPORT unzeof (file)
+       unzFile file;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+       
+       if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+               return 1;
+       else
+               return 0;
+}
+
+
+
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field that can be read
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+       buf.
+  the return value is the number of bytes copied in buf, or (if <0) 
+       the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
+       unzFile file;
+       voidp buf;
+       unsigned len;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       uInt read_now;
+       uLong size_to_read;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+       size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 
+                               pfile_in_zip_read_info->pos_local_extrafield);
+
+       if (buf==NULL)
+               return (int)size_to_read;
+       
+       if (len>size_to_read)
+               read_now = (uInt)size_to_read;
+       else
+               read_now = (uInt)len ;
+
+       if (read_now==0)
+               return 0;
+       
+       if (fseek(pfile_in_zip_read_info->file,
+              pfile_in_zip_read_info->offset_local_extrafield + 
+                         pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+       if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
+               return UNZ_ERRNO;
+
+       return (int)read_now;
+}
+
+/*
+  Close the file in zip opened with unzipOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+
+       if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+       {
+               if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+                       err=UNZ_CRCERROR;
+       }
+
+
+       TRYFREE(pfile_in_zip_read_info->read_buffer);
+       pfile_in_zip_read_info->read_buffer = NULL;
+       if (pfile_in_zip_read_info->stream_initialised)
+               inflateEnd(&pfile_in_zip_read_info->stream);
+
+       pfile_in_zip_read_info->stream_initialised = 0;
+       TRYFREE(pfile_in_zip_read_info);
+
+    s->pfile_in_zip_read=NULL;
+
+       return err;
+}
+
+
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
+       unzFile file;
+       char *szComment;
+       uLong uSizeBuf;
+{
+       int err=UNZ_OK;
+       unz_s* s;
+       uLong uReadThis ;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+
+       uReadThis = uSizeBuf;
+       if (uReadThis>s->gi.size_comment)
+               uReadThis = s->gi.size_comment;
+
+       if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+       if (uReadThis>0)
+    {
+      *szComment='\0';
+         if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
+               return UNZ_ERRNO;
+    }
+
+       if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+               *(szComment+s->gi.size_comment)='\0';
+       return (int)uReadThis;
+}
diff --git a/lib/zlib/contrib/minizip/unzip.def b/lib/zlib/contrib/minizip/unzip.def
new file mode 100644 (file)
index 0000000..f6ede89
--- /dev/null
@@ -0,0 +1,15 @@
+       unzOpen                       @61
+       unzClose                      @62
+       unzGetGlobalInfo              @63
+       unzGetCurrentFileInfo         @64
+       unzGoToFirstFile              @65
+       unzGoToNextFile               @66
+       unzOpenCurrentFile            @67
+       unzReadCurrentFile            @68
+       unztell                       @70
+       unzeof                        @71
+       unzCloseCurrentFile           @72
+       unzGetGlobalComment           @73
+       unzStringFileNameCompare      @74
+       unzLocateFile                 @75
+       unzGetLocalExtrafield         @76
diff --git a/lib/zlib/contrib/minizip/unzip.h b/lib/zlib/contrib/minizip/unzip.h
new file mode 100644 (file)
index 0000000..76692cb
--- /dev/null
@@ -0,0 +1,275 @@
+/* unzip.h -- IO for uncompress .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Copyright (C) 1998 Gilles Vollant
+
+   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
+     WinZip, InfoZip tools and compatible.
+   Encryption and multi volume ZipFile (span) are not supported.
+   Old compressions used by old PKZip 1.x are not supported
+
+   THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+   CAN CHANGE IN FUTURE VERSION !!
+   I WAIT FEEDBACK at mail info@winimage.com
+   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
+
+   Condition of use and distribution are the same than zlib :
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+/* for more info about .ZIP format, see 
+      ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+   PkWare has also a specification at :
+      ftp://ftp.pkware.com/probdesc.zip */
+
+#ifndef _unz_H
+#define _unz_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__; 
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK                                  (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO               (Z_ERRNO)
+#define UNZ_EOF                 (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s 
+{
+       uInt tm_sec;            /* seconds after the minute - [0,59] */
+       uInt tm_min;            /* minutes after the hour - [0,59] */
+       uInt tm_hour;           /* hours since midnight - [0,23] */
+       uInt tm_mday;           /* day of the month - [1,31] */
+       uInt tm_mon;            /* months since January - [0,11] */
+       uInt tm_year;           /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+   These data comes from the end of central dir */
+typedef struct unz_global_info_s
+{
+       uLong number_entry;         /* total number of entries in
+                                      the central dir on this disk */
+       uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info;
+
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    uLong compressed_size;      /* compressed size                 4 bytes */ 
+    uLong uncompressed_size;    /* uncompressed size               4 bytes */ 
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+                                                                                                const char* fileName2,
+                                                                                                int iCaseSensitivity));
+/*
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                                               or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+       (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+        "zlib/zlib111.zip".
+        If the zipfile cannot be opened (file don't exist or in not valid), the
+          return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+          of this unzip package.
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+  Close a ZipFile opened with unzipOpen.
+  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+  return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+                                       unz_global_info *pglobal_info));
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+                                                                                  char *szComment,
+                                          uLong uSizeBuf));
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file, 
+                                    const char *szFileName,
+                                    int iCaseSensitivity));
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+                                            unz_file_info *pfile_info,
+                                            char *szFileName,
+                                            uLong fileNameBufferSize,
+                                            void *extraField,
+                                            uLong extraFieldBufferSize,
+                                            char *szComment,
+                                            uLong commentBufferSize));
+/*
+  Get Info about the current file
+  if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+           the current file
+  if szFileName!=NULL, the filemane string will be copied in szFileName
+                       (fileNameBufferSize is the size of the buffer)
+  if extraField!=NULL, the extra field information will be copied in extraField
+                       (extraFieldBufferSize is the size of the buffer).
+                       This is the Central-header version of the extra field
+  if szComment!=NULL, the comment string of the file will be copied in szComment
+                       (commentBufferSize is the size of the buffer)
+*/
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+   from it, and close it (you can close it before reading all the file)
+   */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+  Close the file in zip opened with unzOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+                                                                                               
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file, 
+                                         voidp buf,
+                                         unsigned len));
+/*
+  Read bytes from the current file (opened by unzOpenCurrentFile)
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+/*
+  Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+  return 1 if the end of file was reached, 0 elsewhere 
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+                                                                                        voidp buf,
+                                                                                        unsigned len));
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+       buf.
+  the return value is the number of bytes copied in buf, or (if <0) 
+       the error code
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz_H */
diff --git a/lib/zlib/contrib/minizip/zip.c b/lib/zlib/contrib/minizip/zip.c
new file mode 100644 (file)
index 0000000..0cae64a
--- /dev/null
@@ -0,0 +1,718 @@
+/* zip.c -- IO on .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Read zip.h for more info
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "zip.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#ifndef VERSIONMADEBY
+# define VERSIONMADEBY   (0x0) /* platform depedent */
+#endif
+
+#ifndef Z_BUFSIZE
+#define Z_BUFSIZE (16384)
+#endif
+
+#ifndef Z_MAXFILENAMEINZIP
+#define Z_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/*
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+*/
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR    1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END    2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET    0
+#endif
+
+const char zip_copyright[] =
+   " zip 0.15 Copyright 1998 Gilles Vollant ";
+
+
+#define SIZEDATA_INDATABLOCK (4096-(4*4))
+
+#define LOCALHEADERMAGIC    (0x04034b50)
+#define CENTRALHEADERMAGIC  (0x02014b50)
+#define ENDHEADERMAGIC      (0x06054b50)
+
+#define FLAG_LOCALHEADER_OFFSET (0x06)
+#define CRC_LOCALHEADER_OFFSET  (0x0e)
+
+#define SIZECENTRALHEADER (0x2e) /* 46 */
+
+typedef struct linkedlist_datablock_internal_s
+{
+  struct linkedlist_datablock_internal_s* next_datablock;
+  uLong  avail_in_this_block;
+  uLong  filled_in_this_block;
+  uLong  unused; /* for future use and alignement */
+  unsigned char data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+    linkedlist_datablock_internal* first_block;
+    linkedlist_datablock_internal* last_block;
+} linkedlist_data;
+
+
+typedef struct
+{
+       z_stream stream;            /* zLib stream structure for inflate */
+    int  stream_initialised;    /* 1 is stream is initialised */
+    uInt pos_in_buffered_data;  /* last written byte in buffered_data */
+
+    uLong pos_local_header;     /* offset of the local header of the file 
+                                     currenty writing */
+    char* central_header;       /* central header data for the current file */
+    uLong size_centralheader;   /* size of the central header for cur file */
+    uLong flag;                 /* flag of the file currently writing */
+
+    int  method;                /* compression method of file currenty wr.*/
+    Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
+    uLong dosDate;
+    uLong crc32;
+} curfile_info;
+
+typedef struct
+{
+    FILE * filezip;
+    linkedlist_data central_dir;/* datablock with central dir in construction*/
+    int  in_opened_file_inzip;  /* 1 if a file in the zip is currently writ.*/
+    curfile_info ci;            /* info on the file curretly writing */
+
+    uLong begin_pos;            /* position of the beginning of the zipfile */
+    uLong number_entry;
+} zip_internal;
+
+local linkedlist_datablock_internal* allocate_new_datablock()
+{
+    linkedlist_datablock_internal* ldi;
+    ldi = (linkedlist_datablock_internal*)
+                 ALLOC(sizeof(linkedlist_datablock_internal));
+    if (ldi!=NULL)
+    {
+        ldi->next_datablock = NULL ;
+        ldi->filled_in_this_block = 0 ;
+        ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
+    }
+    return ldi;
+}
+
+local void free_datablock(ldi)
+    linkedlist_datablock_internal* ldi;
+{
+    while (ldi!=NULL)
+    {
+        linkedlist_datablock_internal* ldinext = ldi->next_datablock;
+        TRYFREE(ldi);
+        ldi = ldinext;
+    }
+}
+
+local void init_linkedlist(ll)
+    linkedlist_data* ll;
+{
+    ll->first_block = ll->last_block = NULL;
+}
+
+local void free_linkedlist(ll)
+    linkedlist_data* ll;
+{
+    free_datablock(ll->first_block);
+    ll->first_block = ll->last_block = NULL;
+}
+
+
+local int add_data_in_datablock(ll,buf,len)
+    linkedlist_data* ll;    
+    const void* buf;
+    uLong len;
+{
+    linkedlist_datablock_internal* ldi;
+    const unsigned char* from_copy;
+
+    if (ll==NULL)
+        return ZIP_INTERNALERROR;
+
+    if (ll->last_block == NULL)
+    {
+        ll->first_block = ll->last_block = allocate_new_datablock();
+        if (ll->first_block == NULL)
+            return ZIP_INTERNALERROR;
+    }
+
+    ldi = ll->last_block;
+    from_copy = (unsigned char*)buf;
+
+    while (len>0)
+    {
+        uInt copy_this;
+        uInt i;
+        unsigned char* to_copy;
+
+        if (ldi->avail_in_this_block==0)
+        {
+            ldi->next_datablock = allocate_new_datablock();
+            if (ldi->next_datablock == NULL)
+                return ZIP_INTERNALERROR;
+            ldi = ldi->next_datablock ;
+            ll->last_block = ldi;
+        }
+
+        if (ldi->avail_in_this_block < len)
+            copy_this = (uInt)ldi->avail_in_this_block;
+        else
+            copy_this = (uInt)len;
+
+        to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+        for (i=0;i<copy_this;i++)
+            *(to_copy+i)=*(from_copy+i);
+
+        ldi->filled_in_this_block += copy_this;
+        ldi->avail_in_this_block -= copy_this;
+        from_copy += copy_this ;
+        len -= copy_this;
+    }
+    return ZIP_OK;
+}
+
+
+local int write_datablock(fout,ll)
+    FILE * fout;
+    linkedlist_data* ll;    
+{
+    linkedlist_datablock_internal* ldi;
+    ldi = ll->first_block;
+    while (ldi!=NULL)
+    {
+        if (ldi->filled_in_this_block > 0)
+            if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,1,fout)!=1)
+                return ZIP_ERRNO;
+        ldi = ldi->next_datablock;
+    }
+    return ZIP_OK;
+}
+
+/****************************************************************************/
+
+/* ===========================================================================
+   Outputs a long in LSB order to the given file
+   nbByte == 1, 2 or 4 (byte, short or long)
+*/
+
+local int ziplocal_putValue OF((FILE *file, uLong x, int nbByte));
+local int ziplocal_putValue (file, x, nbByte)
+    FILE *file;
+    uLong x;
+    int nbByte;
+{
+    unsigned char buf[4];
+    int n;
+    for (n = 0; n < nbByte; n++) {
+        buf[n] = (unsigned char)(x & 0xff);
+        x >>= 8;
+    }
+    if (fwrite(buf,nbByte,1,file)!=1)
+        return ZIP_ERRNO;
+    else
+        return ZIP_OK;
+}
+
+local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
+local void ziplocal_putValue_inmemory (dest, x, nbByte)
+    void* dest;
+    uLong x;
+    int nbByte;
+{
+    unsigned char* buf=(unsigned char*)dest;
+    int n;
+    for (n = 0; n < nbByte; n++) {
+        buf[n] = (unsigned char)(x & 0xff);
+        x >>= 8;
+    }
+}
+/****************************************************************************/
+
+
+local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
+    tm_zip* ptm;
+    uLong dosDate;
+{
+    uLong year = (uLong)ptm->tm_year;
+    if (year>1980)
+        year-=1980;
+    else if (year>80)
+        year-=80;
+    return
+      (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
+        ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
+}
+
+
+/****************************************************************************/
+
+extern zipFile ZEXPORT zipOpen (pathname, append)
+    const char *pathname;
+    int append;
+{
+    zip_internal ziinit;
+    zip_internal* zi;
+
+    ziinit.filezip = fopen(pathname,(append == 0) ? "wb" : "ab");
+    if (ziinit.filezip == NULL)
+        return NULL;
+    ziinit.begin_pos = ftell(ziinit.filezip);
+    ziinit.in_opened_file_inzip = 0;
+    ziinit.ci.stream_initialised = 0;
+    ziinit.number_entry = 0;
+    init_linkedlist(&(ziinit.central_dir));
+
+
+    zi = (zip_internal*)ALLOC(sizeof(zip_internal));
+    if (zi==NULL)
+    {
+        fclose(ziinit.filezip);
+        return NULL;
+    }
+
+    *zi = ziinit;
+    return (zipFile)zi;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, 
+                                        extrafield_local, size_extrafield_local,
+                                        extrafield_global, size_extrafield_global,
+                                        comment, method, level)
+    zipFile file;
+    const char* filename;
+    const zip_fileinfo* zipfi;
+    const void* extrafield_local;
+    uInt size_extrafield_local;
+    const void* extrafield_global;
+    uInt size_extrafield_global;
+    const char* comment;
+    int method;
+    int level;
+{
+    zip_internal* zi;
+    uInt size_filename;
+    uInt size_comment;
+    uInt i;
+    int err = ZIP_OK;
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    if ((method!=0) && (method!=Z_DEFLATED))
+        return ZIP_PARAMERROR;
+
+    zi = (zip_internal*)file;
+
+    if (zi->in_opened_file_inzip == 1)
+    {
+        err = zipCloseFileInZip (file);
+        if (err != ZIP_OK)
+            return err;
+    }
+
+
+    if (filename==NULL)
+        filename="-";
+
+    if (comment==NULL)
+        size_comment = 0;
+    else
+        size_comment = strlen(comment);
+
+    size_filename = strlen(filename);
+
+    if (zipfi == NULL)
+        zi->ci.dosDate = 0;
+    else
+    {
+        if (zipfi->dosDate != 0)
+            zi->ci.dosDate = zipfi->dosDate;
+        else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
+    }
+
+    zi->ci.flag = 0;
+    if ((level==8) || (level==9))
+      zi->ci.flag |= 2;
+    if ((level==2))
+      zi->ci.flag |= 4;
+    if ((level==1))
+      zi->ci.flag |= 6;
+
+    zi->ci.crc32 = 0;
+    zi->ci.method = method;
+    zi->ci.stream_initialised = 0;
+    zi->ci.pos_in_buffered_data = 0;
+    zi->ci.pos_local_header = ftell(zi->filezip);
+    zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + 
+                                      size_extrafield_global + size_comment;
+    zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
+
+    ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
+    /* version info */
+    ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
+    ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
+    ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
+    ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
+    ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
+    ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
+
+    if (zipfi==NULL)
+        ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); 
+    else
+        ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); 
+
+    if (zipfi==NULL)
+        ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); 
+    else
+        ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
+
+    ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header,4);
+
+    for (i=0;i<size_filename;i++)
+        *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
+
+    for (i=0;i<size_extrafield_global;i++)
+        *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
+              *(((const char*)extrafield_global)+i);
+
+    for (i=0;i<size_comment;i++)
+        *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
+              size_extrafield_global+i) = *(filename+i);
+    if (zi->ci.central_header == NULL)
+        return ZIP_INTERNALERROR;
+
+    /* write the local header */
+    err = ziplocal_putValue(zi->filezip,(uLong)LOCALHEADERMAGIC,4);
+
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)20,2);/* version needed to extract */
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.flag,2);
+
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.method,2);
+
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.dosDate,4);
+
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* crc 32, unknown */
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* compressed size, unknown */
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* uncompressed size, unknown */
+
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)size_filename,2);
+
+    if (err==ZIP_OK)
+        err = ziplocal_putValue(zi->filezip,(uLong)size_extrafield_local,2);
+
+    if ((err==ZIP_OK) && (size_filename>0))
+        if (fwrite(filename,(uInt)size_filename,1,zi->filezip)!=1)
+                err = ZIP_ERRNO;
+
+    if ((err==ZIP_OK) && (size_extrafield_local>0))
+        if (fwrite(extrafield_local,(uInt)size_extrafield_local,1,zi->filezip)
+                                                                           !=1)
+                err = ZIP_ERRNO;
+
+    zi->ci.stream.avail_in = (uInt)0;
+    zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+    zi->ci.stream.next_out = zi->ci.buffered_data;
+    zi->ci.stream.total_in = 0;
+    zi->ci.stream.total_out = 0;
+
+    if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED))
+    {
+        zi->ci.stream.zalloc = (alloc_func)0;
+        zi->ci.stream.zfree = (free_func)0;
+        zi->ci.stream.opaque = (voidpf)0;
+
+        err = deflateInit2(&zi->ci.stream, level,
+               Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
+
+        if (err==Z_OK)
+            zi->ci.stream_initialised = 1;
+    }
+
+
+    if (err==Z_OK)
+        zi->in_opened_file_inzip = 1;
+    return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
+    zipFile file;
+    const voidp buf;
+    unsigned len;
+{
+    zip_internal* zi;
+    int err=ZIP_OK;
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    zi = (zip_internal*)file;
+
+    if (zi->in_opened_file_inzip == 0)
+        return ZIP_PARAMERROR;
+
+    zi->ci.stream.next_in = buf;
+    zi->ci.stream.avail_in = len;
+    zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
+
+    while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+    {
+        if (zi->ci.stream.avail_out == 0)
+        {
+            if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
+                                                                           !=1)
+                err = ZIP_ERRNO;
+            zi->ci.pos_in_buffered_data = 0;
+            zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+            zi->ci.stream.next_out = zi->ci.buffered_data;
+        }
+
+        if (zi->ci.method == Z_DEFLATED)
+        {
+            uLong uTotalOutBefore = zi->ci.stream.total_out;
+            err=deflate(&zi->ci.stream,  Z_NO_FLUSH);
+            zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+
+        }
+        else
+        {
+            uInt copy_this,i;
+            if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+                copy_this = zi->ci.stream.avail_in;
+            else
+                copy_this = zi->ci.stream.avail_out;
+            for (i=0;i<copy_this;i++)
+                *(((char*)zi->ci.stream.next_out)+i) =
+                    *(((const char*)zi->ci.stream.next_in)+i);
+            {
+                zi->ci.stream.avail_in -= copy_this;
+                zi->ci.stream.avail_out-= copy_this;
+                zi->ci.stream.next_in+= copy_this;
+                zi->ci.stream.next_out+= copy_this;
+                zi->ci.stream.total_in+= copy_this;
+                zi->ci.stream.total_out+= copy_this;
+                zi->ci.pos_in_buffered_data += copy_this;
+            }
+        }
+    }
+
+    return 0;
+}
+
+extern int ZEXPORT zipCloseFileInZip (file)
+    zipFile file;
+{
+    zip_internal* zi;
+    int err=ZIP_OK;
+
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    zi = (zip_internal*)file;
+
+    if (zi->in_opened_file_inzip == 0)    
+        return ZIP_PARAMERROR;
+    zi->ci.stream.avail_in = 0;
+    
+    if (zi->ci.method == Z_DEFLATED)
+        while (err==ZIP_OK)
+    {
+        uLong uTotalOutBefore;
+        if (zi->ci.stream.avail_out == 0)
+        {
+            if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
+                                                                           !=1)
+                err = ZIP_ERRNO;
+            zi->ci.pos_in_buffered_data = 0;
+            zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+            zi->ci.stream.next_out = zi->ci.buffered_data;
+        }
+        uTotalOutBefore = zi->ci.stream.total_out;
+        err=deflate(&zi->ci.stream,  Z_FINISH);
+        zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+    }
+
+    if (err==Z_STREAM_END)
+        err=ZIP_OK; /* this is normal */
+
+    if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
+        if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
+                                                                       !=1)
+            err = ZIP_ERRNO;
+
+    if ((zi->ci.method == Z_DEFLATED) && (err==ZIP_OK))
+    {
+        err=deflateEnd(&zi->ci.stream);
+        zi->ci.stream_initialised = 0;
+    }
+
+    ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)zi->ci.crc32,4); /*crc*/
+    ziplocal_putValue_inmemory(zi->ci.central_header+20,
+                                (uLong)zi->ci.stream.total_out,4); /*compr size*/
+    ziplocal_putValue_inmemory(zi->ci.central_header+24,
+                                (uLong)zi->ci.stream.total_in,4); /*uncompr size*/
+
+    if (err==ZIP_OK)
+        err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
+                                       (uLong)zi->ci.size_centralheader);
+    free(zi->ci.central_header);
+
+    if (err==ZIP_OK)
+    {
+        long cur_pos_inzip = ftell(zi->filezip);
+           if (fseek(zi->filezip,
+                  zi->ci.pos_local_header + 14,SEEK_SET)!=0)
+                   err = ZIP_ERRNO;
+
+        if (err==ZIP_OK)
+            err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.crc32,4); /* crc 32, unknown */
+
+        if (err==ZIP_OK) /* compressed size, unknown */
+            err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_out,4); 
+
+        if (err==ZIP_OK) /* uncompressed size, unknown */
+            err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_in,4);
+
+           if (fseek(zi->filezip,
+                  cur_pos_inzip,SEEK_SET)!=0)
+                   err = ZIP_ERRNO;
+    }
+
+    zi->number_entry ++;
+    zi->in_opened_file_inzip = 0;
+
+    return err;
+}
+
+extern int ZEXPORT zipClose (file, global_comment)
+    zipFile file;
+    const char* global_comment;
+{
+    zip_internal* zi;
+    int err = 0;
+    uLong size_centraldir = 0;
+    uLong centraldir_pos_inzip ;
+    uInt size_global_comment;
+    if (file == NULL)
+        return ZIP_PARAMERROR;
+    zi = (zip_internal*)file;
+
+    if (zi->in_opened_file_inzip == 1)
+    {
+        err = zipCloseFileInZip (file);
+    }
+
+    if (global_comment==NULL)
+        size_global_comment = 0;
+    else
+        size_global_comment = strlen(global_comment);
+
+
+    centraldir_pos_inzip = ftell(zi->filezip);
+    if (err==ZIP_OK)
+    {
+        linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
+        while (ldi!=NULL)
+        {
+            if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
+                if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,
+                                        1,zi->filezip) !=1 )
+                    err = ZIP_ERRNO;
+
+            size_centraldir += ldi->filled_in_this_block;
+            ldi = ldi->next_datablock;
+        }
+    }
+    free_datablock(zi->central_dir.first_block);
+
+    if (err==ZIP_OK) /* Magic End */
+        err = ziplocal_putValue(zi->filezip,(uLong)ENDHEADERMAGIC,4);
+
+    if (err==ZIP_OK) /* number of this disk */
+        err = ziplocal_putValue(zi->filezip,(uLong)0,2);
+
+    if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+        err = ziplocal_putValue(zi->filezip,(uLong)0,2);
+
+    if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+        err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
+
+    if (err==ZIP_OK) /* total number of entries in the central dir */
+        err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
+
+    if (err==ZIP_OK) /* size of the central directory */
+        err = ziplocal_putValue(zi->filezip,(uLong)size_centraldir,4);
+
+    if (err==ZIP_OK) /* offset of start of central directory with respect to the 
+                               starting disk number */
+        err = ziplocal_putValue(zi->filezip,(uLong)centraldir_pos_inzip ,4);
+
+    if (err==ZIP_OK) /* zipfile comment length */
+        err = ziplocal_putValue(zi->filezip,(uLong)size_global_comment,2);
+
+    if ((err==ZIP_OK) && (size_global_comment>0))
+        if (fwrite(global_comment,(uInt)size_global_comment,1,zi->filezip) !=1 )
+                err = ZIP_ERRNO;
+    fclose(zi->filezip);
+    TRYFREE(zi);
+
+    return err;
+}
diff --git a/lib/zlib/contrib/minizip/zip.def b/lib/zlib/contrib/minizip/zip.def
new file mode 100644 (file)
index 0000000..5d5079f
--- /dev/null
@@ -0,0 +1,5 @@
+       zipOpen                       @80
+       zipOpenNewFileInZip           @81
+       zipWriteInFileInZip           @82
+       zipCloseFileInZip             @83
+       zipClose                      @84
diff --git a/lib/zlib/contrib/minizip/zip.h b/lib/zlib/contrib/minizip/zip.h
new file mode 100644 (file)
index 0000000..678260b
--- /dev/null
@@ -0,0 +1,150 @@
+/* zip.h -- IO for compress .zip files using zlib 
+   Version 0.15 alpha, Mar 19th, 1998,
+
+   Copyright (C) 1998 Gilles Vollant
+
+   This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
+     WinZip, InfoZip tools and compatible.
+   Encryption and multi volume ZipFile (span) are not supported.
+   Old compressions used by old PKZip 1.x are not supported
+
+  For uncompress .zip file, look at unzip.h
+
+   THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+   CAN CHANGE IN FUTURE VERSION !!
+   I WAIT FEEDBACK at mail info@winimage.com
+   Visit also http://www.winimage.com/zLibDll/zip.htm for evolution
+
+   Condition of use and distribution are the same than zlib :
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+
+/* for more info about .ZIP format, see 
+      ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+   PkWare has also a specification at :
+      ftp://ftp.pkware.com/probdesc.zip
+*/
+
+#ifndef _zip_H
+#define _zip_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zipFile__; 
+typedef zipFile__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK                                  (0)
+#define ZIP_ERRNO               (Z_ERRNO)
+#define ZIP_PARAMERROR                  (-102)
+#define ZIP_INTERNALERROR               (-104)
+
+/* tm_zip contain date/time info */
+typedef struct tm_zip_s 
+{
+       uInt tm_sec;            /* seconds after the minute - [0,59] */
+       uInt tm_min;            /* minutes after the hour - [0,59] */
+       uInt tm_hour;           /* hours since midnight - [0,23] */
+       uInt tm_mday;           /* day of the month - [1,31] */
+       uInt tm_mon;            /* months since January - [0,11] */
+       uInt tm_year;           /* years - [1980..2044] */
+} tm_zip;
+
+typedef struct
+{
+       tm_zip      tmz_date;       /* date in understandable format           */
+    uLong       dosDate;       /* if dos_date == 0, tmu_date is used      */
+/*    uLong       flag;        */   /* general purpose bit flag        2 bytes */
+
+    uLong       internal_fa;    /* internal file attributes        2 bytes */
+    uLong       external_fa;    /* external file attributes        4 bytes */
+} zip_fileinfo;
+
+extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
+/*
+  Create a zipfile.
+        pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on
+          an Unix computer "zlib/zlib111.zip".
+        if the file pathname exist and append=1, the zip will be created at the end
+          of the file. (useful if the file contain a self extractor code)
+        If the zipfile cannot be opened, the return value is NULL.
+     Else, the return value is a zipFile Handle, usable with other function
+          of this zip package.
+
+
+*/
+
+extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
+                                          const char* filename,
+                                          const zip_fileinfo* zipfi,
+                                          const void* extrafield_local,
+                                          uInt size_extrafield_local,
+                                          const void* extrafield_global,
+                                          uInt size_extrafield_global,
+                                          const char* comment,
+                                          int method,
+                                          int level));
+/*
+  Open a file in the ZIP for writing.
+  filename : the filename in zip (if NULL, '-' without quote will be used
+  *zipfi contain supplemental information
+  if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
+    contains the extrafield data the the local header
+  if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+    contains the extrafield data the the local header
+  if comment != NULL, comment contain the comment string
+  method contain the compression method (0 for store, Z_DEFLATED for deflate)
+  level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+*/
+
+extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
+                                          const voidp buf,
+                                          unsigned len));
+/*
+  Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+  Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipClose OF((zipFile file,
+                               const char* global_comment));
+/*
+  Close the zipfile
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _zip_H */
diff --git a/lib/zlib/contrib/minizip/zlibvc.def b/lib/zlib/contrib/minizip/zlibvc.def
new file mode 100644 (file)
index 0000000..7e9d60d
--- /dev/null
@@ -0,0 +1,74 @@
+LIBRARY                "zlib"
+
+DESCRIPTION    '"""zlib data compression library"""'
+
+
+VERSION                1.11
+
+
+HEAPSIZE       1048576,8192
+
+EXPORTS
+    adler32                        @1
+    compress                       @2
+    crc32                          @3
+    deflate                        @4
+    deflateCopy                    @5
+    deflateEnd                     @6
+    deflateInit2_                  @7
+    deflateInit_                   @8
+    deflateParams                  @9
+    deflateReset                   @10
+    deflateSetDictionary           @11
+    gzclose                        @12
+    gzdopen                        @13
+    gzerror                        @14
+    gzflush                        @15
+    gzopen                         @16
+    gzread                         @17
+    gzwrite                        @18
+    inflate                        @19
+    inflateEnd                     @20
+    inflateInit2_                  @21
+    inflateInit_                   @22
+    inflateReset                   @23
+    inflateSetDictionary           @24
+    inflateSync                    @25
+    uncompress                     @26
+    zlibVersion                    @27
+    gzprintf                       @28
+    gzputc                         @29
+    gzgetc                         @30
+    gzseek                         @31
+    gzrewind                       @32
+    gztell                         @33
+    gzeof                          @34
+    gzsetparams                    @35
+    zError                         @36
+    inflateSyncPoint               @37
+    get_crc_table                  @38
+    compress2                      @39
+    gzputs                         @40
+    gzgets                         @41
+
+       unzOpen                       @61
+       unzClose                      @62
+       unzGetGlobalInfo              @63
+       unzGetCurrentFileInfo         @64
+       unzGoToFirstFile              @65
+       unzGoToNextFile               @66
+       unzOpenCurrentFile            @67
+       unzReadCurrentFile            @68
+       unztell                       @70
+       unzeof                        @71
+       unzCloseCurrentFile           @72
+       unzGetGlobalComment           @73
+       unzStringFileNameCompare      @74
+       unzLocateFile                 @75
+       unzGetLocalExtrafield         @76
+
+       zipOpen                       @80
+       zipOpenNewFileInZip           @81
+       zipWriteInFileInZip           @82
+       zipCloseFileInZip             @83
+       zipClose                      @84
diff --git a/lib/zlib/contrib/minizip/zlibvc.dsp b/lib/zlib/contrib/minizip/zlibvc.dsp
new file mode 100644 (file)
index 0000000..a70d4d4
--- /dev/null
@@ -0,0 +1,651 @@
+# Microsoft Developer Studio Project File - Name="zlibvc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+# TARGTYPE "Win32 (ALPHA) Dynamic-Link Library" 0x0602
+
+CFG=zlibvc - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "zlibvc.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "zlibvc.mak" CFG="zlibvc - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "zlibvc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseAxp" (based on\
+ "Win32 (ALPHA) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutAsm" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zlibvc - Win32 ReleaseWithoutCrtdll" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\zlib.dll"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc__"
+# PROP BASE Intermediate_Dir "zlibvc__"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc__"
+# PROP Intermediate_Dir "zlibvc__"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 crtdll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /machine:ALPHA /nodefaultlib /out:"zlibvc__\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_0"
+# PROP BASE Intermediate_Dir "zlibvc_0"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_0"
+# PROP Intermediate_Dir "zlibvc_0"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_0\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zlibvc_1"
+# PROP BASE Intermediate_Dir "zlibvc_1"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zlibvc_1"
+# PROP Intermediate_Dir "zlibvc_1"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+CPP=cl.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_WIN32" /D "BUILD_ZLIBDLL" /D "ZLIB_DLL" /D "DYNAMIC_CRC_TABLE" /D "ASMV" /FAcs /FR /FD /c
+# SUBTRACT CPP /YX
+MTL=midl.exe
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\Release\zlib.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 gvmat32.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib crtdll.lib /nologo /subsystem:windows /dll /map /machine:I386 /nodefaultlib /out:".\zlibvc_1\zlib.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "zlibvc - Win32 Release"
+# Name "zlibvc - Win32 Debug"
+# Name "zlibvc - Win32 ReleaseAxp"
+# Name "zlibvc - Win32 ReleaseWithoutAsm"
+# Name "zlibvc - Win32 ReleaseWithoutCrtdll"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\adler32.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ADLER=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_COMPR=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\crc32.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_CRC32=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\deflate.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_DEFLA=\
+       ".\deflate.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gvmat32c.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\gzio.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_GZIO_=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFBL=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFCO=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inffast.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFFA=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inffast.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inflate.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFLA=\
+       ".\infblock.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFTR=\
+       ".\inftrees.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_INFUT=\
+       ".\infblock.h"\
+       ".\infcodes.h"\
+       ".\inftrees.h"\
+       ".\infutil.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\trees.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_TREES=\
+       ".\deflate.h"\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\uncompr.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_UNCOM=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\unzip.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zip.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlibvc.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.c
+
+!IF  "$(CFG)" == "zlibvc - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 Debug"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseAxp"
+
+DEP_CPP_ZUTIL=\
+       ".\zconf.h"\
+       ".\zlib.h"\
+       ".\zutil.h"\
+       
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutAsm"
+
+!ELSEIF  "$(CFG)" == "zlibvc - Win32 ReleaseWithoutCrtdll"
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\deflate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infcodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inffast.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\inftrees.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\infutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zutil.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/lib/zlib/contrib/minizip/zlibvc.dsw b/lib/zlib/contrib/minizip/zlibvc.dsw
new file mode 100644 (file)
index 0000000..493cd87
--- /dev/null
@@ -0,0 +1,41 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zlibstat"=.\zlibstat.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zlibvc"=.\zlibvc.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lib/zlib/contrib/untgz/Makefile b/lib/zlib/contrib/untgz/Makefile
new file mode 100644 (file)
index 0000000..409b4bd
--- /dev/null
@@ -0,0 +1,14 @@
+CC=cc
+CFLAGS=-g
+
+untgz: untgz.o  ../../libz.a
+       $(CC) $(CFLAGS) -o untgz  untgz.o -L../.. -lz
+
+untgz.o: untgz.c ../../zlib.h
+       $(CC) $(CFLAGS) -c -I../.. untgz.c
+
+../../libz.a:
+       cd ../..; make
+
+clean:
+       rm -f untgz untgz.o *~
diff --git a/lib/zlib/contrib/untgz/makefile.w32 b/lib/zlib/contrib/untgz/makefile.w32
new file mode 100644 (file)
index 0000000..c99dc28
--- /dev/null
@@ -0,0 +1,63 @@
+# Makefile for zlib.  Modified for mingw32
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile, 
+# 
+#   make -fmakefile.w32
+# 
+
+CC=gcc
+
+# Generate dependencies (see end of the file)
+
+CPPFLAGS=-MMD 
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+             -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is not found, replace with copy /Y .
+CP=cp -f
+
+# The default value of RM is "rm -f."  
+# If "rm.exe" is not found, uncomment:
+# RM=del
+
+LD=gcc
+LDLIBS=-L. -lz
+LDFLAGS=-s
+
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o \
+       inffast.o
+
+TEST_OBJS = minigzip.o untgz.o
+
+all: minigzip.exe untgz.exe
+
+rebuild:       clean   all
+
+libz.a: $(OBJS)
+       $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+       $(LD) $(LDFLAGS) -o $@ $< $(LDLIBS)
+
+.PHONY : clean
+
+clean:
+       $(RM) *.d *.o *.exe libz.a foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
+
diff --git a/lib/zlib/contrib/untgz/untgz.c b/lib/zlib/contrib/untgz/untgz.c
new file mode 100644 (file)
index 0000000..4a431ff
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * untgz.c -- Display contents and/or extract file from
+ * a gzip'd TAR file
+ * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef unix
+# include <unistd.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "zlib.h"
+
+#ifdef WIN32
+#  ifndef F_OK
+#    define F_OK (0)
+#  endif
+#  ifdef _MSC_VER
+#    define mkdir(dirname,mode) _mkdir(dirname)
+#    define strdup(str)         _strdup(str)
+#    define unlink(fn)          _unlink(fn)
+#    define access(path,mode)   _access(path,mode)
+#  else
+#    define mkdir(dirname,mode) _mkdir(dirname)
+#  endif
+#else
+#  include <utime.h>
+#endif
+
+
+/* Values used in typeflag field.  */
+
+#define REGTYPE         '0'            /* regular file */
+#define AREGTYPE '\0'          /* regular file */
+#define LNKTYPE  '1'           /* link */
+#define SYMTYPE  '2'           /* reserved */
+#define CHRTYPE  '3'           /* character special */
+#define BLKTYPE  '4'           /* block special */
+#define DIRTYPE  '5'           /* directory */
+#define FIFOTYPE '6'           /* FIFO special */
+#define CONTTYPE '7'           /* reserved */
+
+#define BLOCKSIZE 512
+
+struct tar_header
+{                              /* byte offset */
+  char name[100];              /*   0 */
+  char mode[8];                        /* 100 */
+  char uid[8];                 /* 108 */
+  char gid[8];                 /* 116 */
+  char size[12];               /* 124 */
+  char mtime[12];              /* 136 */
+  char chksum[8];              /* 148 */
+  char typeflag;               /* 156 */
+  char linkname[100];          /* 157 */
+  char magic[6];               /* 257 */
+  char version[2];             /* 263 */
+  char uname[32];              /* 265 */
+  char gname[32];              /* 297 */
+  char devmajor[8];            /* 329 */
+  char devminor[8];            /* 337 */
+  char prefix[155];            /* 345 */
+                               /* 500 */
+};
+
+union tar_buffer {
+  char               buffer[BLOCKSIZE];
+  struct tar_header  header;
+};
+
+enum { TGZ_EXTRACT = 0, TGZ_LIST };
+
+static char *TGZfname  OF((const char *));
+void TGZnotfound       OF((const char *));
+
+int getoct             OF((char *, int));
+char *strtime          OF((time_t *));
+int ExprMatch          OF((char *,char *));
+
+int makedir            OF((char *));
+int matchname          OF((int,int,char **,char *));
+
+void error             OF((const char *));
+int  tar               OF((gzFile, int, int, int, char **));
+
+void help              OF((int));
+int main               OF((int, char **));
+
+char *prog;
+
+/* This will give a benign warning */
+
+static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar", NULL };
+
+/* Return the real name of the TGZ archive */
+/* or NULL if it does not exist. */
+
+static char *TGZfname OF((const char *fname))
+{
+  static char buffer[1024];
+  int origlen,i;
+  
+  strcpy(buffer,fname);
+  origlen = strlen(buffer);
+
+  for (i=0; TGZprefix[i]; i++)
+    {
+       strcpy(buffer+origlen,TGZprefix[i]);
+       if (access(buffer,F_OK) == 0)
+         return buffer;
+    }
+  return NULL;
+}
+
+/* error message for the filename */
+
+void TGZnotfound OF((const char *fname))
+{
+  int i;
+
+  fprintf(stderr,"%s : couldn't find ",prog);
+  for (i=0;TGZprefix[i];i++)
+    fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
+            fname,
+            TGZprefix[i]);
+  exit(1);
+}
+
+
+/* help functions */
+
+int getoct(char *p,int width)
+{
+  int result = 0;
+  char c;
+  
+  while (width --)
+    {
+      c = *p++;
+      if (c == ' ')
+       continue;
+      if (c == 0)
+       break;
+      result = result * 8 + (c - '0');
+    }
+  return result;
+}
+
+char *strtime (time_t *t)
+{
+  struct tm   *local;
+  static char result[32];
+
+  local = localtime(t);
+  sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
+         local->tm_mday, local->tm_mon+1, local->tm_year+1900,
+         local->tm_hour, local->tm_min,   local->tm_sec);
+  return result;
+}
+
+
+/* regular expression matching */
+
+#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
+
+int ExprMatch(char *string,char *expr)
+{
+  while (1)
+    {
+      if (ISSPECIAL(*expr))
+       {
+         if (*expr == '/')
+           {
+             if (*string != '\\' && *string != '/')
+               return 0;
+             string ++; expr++;
+           }
+         else if (*expr == '*')
+           {
+             if (*expr ++ == 0)
+               return 1;
+             while (*++string != *expr)
+               if (*string == 0)
+                 return 0;
+           }
+       }
+      else
+       {
+         if (*string != *expr)
+           return 0;
+         if (*expr++ == 0)
+           return 1;
+         string++;
+       }
+    }
+}
+
+/* recursive make directory */
+/* abort if you get an ENOENT errno somewhere in the middle */
+/* e.g. ignore error "mkdir on existing directory" */
+/* */
+/* return 1 if OK */
+/*        0 on error */
+
+int makedir (char *newdir)
+{
+  char *buffer = strdup(newdir);
+  char *p;
+  int  len = strlen(buffer);
+  
+  if (len <= 0) {
+    free(buffer);
+    return 0;
+  }
+  if (buffer[len-1] == '/') {
+    buffer[len-1] = '\0';
+  }
+  if (mkdir(buffer, 0775) == 0)
+    {
+      free(buffer);
+      return 1;
+    }
+
+  p = buffer+1;
+  while (1)
+    {
+      char hold;
+      
+      while(*p && *p != '\\' && *p != '/')
+       p++;
+      hold = *p;
+      *p = 0;
+      if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
+       {
+         fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
+         free(buffer);
+         return 0;
+       }
+      if (hold == 0)
+       break;
+      *p++ = hold;
+    }
+  free(buffer);
+  return 1;
+}
+
+int matchname (int arg,int argc,char **argv,char *fname)
+{
+  if (arg == argc)             /* no arguments given (untgz tgzarchive) */
+    return 1;
+
+  while (arg < argc)
+    if (ExprMatch(fname,argv[arg++]))
+      return 1;
+
+  return 0; /* ignore this for the moment being */
+}
+
+
+/* Tar file list or extract */
+
+int tar (gzFile in,int action,int arg,int argc,char **argv)
+{
+  union  tar_buffer buffer;
+  int    len;
+  int    err;
+  int    getheader = 1;
+  int    remaining = 0;
+  FILE   *outfile = NULL;
+  char   fname[BLOCKSIZE];
+  time_t tartime;
+  
+  if (action == TGZ_LIST)
+    printf("     day      time     size                       file\n"
+          " ---------- -------- --------- -------------------------------------\n");
+  while (1)
+    {
+      len = gzread(in, &buffer, BLOCKSIZE);
+      if (len < 0)
+       error (gzerror(in, &err));
+      /*
+       * Always expect complete blocks to process
+       * the tar information.
+       */
+      if (len != BLOCKSIZE)
+       error("gzread: incomplete block read");
+      
+      /*
+       * If we have to get a tar header
+       */
+      if (getheader == 1)
+       {
+         /*
+          * if we met the end of the tar
+          * or the end-of-tar block,
+          * we are done
+          */
+         if ((len == 0)  || (buffer.header.name[0]== 0)) break;
+
+         tartime = (time_t)getoct(buffer.header.mtime,12);
+         strcpy(fname,buffer.header.name);
+         
+         switch (buffer.header.typeflag)
+           {
+           case DIRTYPE:
+             if (action == TGZ_LIST)
+               printf(" %s     <dir> %s\n",strtime(&tartime),fname);
+             if (action == TGZ_EXTRACT)
+               makedir(fname);
+             break;
+           case REGTYPE:
+           case AREGTYPE:
+             remaining = getoct(buffer.header.size,12);
+             if (action == TGZ_LIST)
+               printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
+             if (action == TGZ_EXTRACT)
+               {
+                 if ((remaining) && (matchname(arg,argc,argv,fname)))
+                   {
+                     outfile = fopen(fname,"wb");
+                     if (outfile == NULL) {
+                       /* try creating directory */
+                       char *p = strrchr(fname, '/');
+                       if (p != NULL) {
+                         *p = '\0';
+                         makedir(fname);
+                         *p = '/';
+                         outfile = fopen(fname,"wb");
+                       }
+                     }
+                     fprintf(stderr,
+                             "%s %s\n",
+                             (outfile) ? "Extracting" : "Couldn't create",
+                             fname);
+                   }
+                 else
+                   outfile = NULL;
+               }
+             /*
+              * could have no contents
+              */
+             getheader = (remaining) ? 0 : 1;
+             break;
+           default:
+             if (action == TGZ_LIST)
+               printf(" %s     <---> %s\n",strtime(&tartime),fname);
+             break;
+           }
+       }
+      else
+       {
+         unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
+
+         if ((action == TGZ_EXTRACT) && (outfile != NULL))
+           {
+             if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
+               {
+                 fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
+                 fclose(outfile);
+                 unlink(fname);
+               }
+           }
+         remaining -= bytes;
+         if (remaining == 0)
+           {
+             getheader = 1;
+             if ((action == TGZ_EXTRACT) && (outfile != NULL))
+               {
+#ifdef WIN32
+                 HANDLE hFile;
+                 FILETIME ftm,ftLocal;
+                 SYSTEMTIME st;
+                 struct tm localt;
+                 fclose(outfile);
+
+                 localt = *localtime(&tartime);
+
+                 hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
+                                    0, NULL, OPEN_EXISTING, 0, NULL);
+                 
+                 st.wYear = (WORD)localt.tm_year+1900;
+                 st.wMonth = (WORD)localt.tm_mon;
+                 st.wDayOfWeek = (WORD)localt.tm_wday;
+                 st.wDay = (WORD)localt.tm_mday;
+                 st.wHour = (WORD)localt.tm_hour;
+                 st.wMinute = (WORD)localt.tm_min;
+                 st.wSecond = (WORD)localt.tm_sec;
+                 st.wMilliseconds = 0;
+                 SystemTimeToFileTime(&st,&ftLocal);
+                 LocalFileTimeToFileTime(&ftLocal,&ftm);
+                 SetFileTime(hFile,&ftm,NULL,&ftm);
+                 CloseHandle(hFile);
+
+                 outfile = NULL;
+#else
+                 struct utimbuf settime;
+
+                 settime.actime = settime.modtime = tartime;
+
+                 fclose(outfile);
+                 outfile = NULL;
+                 utime(fname,&settime);
+#endif
+               }
+           }
+       }
+    }
+  
+  if (gzclose(in) != Z_OK)
+    error("failed gzclose");
+
+  return 0;
+}
+
+
+/* =========================================================== */
+
+void help(int exitval)
+{
+  fprintf(stderr,
+         "untgz v 0.1\n"
+         " an sample application of zlib 1.0.4\n\n"
+          "Usage : untgz TGZfile            to extract all files\n"
+          "        untgz TGZfile fname ...  to extract selected files\n"
+          "        untgz -l TGZfile         to list archive contents\n"
+          "        untgz -h                 to display this help\n\n");
+  exit(exitval);
+}
+
+void error(const char *msg)
+{
+    fprintf(stderr, "%s: %s\n", prog, msg);
+    exit(1);
+}
+
+
+/* ====================================================================== */
+
+int _CRT_glob = 0;     /* disable globbing of the arguments */
+
+int main(int argc,char **argv)
+{
+    int        action = TGZ_EXTRACT;
+    int        arg = 1;
+    char       *TGZfile;
+    gzFile     *f;
+    
+
+    prog = strrchr(argv[0],'\\');
+    if (prog == NULL)
+      {
+       prog = strrchr(argv[0],'/');
+       if (prog == NULL)
+         {
+           prog = strrchr(argv[0],':');
+           if (prog == NULL)
+             prog = argv[0];
+           else
+             prog++;
+         }
+       else
+         prog++;
+      }
+    else
+      prog++;
+    
+    if (argc == 1)
+      help(0);
+
+    if (strcmp(argv[arg],"-l") == 0)
+      {
+       action = TGZ_LIST;
+       if (argc == ++arg)
+         help(0);
+      }
+    else if (strcmp(argv[arg],"-h") == 0)
+      {
+       help(0);
+      }
+
+    if ((TGZfile = TGZfname(argv[arg])) == NULL)
+      TGZnotfound(argv[arg]);            
+
+    ++arg;
+    if ((action == TGZ_LIST) && (arg != argc))
+      help(1);
+
+/*
+ *  Process the TGZ file
+ */
+    switch(action)
+      {
+      case TGZ_LIST:
+      case TGZ_EXTRACT:
+       f = gzopen(TGZfile,"rb");
+       if (f == NULL)
+         {
+           fprintf(stderr,"%s: Couldn't gzopen %s\n",
+                   prog,
+                   TGZfile);
+           return 1;
+         }
+       exit(tar(f, action, arg, argc, argv));
+      break;
+       
+      default:
+       error("Unknown option!");
+       exit(1);
+      }
+
+    return 0;
+}
diff --git a/lib/zlib/contrib/visual-basic.txt b/lib/zlib/contrib/visual-basic.txt
new file mode 100644 (file)
index 0000000..10fb44b
--- /dev/null
@@ -0,0 +1,69 @@
+See below some functions declarations for Visual Basic.
+
+Frequently Asked Question:
+
+Q: Each time I use the compress function I get the -5 error (not enough
+   room in the output buffer).
+
+A: Make sure that the length of the compressed buffer is passed by
+   reference ("as any"), not by value ("as long"). Also check that
+   before the call of compress this length is equal to the total size of
+   the compressed buffer and not zero.
+
+
+From: "Jon Caruana" <jon-net@usa.net>
+Subject: Re: How to port zlib declares to vb?
+Date: Mon, 28 Oct 1996 18:33:03 -0600
+
+Got the answer! (I haven't had time to check this but it's what I got, and
+looks correct):
+
+He has the following routines working:
+        compress
+        uncompress
+        gzopen
+        gzwrite
+        gzread
+        gzclose
+
+Declares follow: (Quoted from Carlos Rios <c_rios@sonda.cl>, in Vb4 form)
+
+#If Win16 Then   'Use Win16 calls.
+Declare Function compress Lib "ZLIB.DLL" (ByVal compr As
+        String, comprLen As Any, ByVal buf As String, ByVal buflen
+        As Long) As Integer
+Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr
+        As String, uncomprLen As Any, ByVal compr As String, ByVal
+        lcompr As Long) As Integer
+Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As
+        String, ByVal mode As String) As Long
+Declare Function gzread Lib "ZLIB.DLL" (ByVal file As
+        Long, ByVal uncompr As String, ByVal uncomprLen As Integer)
+        As Integer
+Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As
+        Long, ByVal uncompr As String, ByVal uncomprLen As Integer)
+        As Integer
+Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As
+        Long) As Integer
+#Else
+Declare Function compress Lib "ZLIB32.DLL"
+        (ByVal compr As String, comprLen As Any, ByVal buf As
+        String, ByVal buflen As Long) As Integer
+Declare Function uncompress Lib "ZLIB32.DLL"
+        (ByVal uncompr As String, uncomprLen As Any, ByVal compr As
+        String, ByVal lcompr As Long) As Long
+Declare Function gzopen Lib "ZLIB32.DLL"
+        (ByVal file As String, ByVal mode As String) As Long
+Declare Function gzread Lib "ZLIB32.DLL"
+        (ByVal file As Long, ByVal uncompr As String, ByVal
+        uncomprLen As Long) As Long
+Declare Function gzwrite Lib "ZLIB32.DLL"
+        (ByVal file As Long, ByVal uncompr As String, ByVal
+        uncomprLen As Long) As Long
+Declare Function gzclose Lib "ZLIB32.DLL"
+        (ByVal file As Long) As Long
+#End If
+
+-Jon Caruana
+jon-net@usa.net
+Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member
diff --git a/lib/zlib/crc32.c b/lib/zlib/crc32.c
new file mode 100644 (file)
index 0000000..a91101a
--- /dev/null
@@ -0,0 +1,162 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+#define local static
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The table is simply the CRC of all possible eight bit values.  This is all
+  the information needed to generate CRC's on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+  uLong c;
+  int n, k;
+  uLong poly;            /* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  poly = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+    poly |= 1L << (31 - p[n]);
+  for (n = 0; n < 256; n++)
+  {
+    c = (uLong)n;
+    for (k = 0; k < 8; k++)
+      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+    crc_table[n] = c;
+  }
+  crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+#endif
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (crc_table_empty) make_crc_table();
+#endif
+  return (const uLongf *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+    uLong crc;
+    const Bytef *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    crc = crc ^ 0xffffffffL;
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+    return crc ^ 0xffffffffL;
+}
diff --git a/lib/zlib/deflate.c b/lib/zlib/deflate.c
new file mode 100644 (file)
index 0000000..25d5818
--- /dev/null
@@ -0,0 +1,1350 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.1.3 Copyright 1995-1998 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                        Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                 version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static const char* my_version = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+       return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == Z_NULL) {
+       strm->zalloc = zcalloc;
+       strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#ifdef FASTEST
+    level = 1;
+#endif
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+       strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    s = strm->state;
+    strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+       length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+       dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+       INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+       level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+       return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+       /* Flush the last buffer: */
+       err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+       s->level = level;
+       s->max_lazy_match   = configuration_table[level].max_lazy;
+       s->good_match       = configuration_table[level].good_length;
+       s->nice_match       = configuration_table[level].nice_length;
+       s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+       flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+       (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+       if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+       /* Save the adler32 of the preset dictionary: */
+       if (s->strstart != 0) {
+           putShortMSB(s, (uInt)(strm->adler >> 16));
+           putShortMSB(s, (uInt)(strm->adler & 0xffff));
+       }
+       strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+           /* Since avail_out is 0, deflate will be called again with
+            * more output space, but possibly with both pending and
+            * avail_in equal to zero. There won't be anything to do,
+            * but this is not an error situation so make sure we
+            * return OK instead of BUF_ERROR at next call of deflate:
+             */
+           s->last_flush = -1;
+           return Z_OK;
+       }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+              flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+       bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+           if (strm->avail_out == 0) {
+               s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+           }
+           return Z_OK;
+           /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+            * of deflate should use the same flush parameter to make sure
+            * that the flush is complete. So we don't have to output an
+            * empty block here, this will be done at next call. This also
+            * ensures that for a very small output buffer, we emit at most
+            * one empty block.
+            */
+       }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+           if (strm->avail_out == 0) {
+             s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+             return Z_OK;
+           }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+       status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    *dest = *source;
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!strm->state->noheader) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+#ifndef FASTEST
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+
+#else /* FASTEST */
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 only
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+            *++scan == *++match && *++scan == *++match &&
+            *++scan == *++match && *++scan == *++match &&
+            *++scan == *++match && *++scan == *++match &&
+            scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return len <= s->lookahead ? len : s->lookahead;
+}
+#endif /* FASTEST */
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+               start, match, length);
+        do {
+           fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+       } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+            more = wsize;
+
+        } else if (more == (unsigned)(-1)) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+           n = s->hash_size;
+           p = &s->head[n];
+           do {
+               m = *--p;
+               *p = (Pos)(m >= wsize ? m-wsize : NIL);
+           } while (--n);
+
+           n = wsize;
+#ifndef FASTEST
+           p = &s->prev[n];
+           do {
+               m = *--p;
+               *p = (Pos)(m >= wsize ? m-wsize : NIL);
+               /* If n is not on any hash chain, prev[n] is garbage but
+                * its value will never be used.
+                */
+           } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+               (ulg)((long)s->strstart - s->block_start), \
+               (eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                  s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+       Assert(s->block_start >= 0L, "block gone");
+
+       s->strstart += s->lookahead;
+       s->lookahead = 0;
+
+       /* Emit a stored block if pending_buf will be full: */
+       max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+           /* strstart == 0 is possible when wraparound on 16-bit machine */
+           s->lookahead = (uInt)(s->strstart - max_start);
+           s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+       }
+       /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+       }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+               return need_more;
+           }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else
+#endif
+           {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++; 
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+               return need_more;
+           }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                          s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+           _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+           if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/lib/zlib/deflate.h b/lib/zlib/deflate.h
new file mode 100644 (file)
index 0000000..962676d
--- /dev/null
@@ -0,0 +1,318 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1998 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+#include "zutil.h"
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+                         int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length) 
+#endif
+
+#endif
diff --git a/lib/zlib/descrip.mms b/lib/zlib/descrip.mms
new file mode 100644 (file)
index 0000000..9d36459
--- /dev/null
@@ -0,0 +1,48 @@
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser <m.zinser@gsi.de>
+
+cc_defs = 
+c_deb = 
+
+.ifdef __DECC__
+pref = /prefix=all
+.endif
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\
+       deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\
+       inftrees.obj, infcodes.obj, infutil.obj, inffast.obj
+
+CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
+
+all : example.exe minigzip.exe
+        @ write sys$output " Example applications available"
+libz.olb : libz.olb($(OBJS))
+       @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+              link example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+              link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib
+
+clean : 
+       delete *.obj;*,libz.olb;*
+
+
+# Other dependencies.
+adler32.obj : zutil.h zlib.h zconf.h
+compress.obj : zlib.h zconf.h
+crc32.obj : zutil.h zlib.h zconf.h
+deflate.obj : deflate.h zutil.h zlib.h zconf.h
+example.obj : zlib.h zconf.h
+gzio.obj : zutil.h zlib.h zconf.h
+infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.obj : zutil.h zlib.h zconf.h infblock.h
+inftrees.obj : zutil.h zlib.h zconf.h inftrees.h
+infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.obj : zlib.h zconf.h
+trees.obj : deflate.h zutil.h zlib.h zconf.h
+uncompr.obj : zlib.h zconf.h
+zutil.obj : zutil.h zlib.h zconf.h
diff --git a/lib/zlib/example.c b/lib/zlib/example.c
new file mode 100644 (file)
index 0000000..8307c84
--- /dev/null
@@ -0,0 +1,556 @@
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#else
+   extern void exit  OF((int));
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+#  define TESTFILE "foo-gz"
+#else
+#  define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+    if (err != Z_OK) { \
+        fprintf(stderr, "%s error: %d\n", msg, err); \
+        exit(1); \
+    } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress      OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_gzio          OF((const char *out, const char *in, 
+                           Byte *uncompr, int uncomprLen));
+void test_deflate       OF((Byte *compr, uLong comprLen));
+void test_inflate       OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_flush         OF((Byte *compr, uLong *comprLen));
+void test_sync          OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate  OF((Byte *compr, uLong comprLen));
+void test_dict_inflate  OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+int  main               OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    uLong len = strlen(hello)+1;
+
+    err = compress(compr, &comprLen, (const Bytef*)hello, len);
+    CHECK_ERR(err, "compress");
+
+    strcpy((char*)uncompr, "garbage");
+
+    err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+    CHECK_ERR(err, "uncompress");
+
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad uncompress\n");
+       exit(1);
+    } else {
+        printf("uncompress(): %s\n", (char *)uncompr);
+    }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(out, in, uncompr, uncomprLen)
+    const char *out; /* compressed output file */
+    const char *in;  /* compressed input file */
+    Byte *uncompr;
+    int  uncomprLen;
+{
+    int err;
+    int len = strlen(hello)+1;
+    gzFile file;
+    z_off_t pos;
+
+    file = gzopen(out, "wb");
+    if (file == NULL) {
+        fprintf(stderr, "gzopen error\n");
+        exit(1);
+    }
+    gzputc(file, 'h');
+    if (gzputs(file, "ello") != 4) {
+        fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    if (gzprintf(file, ", %s!", "hello") != 8) {
+        fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+    gzclose(file);
+
+    file = gzopen(in, "rb");
+    if (file == NULL) {
+        fprintf(stderr, "gzopen error\n");
+    }
+    strcpy((char*)uncompr, "garbage");
+
+    uncomprLen = gzread(file, uncompr, (unsigned)uncomprLen);
+    if (uncomprLen != len) {
+        fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+       exit(1);
+    } else {
+        printf("gzread(): %s\n", (char *)uncompr);
+    }
+
+    pos = gzseek(file, -8L, SEEK_CUR);
+    if (pos != 6 || gztell(file) != pos) {
+       fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+               (long)pos, (long)gztell(file));
+       exit(1);
+    }
+
+    if (gzgetc(file) != ' ') {
+       fprintf(stderr, "gzgetc error\n");
+       exit(1);
+    }
+
+    gzgets(file, (char*)uncompr, uncomprLen);
+    uncomprLen = strlen((char*)uncompr);
+    if (uncomprLen != 6) { /* "hello!" */
+        fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    if (strcmp((char*)uncompr, hello+7)) {
+        fprintf(stderr, "bad gzgets after gzseek\n");
+       exit(1);
+    } else {
+        printf("gzgets() after gzseek: %s\n", (char *)uncompr);
+    }
+
+    gzclose(file);
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+    Byte *compr;
+    uLong comprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+    int len = strlen(hello)+1;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+    CHECK_ERR(err, "deflateInit");
+
+    c_stream.next_in  = (Bytef*)hello;
+    c_stream.next_out = compr;
+
+    while (c_stream.total_in != (uLong)len && c_stream.total_out < comprLen) {
+        c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+        err = deflate(&c_stream, Z_NO_FLUSH);
+        CHECK_ERR(err, "deflate");
+    }
+    /* Finish the stream, still forcing small buffers: */
+    for (;;) {
+        c_stream.avail_out = 1;
+        err = deflate(&c_stream, Z_FINISH);
+        if (err == Z_STREAM_END) break;
+        CHECK_ERR(err, "deflate");
+    }
+
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = 0;
+    d_stream.next_out = uncompr;
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+        d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+        err = inflate(&d_stream, Z_NO_FLUSH);
+        if (err == Z_STREAM_END) break;
+        CHECK_ERR(err, "inflate");
+    }
+
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad inflate\n");
+       exit(1);
+    } else {
+        printf("inflate(): %s\n", (char *)uncompr);
+    }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_BEST_SPEED);
+    CHECK_ERR(err, "deflateInit");
+
+    c_stream.next_out = compr;
+    c_stream.avail_out = (uInt)comprLen;
+
+    /* At this point, uncompr is still mostly zeroes, so it should compress
+     * very well:
+     */
+    c_stream.next_in = uncompr;
+    c_stream.avail_in = (uInt)uncomprLen;
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "deflate");
+    if (c_stream.avail_in != 0) {
+        fprintf(stderr, "deflate not greedy\n");
+       exit(1);
+    }
+
+    /* Feed in already compressed data and switch to no compression: */
+    deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+    c_stream.next_in = compr;
+    c_stream.avail_in = (uInt)comprLen/2;
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "deflate");
+
+    /* Switch back to compressing mode: */
+    deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+    c_stream.next_in = uncompr;
+    c_stream.avail_in = (uInt)uncomprLen;
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "deflate");
+
+    err = deflate(&c_stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        fprintf(stderr, "deflate should report Z_STREAM_END\n");
+       exit(1);
+    }
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = (uInt)comprLen;
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    for (;;) {
+        d_stream.next_out = uncompr;            /* discard the output */
+       d_stream.avail_out = (uInt)uncomprLen;
+        err = inflate(&d_stream, Z_NO_FLUSH);
+        if (err == Z_STREAM_END) break;
+        CHECK_ERR(err, "large inflate");
+    }
+
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+        fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+       exit(1);
+    } else {
+        printf("large_inflate(): OK\n");
+    }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+    Byte *compr;
+    uLong *comprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+    int len = strlen(hello)+1;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+    CHECK_ERR(err, "deflateInit");
+
+    c_stream.next_in  = (Bytef*)hello;
+    c_stream.next_out = compr;
+    c_stream.avail_in = 3;
+    c_stream.avail_out = (uInt)*comprLen;
+    err = deflate(&c_stream, Z_FULL_FLUSH);
+    CHECK_ERR(err, "deflate");
+
+    compr[3]++; /* force an error in first compressed block */
+    c_stream.avail_in = len - 3;
+
+    err = deflate(&c_stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        CHECK_ERR(err, "deflate");
+    }
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+
+    *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = 2; /* just read the zlib header */
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    d_stream.next_out = uncompr;
+    d_stream.avail_out = (uInt)uncomprLen;
+
+    inflate(&d_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "inflate");
+
+    d_stream.avail_in = (uInt)comprLen-2;   /* read all compressed data */
+    err = inflateSync(&d_stream);           /* but skip the damaged part */
+    CHECK_ERR(err, "inflateSync");
+
+    err = inflate(&d_stream, Z_FINISH);
+    if (err != Z_DATA_ERROR) {
+        fprintf(stderr, "inflate should report DATA_ERROR\n");
+        /* Because of incorrect adler32 */
+       exit(1);
+    }
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+    Byte *compr;
+    uLong comprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+    CHECK_ERR(err, "deflateInit");
+
+    err = deflateSetDictionary(&c_stream,
+                              (const Bytef*)dictionary, sizeof(dictionary));
+    CHECK_ERR(err, "deflateSetDictionary");
+
+    dictId = c_stream.adler;
+    c_stream.next_out = compr;
+    c_stream.avail_out = (uInt)comprLen;
+
+    c_stream.next_in = (Bytef*)hello;
+    c_stream.avail_in = (uInt)strlen(hello)+1;
+
+    err = deflate(&c_stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        fprintf(stderr, "deflate should report Z_STREAM_END\n");
+       exit(1);
+    }
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = (uInt)comprLen;
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    d_stream.next_out = uncompr;
+    d_stream.avail_out = (uInt)uncomprLen;
+
+    for (;;) {
+        err = inflate(&d_stream, Z_NO_FLUSH);
+        if (err == Z_STREAM_END) break;
+       if (err == Z_NEED_DICT) {
+           if (d_stream.adler != dictId) {
+               fprintf(stderr, "unexpected dictionary");
+               exit(1);
+           }
+           err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+                                      sizeof(dictionary));
+       }
+        CHECK_ERR(err, "inflate with dict");
+    }
+
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad inflate with dict\n");
+       exit(1);
+    } else {
+        printf("inflate with dictionary: %s\n", (char *)uncompr);
+    }
+}
+
+/* ===========================================================================
+ * Usage:  example [output.gz  [input.gz]]
+ */
+
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    Byte *compr, *uncompr;
+    uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+    uLong uncomprLen = comprLen;
+    static const char* myVersion = ZLIB_VERSION;
+
+    if (zlibVersion()[0] != myVersion[0]) {
+        fprintf(stderr, "incompatible zlib version\n");
+        exit(1);
+
+    } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+        fprintf(stderr, "warning: different zlib version\n");
+    }
+
+    compr    = (Byte*)calloc((uInt)comprLen, 1);
+    uncompr  = (Byte*)calloc((uInt)uncomprLen, 1);
+    /* compr and uncompr are cleared to avoid reading uninitialized
+     * data and to ensure that uncompr compresses well.
+     */
+    if (compr == Z_NULL || uncompr == Z_NULL) {
+        printf("out of memory\n");
+       exit(1);
+    }
+    test_compress(compr, comprLen, uncompr, uncomprLen);
+
+    test_gzio((argc > 1 ? argv[1] : TESTFILE),
+              (argc > 2 ? argv[2] : TESTFILE),
+             uncompr, (int)uncomprLen);
+
+    test_deflate(compr, comprLen);
+    test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+    test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+    test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+    test_flush(compr, &comprLen);
+    test_sync(compr, comprLen, uncompr, uncomprLen);
+    comprLen = uncomprLen;
+
+    test_dict_deflate(compr, comprLen);
+    test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+    exit(0);
+    return 0; /* to avoid warning */
+}
diff --git a/lib/zlib/gzio.c b/lib/zlib/gzio.c
new file mode 100644 (file)
index 0000000..f7c336a
--- /dev/null
@@ -0,0 +1,875 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_DEFLATE to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef Z_BUFSIZE
+#  ifdef MAXSEG_64K
+#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+#  else
+#    define Z_BUFSIZE 16384
+#  endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+#  define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+    Byte     *inbuf;  /* input buffer */
+    Byte     *outbuf; /* output buffer */
+    uLong    crc;     /* crc32 of uncompressed data */
+    char     *msg;    /* error message */
+    char     *path;   /* path name for debugging only */
+    int      transparent; /* 1 if input file is not a .gz file */
+    char     mode;    /* 'w' or 'r' */
+    long     startpos; /* start of compressed data in file (header skipped) */
+} gz_stream;
+
+
+local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
+local int do_flush        OF((gzFile file, int flush));
+local int    get_byte     OF((gz_stream *s));
+local void   check_header OF((gz_stream *s));
+local int    destroy      OF((gz_stream *s));
+local void   putLong      OF((FILE *file, uLong x));
+local uLong  getLong      OF((gz_stream *s));
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+   or path name (if fd == -1).
+     gz_open return NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+    const char *path;
+    const char *mode;
+    int  fd;
+{
+    int err;
+    int level = Z_DEFAULT_COMPRESSION; /* compression level */
+    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+    char *p = (char*)mode;
+    gz_stream *s;
+    char fmode[80]; /* copy of mode, without the compression level */
+    char *m = fmode;
+
+    if (!path || !mode) return Z_NULL;
+
+    s = (gz_stream *)ALLOC(sizeof(gz_stream));
+    if (!s) return Z_NULL;
+
+    s->stream.zalloc = (alloc_func)0;
+    s->stream.zfree = (free_func)0;
+    s->stream.opaque = (voidpf)0;
+    s->stream.next_in = s->inbuf = Z_NULL;
+    s->stream.next_out = s->outbuf = Z_NULL;
+    s->stream.avail_in = s->stream.avail_out = 0;
+    s->file = NULL;
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->crc = crc32(0L, Z_NULL, 0);
+    s->msg = NULL;
+    s->transparent = 0;
+
+    s->path = (char*)ALLOC(strlen(path)+1);
+    if (s->path == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    strcpy(s->path, path); /* do this early for debugging */
+
+    s->mode = '\0';
+    do {
+        if (*p == 'r') s->mode = 'r';
+        if (*p == 'w' || *p == 'a') s->mode = 'w';
+        if (*p >= '0' && *p <= '9') {
+           level = *p - '0';
+       } else if (*p == 'f') {
+         strategy = Z_FILTERED;
+       } else if (*p == 'h') {
+         strategy = Z_HUFFMAN_ONLY;
+       } else {
+           *m++ = *p; /* copy the mode */
+       }
+    } while (*p++ && m != fmode + sizeof(fmode));
+    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+    
+    if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+        err = Z_STREAM_ERROR;
+#else
+        err = deflateInit2(&(s->stream), level,
+                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+        /* windowBits is passed < 0 to suppress zlib header */
+
+        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+        if (err != Z_OK || s->outbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    } else {
+        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+        err = inflateInit2(&(s->stream), -MAX_WBITS);
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+         * present after the compressed stream.
+         */
+        if (err != Z_OK || s->inbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    }
+    s->stream.avail_out = Z_BUFSIZE;
+
+    errno = 0;
+    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+    if (s->file == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    if (s->mode == 'w') {
+        /* Write a very simple .gz header:
+         */
+        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+       s->startpos = 10L;
+       /* We use 10L instead of ftell(s->file) to because ftell causes an
+         * fflush on some systems. This version of the library doesn't use
+         * startpos anyway in write mode, so this initialization is not
+         * necessary.
+         */
+    } else {
+       check_header(s); /* skip the .gz header */
+       s->startpos = (ftell(s->file) - s->stream.avail_in);
+    }
+    
+    return (gzFile)s;
+}
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+   to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+    int fd;
+    const char *mode;
+{
+    char name[20];
+
+    if (fd < 0) return (gzFile)Z_NULL;
+    sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+    return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    /* Make room to allow flushing */
+    if (s->stream.avail_out == 0) {
+
+       s->stream.next_out = s->outbuf;
+       if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+           s->z_err = Z_ERRNO;
+       }
+       s->stream.avail_out = Z_BUFSIZE;
+    }
+
+    return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+    gz_stream *s;
+{
+    if (s->z_eof) return EOF;
+    if (s->stream.avail_in == 0) {
+       errno = 0;
+       s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+       if (s->stream.avail_in == 0) {
+           s->z_eof = 1;
+           if (ferror(s->file)) s->z_err = Z_ERRNO;
+           return EOF;
+       }
+       s->stream.next_in = s->inbuf;
+    }
+    s->stream.avail_in--;
+    return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+      Check the gzip header of a gz_stream opened for reading. Set the stream
+    mode to transparent if the gzip magic header is not present; set s->err
+    to Z_DATA_ERROR if the magic header is present but the rest of the header
+    is incorrect.
+    IN assertion: the stream s has already been created sucessfully;
+       s->stream.avail_in is zero for the first time, but may be non-zero
+       for concatenated .gz files.
+*/
+local void check_header(s)
+    gz_stream *s;
+{
+    int method; /* method byte */
+    int flags;  /* flags byte */
+    uInt len;
+    int c;
+
+    /* Check the gzip magic header */
+    for (len = 0; len < 2; len++) {
+       c = get_byte(s);
+       if (c != gz_magic[len]) {
+           if (len != 0) s->stream.avail_in++, s->stream.next_in--;
+           if (c != EOF) {
+               s->stream.avail_in++, s->stream.next_in--;
+               s->transparent = 1;
+           }
+           s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
+           return;
+       }
+    }
+    method = get_byte(s);
+    flags = get_byte(s);
+    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+       s->z_err = Z_DATA_ERROR;
+       return;
+    }
+
+    /* Discard time, xflags and OS code: */
+    for (len = 0; len < 6; len++) (void)get_byte(s);
+
+    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+       len  =  (uInt)get_byte(s);
+       len += ((uInt)get_byte(s))<<8;
+       /* len is garbage if EOF but the loop below will quit anyway */
+       while (len-- != 0 && get_byte(s) != EOF) ;
+    }
+    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+       while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
+       while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
+       for (len = 0; len < 2; len++) (void)get_byte(s);
+    }
+    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+   Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+    gz_stream *s;
+{
+    int err = Z_OK;
+
+    if (!s) return Z_STREAM_ERROR;
+
+    TRYFREE(s->msg);
+
+    if (s->stream.state != NULL) {
+       if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+           err = Z_STREAM_ERROR;
+#else
+           err = deflateEnd(&(s->stream));
+#endif
+       } else if (s->mode == 'r') {
+           err = inflateEnd(&(s->stream));
+       }
+    }
+    if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+       if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+           err = Z_ERRNO;
+    }
+    if (s->z_err < 0) err = s->z_err;
+
+    TRYFREE(s->inbuf);
+    TRYFREE(s->outbuf);
+    TRYFREE(s->path);
+    TRYFREE(s);
+    return err;
+}
+
+/* ===========================================================================
+     Reads the given number of uncompressed bytes from the compressed file.
+   gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
+
+    next_out = (Byte*)buf;
+    s->stream.next_out = (Bytef*)buf;
+    s->stream.avail_out = len;
+
+    while (s->stream.avail_out != 0) {
+
+       if (s->transparent) {
+           /* Copy first the lookahead bytes: */
+           uInt n = s->stream.avail_in;
+           if (n > s->stream.avail_out) n = s->stream.avail_out;
+           if (n > 0) {
+               zmemcpy(s->stream.next_out, s->stream.next_in, n);
+               next_out += n;
+               s->stream.next_out = next_out;
+               s->stream.next_in   += n;
+               s->stream.avail_out -= n;
+               s->stream.avail_in  -= n;
+           }
+           if (s->stream.avail_out > 0) {
+               s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
+                                            s->file);
+           }
+           len -= s->stream.avail_out;
+           s->stream.total_in  += (uLong)len;
+           s->stream.total_out += (uLong)len;
+            if (len == 0) s->z_eof = 1;
+           return (int)len;
+       }
+        if (s->stream.avail_in == 0 && !s->z_eof) {
+
+            errno = 0;
+            s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+            if (s->stream.avail_in == 0) {
+                s->z_eof = 1;
+               if (ferror(s->file)) {
+                   s->z_err = Z_ERRNO;
+                   break;
+               }
+            }
+            s->stream.next_in = s->inbuf;
+        }
+        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+
+       if (s->z_err == Z_STREAM_END) {
+           /* Check CRC and original size */
+           s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+           start = s->stream.next_out;
+
+           if (getLong(s) != s->crc) {
+               s->z_err = Z_DATA_ERROR;
+           } else {
+               (void)getLong(s);
+                /* The uncompressed length returned by above getlong() may
+                 * be different from s->stream.total_out) in case of
+                * concatenated .gz files. Check for such files:
+                */
+               check_header(s);
+               if (s->z_err == Z_OK) {
+                   uLong total_in = s->stream.total_in;
+                   uLong total_out = s->stream.total_out;
+
+                   inflateReset(&(s->stream));
+                   s->stream.total_in = total_in;
+                   s->stream.total_out = total_out;
+                   s->crc = crc32(0L, Z_NULL, 0);
+               }
+           }
+       }
+       if (s->z_err != Z_OK || s->z_eof) break;
+    }
+    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+    return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    unsigned char c;
+
+    return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+      Reads bytes from the compressed file until len-1 characters are
+   read, or a newline character is read and transferred to buf, or an
+   end-of-file condition is encountered.  The string is then terminated
+   with a null character.
+      gzgets returns buf, or Z_NULL in case of error.
+
+      The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    char *b = buf;
+    if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+    *buf = '\0';
+    return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_DEFLATE
+/* ===========================================================================
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+    gzFile file;
+    const voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.next_in = (Bytef*)buf;
+    s->stream.avail_in = len;
+
+    while (s->stream.avail_in != 0) {
+
+        if (s->stream.avail_out == 0) {
+
+            s->stream.next_out = s->outbuf;
+            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+                s->z_err = Z_ERRNO;
+                break;
+            }
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+        if (s->z_err != Z_OK) break;
+    }
+    s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+    return (int)(len - s->stream.avail_in);
+}
+
+/* ===========================================================================
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    va_list va;
+    int len;
+
+    va_start(va, format);
+#ifdef HAS_vsnprintf
+    (void)vsnprintf(buf, sizeof(buf), format, va);
+#else
+    (void)vsprintf(buf, format, va);
+#endif
+    va_end(va);
+    len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
+    if (len <= 0) return 0;
+
+    return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                      a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    int len;
+
+#ifdef HAS_snprintf
+    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#else
+    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+           a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#endif
+    len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
+    if (len <= 0) return 0;
+
+    return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+    gzFile file;
+    const char *s;
+{
+    return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+    gzFile file;
+    int flush;
+{
+    uInt len;
+    int done = 0;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.avail_in = 0; /* should be zero already anyway */
+
+    for (;;) {
+        len = Z_BUFSIZE - s->stream.avail_out;
+
+        if (len != 0) {
+            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+                s->z_err = Z_ERRNO;
+                return Z_ERRNO;
+            }
+            s->stream.next_out = s->outbuf;
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        if (done) break;
+        s->z_err = deflate(&(s->stream), flush);
+
+       /* Ignore the second of two consecutive flushes: */
+       if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+        /* deflate has finished flushing only when it hasn't used up
+         * all the available space in the output buffer: 
+         */
+        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+    }
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+     gzFile file;
+     int flush;
+{
+    gz_stream *s = (gz_stream*)file;
+    int err = do_flush (file, flush);
+
+    if (err) return err;
+    fflush(s->file);
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_DEFLATE */
+
+/* ===========================================================================
+      Sets the starting position for the next gzread or gzwrite on the given
+   compressed file. The offset represents a number of bytes in the
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error.
+      SEEK_END is not implemented, returns error.
+      In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || whence == SEEK_END ||
+       s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+       return -1L;
+    }
+    
+    if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+       return -1L;
+#else
+       if (whence == SEEK_SET) {
+           offset -= s->stream.total_in;
+       }
+       if (offset < 0) return -1L;
+
+       /* At this point, offset is the number of zero bytes to write. */
+       if (s->inbuf == Z_NULL) {
+           s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+           zmemzero(s->inbuf, Z_BUFSIZE);
+       }
+       while (offset > 0)  {
+           uInt size = Z_BUFSIZE;
+           if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+           size = gzwrite(file, s->inbuf, size);
+           if (size == 0) return -1L;
+
+           offset -= size;
+       }
+       return (z_off_t)s->stream.total_in;
+#endif
+    }
+    /* Rest of function is for reading only */
+
+    /* compute absolute position */
+    if (whence == SEEK_CUR) {
+       offset += s->stream.total_out;
+    }
+    if (offset < 0) return -1L;
+
+    if (s->transparent) {
+       /* map to fseek */
+       s->stream.avail_in = 0;
+       s->stream.next_in = s->inbuf;
+        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+       s->stream.total_in = s->stream.total_out = (uLong)offset;
+       return offset;
+    }
+
+    /* For a negative seek, rewind and use positive seek */
+    if ((uLong)offset >= s->stream.total_out) {
+       offset -= s->stream.total_out;
+    } else if (gzrewind(file) < 0) {
+       return -1L;
+    }
+    /* offset is now the number of bytes to skip. */
+
+    if (offset != 0 && s->outbuf == Z_NULL) {
+       s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+    }
+    while (offset > 0)  {
+       int size = Z_BUFSIZE;
+       if (offset < Z_BUFSIZE) size = (int)offset;
+
+       size = gzread(file, s->outbuf, (uInt)size);
+       if (size <= 0) return -1L;
+       offset -= size;
+    }
+    return (z_off_t)s->stream.total_out;
+}
+
+/* ===========================================================================
+     Rewinds input file. 
+*/
+int ZEXPORT gzrewind (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+    
+    if (s == NULL || s->mode != 'r') return -1;
+
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->stream.avail_in = 0;
+    s->stream.next_in = s->inbuf;
+    s->crc = crc32(0L, Z_NULL, 0);
+       
+    if (s->startpos == 0) { /* not a compressed file */
+       rewind(s->file);
+       return 0;
+    }
+
+    (void) inflateReset(&s->stream);
+    return fseek(s->file, s->startpos, SEEK_SET);
+}
+
+/* ===========================================================================
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+    gzFile file;
+{
+    return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+    
+    return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
+}
+
+/* ===========================================================================
+   Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+    FILE *file;
+    uLong x;
+{
+    int n;
+    for (n = 0; n < 4; n++) {
+        fputc((int)(x & 0xff), file);
+        x >>= 8;
+    }
+}
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets z_err in case
+   of error.
+*/
+local uLong getLong (s)
+    gz_stream *s;
+{
+    uLong x = (uLong)get_byte(s);
+    int c;
+
+    x += ((uLong)get_byte(s))<<8;
+    x += ((uLong)get_byte(s))<<16;
+    c = get_byte(s);
+    if (c == EOF) s->z_err = Z_DATA_ERROR;
+    x += ((uLong)c)<<24;
+    return x;
+}
+
+/* ===========================================================================
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+    gzFile file;
+{
+    int err;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return Z_STREAM_ERROR;
+
+    if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+       return Z_STREAM_ERROR;
+#else
+        err = do_flush (file, Z_FINISH);
+        if (err != Z_OK) return destroy((gz_stream*)file);
+
+        putLong (s->file, s->crc);
+        putLong (s->file, s->stream.total_in);
+#endif
+    }
+    return destroy((gz_stream*)file);
+}
+
+/* ===========================================================================
+     Returns the error message for the last error which occured on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occured in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+const char*  ZEXPORT gzerror (file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    char *m;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) {
+        *errnum = Z_STREAM_ERROR;
+        return (const char*)ERR_MSG(Z_STREAM_ERROR);
+    }
+    *errnum = s->z_err;
+    if (*errnum == Z_OK) return (const char*)"";
+
+    m =  (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+    TRYFREE(s->msg);
+    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+    strcpy(s->msg, s->path);
+    strcat(s->msg, ": ");
+    strcat(s->msg, m);
+    return (const char*)s->msg;
+}
diff --git a/lib/zlib/infblock.c b/lib/zlib/infblock.c
new file mode 100644 (file)
index 0000000..f4920fa
--- /dev/null
@@ -0,0 +1,398 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens);
+  if (s->mode == CODES)
+    inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+  Tracev((stderr, "inflate:   blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->hufts =
+       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+  {
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s->hufts);
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Tracev((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Tracev((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Tracev((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        ZFREE(z, s->sub.trees.blens);
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BAD;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->bits;
+        c = h->base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BAD;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
+                                  s->hufts, z);
+        ZFREE(z, s->sub.trees.blens);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BAD;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONE;
+    case DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_blocks_reset(s, z, Z_NULL);
+  ZFREE(z, s->window);
+  ZFREE(z, s->hufts);
+  ZFREE(z, s);
+  Tracev((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  zmemcpy(s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+  return s->mode == LENS;
+}
diff --git a/lib/zlib/infblock.h b/lib/zlib/infblock.h
new file mode 100644 (file)
index 0000000..bd25c80
--- /dev/null
@@ -0,0 +1,39 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern void inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int inflate_blocks_sync_point OF((
+    inflate_blocks_statef *s));
diff --git a/lib/zlib/infcodes.c b/lib/zlib/infcodes.c
new file mode 100644 (file)
index 0000000..d4e5ee9
--- /dev/null
@@ -0,0 +1,257 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode mode;      /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+  ZFREE(z, c);
+  Tracev((stderr, "inflate:       codes free\n"));
+}
diff --git a/lib/zlib/infcodes.h b/lib/zlib/infcodes.h
new file mode 100644 (file)
index 0000000..6c750d8
--- /dev/null
@@ -0,0 +1,27 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
diff --git a/lib/zlib/inffast.c b/lib/zlib/inffast.c
new file mode 100644 (file)
index 0000000..61a78ee
--- /dev/null
@@ -0,0 +1,170 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (uInt)(q - s->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+          {
+            t += t->base;
+            e = (t += ((uInt)b & inflate_mask[e]))->exop;
+          }
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        t += t->base;
+        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
diff --git a/lib/zlib/inffast.h b/lib/zlib/inffast.h
new file mode 100644 (file)
index 0000000..8facec5
--- /dev/null
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
diff --git a/lib/zlib/inffixed.h b/lib/zlib/inffixed.h
new file mode 100644 (file)
index 0000000..77f7e76
--- /dev/null
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c
new file mode 100644 (file)
index 0000000..32e9b8d
--- /dev/null
@@ -0,0 +1,366 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  inflate_mode  mode;   /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  Tracev((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z);
+  ZFREE(z, z->state);
+  z->state = Z_NULL;
+  Tracev((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream))
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  if (z->zalloc == Z_NULL)
+  {
+    z->zalloc = zcalloc;
+    z->opaque = (voidpf)0;
+  }
+  if (z->zfree == Z_NULL) z->zfree = zcfree;
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Tracev((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = f;
+      if (r != Z_STREAM_END)
+        return r;
+      r = f;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt  dictLength;
+{
+  uInt length = dictLength;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+    return Z_STREAM_ERROR;
+
+  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+  z->adler = 1L;
+
+  if (length >= ((uInt)1<<z->state->wbits))
+  {
+    length = (1<<z->state->wbits)-1;
+    dictionary += dictLength - length;
+  }
+  inflate_set_dictionary(z->state->blocks, dictionary, length);
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+    return Z_STREAM_ERROR;
+  return inflate_blocks_sync_point(z->state->blocks);
+}
diff --git a/lib/zlib/inftrees.c b/lib/zlib/inftrees.c
new file mode 100644 (file)
index 0000000..ef1e0b6
--- /dev/null
@@ -0,0 +1,455 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+#  define BUILDFIXED   /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+const char inflate_copyright[] =
+   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+struct internal_state  {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+   lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_MEM_ERROR;   /* not enough memory */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+    return Z_MEM_ERROR;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  ZFREE(z, v);
+  return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  /* allocate work area */
+  if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+    return Z_MEM_ERROR;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    ZFREE(z, v);
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    ZFREE(z, v);
+    return r;
+#endif
+  }
+
+  /* done */
+  ZFREE(z, v);
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544      /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+z_streamp z;             /* for memory allocation */
+{
+#ifdef BUILDFIXED
+  /* build fixed tables if not already */
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    uInt f = 0;         /* number of hufts used in fixed_mem */
+    uIntf *c;           /* length list for huft_build */
+    uIntf *v;           /* work area for huft_build */
+
+    /* allocate memory */
+    if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+      return Z_MEM_ERROR;
+    if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+    {
+      ZFREE(z, c);
+      return Z_MEM_ERROR;
+    }
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 9;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+               fixed_mem, &f, v);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+               fixed_mem, &f, v);
+
+    /* done */
+    ZFREE(z, v);
+    ZFREE(z, c);
+    fixed_built = 1;
+  }
+#endif
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
diff --git a/lib/zlib/inftrees.h b/lib/zlib/inftrees.h
new file mode 100644 (file)
index 0000000..85853e0
--- /dev/null
@@ -0,0 +1,58 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+extern int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp));                /* for memory allocation */
diff --git a/lib/zlib/infutil.c b/lib/zlib/infutil.c
new file mode 100644 (file)
index 0000000..824dab5
--- /dev/null
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
diff --git a/lib/zlib/infutil.h b/lib/zlib/infutil.h
new file mode 100644 (file)
index 0000000..99d1135
--- /dev/null
@@ -0,0 +1,98 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONE,     /* finished last block, done */
+      BAD}      /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+struct internal_state      {int dummy;}; /* for buggy compilers */
+
+#endif
diff --git a/lib/zlib/maketree.c b/lib/zlib/maketree.c
new file mode 100644 (file)
index 0000000..949d786
--- /dev/null
@@ -0,0 +1,85 @@
+/* maketree.c -- make inffixed.h table for decoding fixed codes
+ * Copyright (C) 1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* This program is included in the distribution for completeness.
+   You do not need to compile or run this program since inffixed.h
+   is already included in the distribution.  To use this program
+   you need to compile zlib with BUILDFIXED defined and then compile
+   and link this program with the zlib library.  Then the output of
+   this program can be piped to inffixed.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zutil.h"
+#include "inftrees.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* generate initialization table for an inflate_huft structure array */
+void maketree(uInt b, inflate_huft *t)
+{
+  int i, e;
+
+  i = 0;
+  while (1)
+  {
+    e = t[i].exop;
+    if (e && (e & (16+64)) == 0)        /* table pointer */
+    {
+      fprintf(stderr, "maketree: cannot initialize sub-tables!\n");
+      exit(1);
+    }
+    if (i % 4 == 0)
+      printf("\n   ");
+    printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base);
+    if (++i == (1<<b))
+      break;
+    putchar(',');
+  }
+  puts("");
+}
+
+/* create the fixed tables in C initialization syntax */
+void main(void)
+{
+  int r;
+  uInt bl, bd;
+  inflate_huft *tl, *td;
+  z_stream z;
+
+  z.zalloc = zcalloc;
+  z.opaque = (voidpf)0;
+  z.zfree = zcfree;
+  r = inflate_trees_fixed(&bl, &bd, &tl, &td, &z);
+  if (r)
+  {
+    fprintf(stderr, "inflate_trees_fixed error %d\n", r);
+    return;
+  }
+  puts("/* inffixed.h -- table for decoding fixed codes");
+  puts(" * Generated automatically by the maketree.c program");
+  puts(" */");
+  puts("");
+  puts("/* WARNING: this file should *not* be used by applications. It is");
+  puts("   part of the implementation of the compression library and is");
+  puts("   subject to change. Applications should only use zlib.h.");
+  puts(" */");
+  puts("");
+  printf("local uInt fixed_bl = %d;\n", bl);
+  printf("local uInt fixed_bd = %d;\n", bd);
+  printf("local inflate_huft fixed_tl[] = {");
+  maketree(bl, tl);
+  puts("  };");
+  printf("local inflate_huft fixed_td[] = {");
+  maketree(bd, td);
+  puts("  };");
+}
diff --git a/lib/zlib/minigzip.c b/lib/zlib/minigzip.c
new file mode 100644 (file)
index 0000000..7215eae
--- /dev/null
@@ -0,0 +1,320 @@
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#else
+   extern void exit  OF((int));
+#endif
+
+#ifdef USE_MMAP
+#  include <sys/types.h>
+#  include <sys/mman.h>
+#  include <sys/stat.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32)
+#  include <fcntl.h>
+#  include <io.h>
+#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+#  define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+#  define unlink delete
+#  define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+#  define unlink remove
+#  define GZ_SUFFIX "-gz"
+#  define fileno(file) file->__file
+#endif
+#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#  include <unix.h> /* for fileno */
+#endif
+
+#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
+  extern int unlink OF((const char *));
+#endif
+
+#ifndef GZ_SUFFIX
+#  define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
+
+#define BUFLEN      16384
+#define MAX_NAME_LEN 1024
+
+#ifdef MAXSEG_64K
+#  define local static
+   /* Needed for systems with limitation on stack size. */
+#else
+#  define local
+#endif
+
+char *prog;
+
+void error            OF((const char *msg));
+void gz_compress      OF((FILE   *in, gzFile out));
+#ifdef USE_MMAP
+int  gz_compress_mmap OF((FILE   *in, gzFile out));
+#endif
+void gz_uncompress    OF((gzFile in, FILE   *out));
+void file_compress    OF((char  *file, char *mode));
+void file_uncompress  OF((char  *file));
+int  main             OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+    const char *msg;
+{
+    fprintf(stderr, "%s: %s\n", prog, msg);
+    exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+
+void gz_compress(in, out)
+    FILE   *in;
+    gzFile out;
+{
+    local char buf[BUFLEN];
+    int len;
+    int err;
+
+#ifdef USE_MMAP
+    /* Try first compressing with mmap. If mmap fails (minigzip used in a
+     * pipe), use the normal fread loop.
+     */
+    if (gz_compress_mmap(in, out) == Z_OK) return;
+#endif
+    for (;;) {
+        len = fread(buf, 1, sizeof(buf), in);
+        if (ferror(in)) {
+            perror("fread");
+            exit(1);
+        }
+        if (len == 0) break;
+
+        if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+    }
+    fclose(in);
+    if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
+
+/* Try compressing the input file at once using mmap. Return Z_OK if
+ * if success, Z_ERRNO otherwise.
+ */
+int gz_compress_mmap(in, out)
+    FILE   *in;
+    gzFile out;
+{
+    int len;
+    int err;
+    int ifd = fileno(in);
+    caddr_t buf;    /* mmap'ed buffer for the entire input file */
+    off_t buf_len;  /* length of the input file */
+    struct stat sb;
+
+    /* Determine the size of the file, needed for mmap: */
+    if (fstat(ifd, &sb) < 0) return Z_ERRNO;
+    buf_len = sb.st_size;
+    if (buf_len <= 0) return Z_ERRNO;
+
+    /* Now do the actual mmap: */
+    buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); 
+    if (buf == (caddr_t)(-1)) return Z_ERRNO;
+
+    /* Compress the whole file at once: */
+    len = gzwrite(out, (char *)buf, (unsigned)buf_len);
+
+    if (len != (int)buf_len) error(gzerror(out, &err));
+
+    munmap(buf, buf_len);
+    fclose(in);
+    if (gzclose(out) != Z_OK) error("failed gzclose");
+    return Z_OK;
+}
+#endif /* USE_MMAP */
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+    gzFile in;
+    FILE   *out;
+{
+    local char buf[BUFLEN];
+    int len;
+    int err;
+
+    for (;;) {
+        len = gzread(in, buf, sizeof(buf));
+        if (len < 0) error (gzerror(in, &err));
+        if (len == 0) break;
+
+        if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+           error("failed fwrite");
+       }
+    }
+    if (fclose(out)) error("failed fclose");
+
+    if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file, mode)
+    char  *file;
+    char  *mode;
+{
+    local char outfile[MAX_NAME_LEN];
+    FILE  *in;
+    gzFile out;
+
+    strcpy(outfile, file);
+    strcat(outfile, GZ_SUFFIX);
+
+    in = fopen(file, "rb");
+    if (in == NULL) {
+        perror(file);
+        exit(1);
+    }
+    out = gzopen(outfile, mode);
+    if (out == NULL) {
+        fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+        exit(1);
+    }
+    gz_compress(in, out);
+
+    unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+    char  *file;
+{
+    local char buf[MAX_NAME_LEN];
+    char *infile, *outfile;
+    FILE  *out;
+    gzFile in;
+    int len = strlen(file);
+
+    strcpy(buf, file);
+
+    if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+        infile = file;
+        outfile = buf;
+        outfile[len-3] = '\0';
+    } else {
+        outfile = file;
+        infile = buf;
+        strcat(infile, GZ_SUFFIX);
+    }
+    in = gzopen(infile, "rb");
+    if (in == NULL) {
+        fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+        exit(1);
+    }
+    out = fopen(outfile, "wb");
+    if (out == NULL) {
+        perror(file);
+        exit(1);
+    }
+
+    gz_uncompress(in, out);
+
+    unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage:  minigzip [-d] [-f] [-h] [-1 to -9] [files...]
+ *   -d : decompress
+ *   -f : compress with Z_FILTERED
+ *   -h : compress with Z_HUFFMAN_ONLY
+ *   -1 to -9 : compression level
+ */
+
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    int uncompr = 0;
+    gzFile file;
+    char outmode[20];
+
+    strcpy(outmode, "wb6 ");
+
+    prog = argv[0];
+    argc--, argv++;
+
+    while (argc > 0) {
+      if (strcmp(*argv, "-d") == 0)
+       uncompr = 1;
+      else if (strcmp(*argv, "-f") == 0)
+       outmode[3] = 'f';
+      else if (strcmp(*argv, "-h") == 0)
+       outmode[3] = 'h';
+      else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
+              (*argv)[2] == 0)
+       outmode[2] = (*argv)[1];
+      else
+       break;
+      argc--, argv++;
+    }
+    if (argc == 0) {
+        SET_BINARY_MODE(stdin);
+        SET_BINARY_MODE(stdout);
+        if (uncompr) {
+            file = gzdopen(fileno(stdin), "rb");
+            if (file == NULL) error("can't gzdopen stdin");
+            gz_uncompress(file, stdout);
+        } else {
+            file = gzdopen(fileno(stdout), outmode);
+            if (file == NULL) error("can't gzdopen stdout");
+            gz_compress(stdin, file);
+        }
+    } else {
+        do {
+            if (uncompr) {
+                file_uncompress(*argv);
+            } else {
+                file_compress(*argv, outmode);
+            }
+        } while (argv++, --argc);
+    }
+    exit(0);
+    return 0; /* to avoid warning */
+}
diff --git a/lib/zlib/msdos/Makefile.b32 b/lib/zlib/msdos/Makefile.b32
new file mode 100644 (file)
index 0000000..f476da9
--- /dev/null
@@ -0,0 +1,104 @@
+# Makefile for zlib
+# Borland C++   
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Borland C 4.5x with the Dos Power Pack for a 32-bit protected mode
+# flat memory model.  It was created for use with POV-Ray ray tracer and
+# you may choose to edit the CFLAGS to suit your needs but the
+# switches -WX and -DMSDOS are required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "make -fmakefile.b32"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Borland C++ -------------
+MODEL=-WX 
+CFLAGS= $(MODEL) -P-C -K -N- -k- -d -3 -r- -v- -f -DMSDOS
+CC=bcc32
+LD=bcc32
+LIB=tlib
+LDFLAGS= $(MODEL)
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+  trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+  trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+  infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+  infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+   infcodes.h infutil.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+   infcodes.h inffast.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+       $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2)
+       del zlib.lib
+       $(LIB) zlib +$(OBJP1)
+       $(LIB) zlib +$(OBJP2)
+
+example.exe: example.obj zlib.lib
+       $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+       $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+       example
+       echo hello world | minigzip | minigzip -d 
+
+#clean:
+#      del *.obj
+#      del *.exe
diff --git a/lib/zlib/msdos/Makefile.bor b/lib/zlib/msdos/Makefile.bor
new file mode 100644 (file)
index 0000000..f5651b4
--- /dev/null
@@ -0,0 +1,125 @@
+# Makefile for zlib
+# Borland C++   ************ UNTESTED ***********
+
+# To use, do "make -fmakefile.bor"
+# To compile in small model, set below: MODEL=s
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+#    -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to the LOC macro below:
+#   -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C++, Borland C++ -------------
+
+#    Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+#    should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added
+#    to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Memory model: one of s, m, c, l (small, medium, compact, large)
+MODEL=l
+
+CC=bcc
+#   replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version
+LD=$(CC)
+AR=tlib
+
+# compiler flags
+CFLAGS=-O2 -Z -m$(MODEL) $(LOC)
+#   replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0
+
+LDFLAGS=-m$(MODEL)
+
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+  trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+  trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+  infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+  infutil$(O)+inffast$(O)
+
+ZLIB_H = zlib.h zconf.h
+ZUTIL_H = zutil.h $(ZLIB_H)
+
+ZLIB_LIB = zlib_$(MODEL).lib
+
+all: test
+
+# individual dependencies and action rules:
+adler32.obj: adler32.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c $(ZUTIL_H) infblock.h inftrees.h infcodes.h infutil.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c $(ZUTIL_H) inftrees.h infutil.h infcodes.h inffast.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c $(ZUTIL_H) infblock.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c $(ZUTIL_H) inftrees.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c $(ZUTIL_H) inftrees.h infutil.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c $(ZUTIL_H) inftrees.h infutil.h inffast.h
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+       del $(ZLIB_LIB)
+       $(AR) $(ZLIB_LIB) +$(OBJP1)
+       $(AR) $(ZLIB_LIB) +$(OBJP2)
+
+example.exe: example.obj $(ZLIB_LIB)
+       $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+       $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+test: example.exe minigzip.exe
+       example
+       echo hello world | minigzip | minigzip -d 
+
+#clean:
+#      del *.obj
+#      del *.exe
diff --git a/lib/zlib/msdos/Makefile.dj2 b/lib/zlib/msdos/Makefile.dj2
new file mode 100644 (file)
index 0000000..0ab431c
--- /dev/null
@@ -0,0 +1,100 @@
+# Makefile for zlib.  Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile, or to compile and test, type:
+# 
+#   make -fmakefile.dj2;  make test -fmakefile.dj2
+# 
+# To install libz.a, zconf.h and zlib.h in the djgpp directories, type:
+# 
+#    make install -fmakefile.dj2
+# 
+# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as
+# in the sample below if the pattern of the DJGPP distribution is to
+# be followed.  Remember that, while <sp>'es around <=> are ignored in
+# makefiles, they are *not* in batch files or in djgpp.env.
+# - - - - -
+# [make]
+# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include
+# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib
+# BUTT=-m486
+# - - - - -
+# Alternately, these variables may be defined below, overriding the values
+# in djgpp.env, as
+# INCLUDE_PATH=c:\usr\include
+# LIBRARY_PATH=c:\usr\lib
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+             -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f."  If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+       ./example
+       echo hello world | .\minigzip | .\minigzip -d 
+
+%.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS)
+       $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+       $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+       -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+       -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+       $(INSTALL) zlib.h $(INCLUDE_PATH)
+       $(INSTALL) zconf.h $(INCLUDE_PATH)
+       $(INSTALL) libz.a $(LIBRARY_PATH)
+
+uninstall:
+       $(RM) $(INCLUDE_PATH)\zlib.h
+       $(RM) $(INCLUDE_PATH)\zconf.h
+       $(RM) $(LIBRARY_PATH)\libz.a
+
+clean:
+       $(RM) *.d
+       $(RM) *.o
+       $(RM) *.exe
+       $(RM) libz.a
+       $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/lib/zlib/msdos/Makefile.emx b/lib/zlib/msdos/Makefile.emx
new file mode 100644 (file)
index 0000000..0e5e5cc
--- /dev/null
@@ -0,0 +1,69 @@
+# Makefile for zlib.  Modified for emx 0.9c by Chr. Spieler, 6/17/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile, or to compile and test, type:
+# 
+#   make -fmakefile.emx;  make test -fmakefile.emx
+# 
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+             -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f."  If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+       ./example
+       echo hello world | .\minigzip | .\minigzip -d 
+
+%.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+       $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+       $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+       $(RM) *.d
+       $(RM) *.o
+       $(RM) *.exe
+       $(RM) zlib.a
+       $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/lib/zlib/msdos/Makefile.msc b/lib/zlib/msdos/Makefile.msc
new file mode 100644 (file)
index 0000000..562201d
--- /dev/null
@@ -0,0 +1,121 @@
+# Makefile for zlib
+# Microsoft C 5.1 or later
+
+# To use, do "make makefile.msc"
+# To compile in small model, set below: MODEL=S
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to the LOC macro below:
+#   -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft C 5.1 and later -------------
+
+#    Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7)
+#    should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added
+#    to the declaration of LOC here:
+LOC = $(LOCAL_ZLIB)
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Memory model: one of S, M, C, L (small, medium, compact, large)
+MODEL=L
+
+CC=cl
+CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC)
+#-Ox generates bad code with MSC 5.1
+LIB_CFLAGS=-Zl $(CFLAGS)
+
+LD=link
+LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode
+# "/farcall/packcode" are only useful for `large code' memory models
+# but should be a "no-op" for small code models.
+
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+  trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+  trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+  infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+  infutil$(O)+inffast$(O)
+
+ZLIB_H = zlib.h zconf.h
+ZUTIL_H = zutil.h $(ZLIB_H)
+
+ZLIB_LIB = zlib_$(MODEL).lib
+
+all:  $(ZLIB_LIB) example.exe minigzip.exe
+
+# individual dependencies and action rules:
+adler32.obj: adler32.c $(ZLIB_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+compress.obj: compress.c $(ZLIB_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZLIB_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h $(ZUTIL_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+gzio.obj: gzio.c $(ZUTIL_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+infblock.obj: infblock.c $(ZUTIL_H) infblock.h inftrees.h infcodes.h infutil.h
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+infcodes.obj: infcodes.c $(ZUTIL_H) inftrees.h infutil.h infcodes.h inffast.h
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+inflate.obj: inflate.c $(ZUTIL_H) infblock.h
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+inftrees.obj: inftrees.c $(ZUTIL_H) inftrees.h
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+infutil.obj: infutil.c $(ZUTIL_H) inftrees.h infutil.h
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+inffast.obj: inffast.c $(ZUTIL_H) inftrees.h infutil.h inffast.h
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h $(ZUTIL_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+uncompr.obj: uncompr.c $(ZLIB_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+zutil.obj: zutil.c $(ZUTIL_H)
+       $(CC) -c $(LIB_CFLAGS) $*.c
+
+example.obj: example.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+       if exist $(ZLIB_LIB) del $(ZLIB_LIB)
+       lib $(ZLIB_LIB) $(OBJ1);
+       lib $(ZLIB_LIB) $(OBJ2);
+
+example.exe: example.obj $(ZLIB_LIB)
+       $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB);
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+       $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB);
+
+test: example.exe minigzip.exe
+       example
+       echo hello world | minigzip | minigzip -d 
+
+#clean:
+#      del *.obj
+#      del *.exe
diff --git a/lib/zlib/msdos/Makefile.tc b/lib/zlib/msdos/Makefile.tc
new file mode 100644 (file)
index 0000000..63e0550
--- /dev/null
@@ -0,0 +1,108 @@
+# Makefile for zlib
+# TurboC 2.0
+
+# To use, do "make -fmakefile.tc"
+# To compile in small model, set below: MODEL=-ms
+
+# WARNING: the small model is supported but only for small values of
+# MAX_WBITS and MAX_MEM_LEVEL. For example:
+#    -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below:
+#   -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Turbo C 2.0 -------------
+MODEL=l
+# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+CFLAGS=-O2 -G -Z -m$(MODEL)
+CC=tcc -I\tc\include
+LD=tcc -L\tc\lib
+AR=tlib
+LDFLAGS=-m$(MODEL) -f-
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+  trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+  trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+  infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+  infutil$(O)+inffast$(O)
+
+ZLIB_H = zlib.h zconf.h
+ZUTIL_H = zutil.h $(ZLIB_H)
+
+ZLIB_LIB = zlib_$(MODEL).lib
+
+all: test
+
+adler32.obj: adler32.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c $(ZUTIL_H) infblock.h inftrees.h infcodes.h infutil.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c $(ZUTIL_H) inftrees.h infutil.h infcodes.h inffast.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c $(ZUTIL_H) infblock.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c $(ZUTIL_H) inftrees.h
+       $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c $(ZUTIL_H) inftrees.h infutil.h
+       $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c $(ZUTIL_H) inftrees.h infutil.h inffast.h
+       $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c $(ZUTIL_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c $(ZLIB_H)
+       $(CC) -c $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+       del $(ZLIB_LIB)
+       $(AR) $(ZLIB_LIB) +$(OBJP1)
+       $(AR) $(ZLIB_LIB) +$(OBJP2)
+
+example.exe: example.obj $(ZLIB_LIB)
+       $(LD) $(LDFLAGS) -eexample.exe example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+       $(LD) $(LDFLAGS) -eminigzip.exe minigzip.obj $(ZLIB_LIB)
+
+test: example.exe minigzip.exe
+       example
+       echo hello world | minigzip | minigzip -d 
+
+#clean:
+#      del *.obj
+#      del *.exe
diff --git a/lib/zlib/msdos/Makefile.w32 b/lib/zlib/msdos/Makefile.w32
new file mode 100644 (file)
index 0000000..0a05fa9
--- /dev/null
@@ -0,0 +1,97 @@
+# Makefile for zlib
+# Microsoft 32-bit Visual C++ 4.0 or later (may work on earlier versions)
+
+# To use, do "nmake /f makefile.w32"
+
+# If you wish to reduce the memory requirements (default 256K for big
+# objects plus a few K), you can add to CFLAGS below: 
+#   -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14
+# See zconf.h for details about the memory requirements.
+
+# ------------- Microsoft Visual C++ 4.0 and later -------------
+MODEL=
+CFLAGS=-Ox -GA3s -nologo -W3
+CC=cl
+LD=link
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+  trees$(O)
+OBJP1 = adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)+\
+  trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+  infutil$(O) inffast$(O)
+OBJP2 = zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)+\
+  infutil$(O)+inffast$(O)
+
+all:  zlib.lib example.exe minigzip.exe
+
+adler32.obj: adler32.c zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+   infcodes.h infutil.h
+  $(CC) -c $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+   infcodes.h inffast.h
+  $(CC) -c $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+  $(CC) -c $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+  $(CC) -c $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+  $(CC) -c $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+  $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+  $(CC) -c $(CFLAGS) $*.c
+
+zlib.lib: $(OBJ1) $(OBJ2)
+  if exist zlib.lib del zlib.lib
+  lib /OUT:zlib.lib $(OBJ1) $(OBJ2)
+
+example.exe: example.obj zlib.lib
+  $(LD) $(LDFLAGS) example.obj zlib.lib /OUT:example.exe /SUBSYSTEM:CONSOLE
+
+minigzip.exe: minigzip.obj zlib.lib
+  $(LD) $(LDFLAGS) minigzip.obj zlib.lib /OUT:minigzip.exe /SUBSYSTEM:CONSOLE
+
+test: example.exe minigzip.exe
+  example
+  echo hello world | minigzip | minigzip -d 
+
+#clean:
+#  del *.obj
+#  del *.exe
diff --git a/lib/zlib/msdos/Makefile.wat b/lib/zlib/msdos/Makefile.wat
new file mode 100644 (file)
index 0000000..44bf860
--- /dev/null
@@ -0,0 +1,103 @@
+# Makefile for zlib
+# Watcom 10a
+
+# This version of the zlib makefile was adapted by Chris Young for use
+# with Watcom 10a 32-bit protected mode flat memory model.  It was created 
+# for use with POV-Ray ray tracer and you may choose to edit the CFLAGS to 
+# suit your needs but the -DMSDOS is required.
+# -- Chris Young 76702.1655@compuserve.com
+
+# To use, do "wmake -f makefile.wat"
+
+# See zconf.h for details about the memory requirements.
+
+# ------------- Watcom 10a -------------
+MODEL=-mf 
+CFLAGS= $(MODEL) -fpi87 -fp5 -zp4 -5r -w5 -oneatx -DMSDOS
+CC=wcc386
+LD=wcl386
+LIB=wlib -b -c 
+LDFLAGS= 
+O=.obj
+
+# variables
+OBJ1=adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) 
+OBJ2=trees$(O) zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) 
+OBJ3=infutil$(O) inffast$(O)
+OBJP1=adler32$(O)+compress$(O)+crc32$(O)+gzio$(O)+uncompr$(O)+deflate$(O)
+OBJP2=trees$(O)+zutil$(O)+inflate$(O)+infblock$(O)+inftrees$(O)+infcodes$(O)
+OBJP3=infutil$(O)+inffast$(O)
+
+all: test
+
+adler32.obj: adler32.c zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h &
+  infcodes.h infutil.h
+       $(CC) $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h &
+  infcodes.h inffast.h
+       $(CC) $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+       $(CC) $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+       $(CC) $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+       $(CC) $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+       $(CC) $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+       $(CC) $(CFLAGS) $*.c
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zlib.lib: $(OBJ1) $(OBJ2) $(OBJ3) 
+       del zlib.lib
+       $(LIB) zlib.lib +$(OBJP1)
+       $(LIB) zlib.lib +$(OBJP2)
+       $(LIB) zlib.lib +$(OBJP3)
+
+example.exe: example.obj zlib.lib
+       $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+       $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: minigzip.exe example.exe
+       example
+       echo hello world | minigzip | minigzip -d >test
+       type test
+
+#clean:
+#      del *.obj
+#      del *.exe
diff --git a/lib/zlib/msdos/zlib.def b/lib/zlib/msdos/zlib.def
new file mode 100644 (file)
index 0000000..6c04412
--- /dev/null
@@ -0,0 +1,60 @@
+LIBRARY                "zlib"
+
+DESCRIPTION    '"""zlib data compression library"""'
+
+EXETYPE                NT
+
+SUBSYSTEM      WINDOWS
+
+STUB           'WINSTUB.EXE'
+
+VERSION                1.13
+
+CODE            EXECUTE READ
+
+DATA            READ WRITE
+
+HEAPSIZE       1048576,4096
+
+EXPORTS
+    adler32                        @1
+    compress                       @2
+    crc32                          @3
+    deflate                        @4
+    deflateCopy                    @5
+    deflateEnd                     @6
+    deflateInit2_                  @7
+    deflateInit_                   @8
+    deflateParams                  @9
+    deflateReset                   @10
+    deflateSetDictionary           @11
+    gzclose                        @12
+    gzdopen                        @13
+    gzerror                        @14
+    gzflush                        @15
+    gzopen                         @16
+    gzread                         @17
+    gzwrite                        @18
+    inflate                        @19
+    inflateEnd                     @20
+    inflateInit2_                  @21
+    inflateInit_                   @22
+    inflateReset                   @23
+    inflateSetDictionary           @24
+    inflateSync                    @25
+    uncompress                     @26
+    zlibVersion                    @27
+    gzprintf                       @28
+    gzputc                         @29
+    gzgetc                         @30
+    gzseek                         @31
+    gzrewind                       @32
+    gztell                         @33
+    gzeof                          @34
+    gzsetparams                    @35
+    zError                         @36
+    inflateSyncPoint               @37
+    get_crc_table                  @38
+    compress2                      @39
+    gzputs                         @40
+    gzgets                         @41
diff --git a/lib/zlib/msdos/zlib.rc b/lib/zlib/msdos/zlib.rc
new file mode 100644 (file)
index 0000000..556d4ff
--- /dev/null
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+#define IDR_VERSION1  1
+IDR_VERSION1   VERSIONINFO     MOVEABLE IMPURE LOADONCALL DISCARDABLE
+  FILEVERSION   1,1,3,0
+  PRODUCTVERSION 1,1,3,0
+  FILEFLAGSMASK        VS_FFI_FILEFLAGSMASK
+  FILEFLAGS    0
+  FILEOS       VOS_DOS_WINDOWS32
+  FILETYPE     VFT_DLL
+  FILESUBTYPE  0       // not used
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904E4"
+    //language ID = U.S. English, char set = Windows, Multilingual
+
+    BEGIN
+      VALUE "FileDescription", "zlib data compression library\0"
+      VALUE "FileVersion",     "1.1.3\0"
+      VALUE "InternalName",    "zlib\0"
+      VALUE "OriginalFilename",        "zlib.dll\0"
+      VALUE "ProductName",     "ZLib.DLL\0"
+      VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0"
+      VALUE "LegalCopyright", "(C) 1995-1998 Jean-loup Gailly & Mark Adler\0"
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x0409, 1252
+  END
+END
diff --git a/lib/zlib/nt/Makefile.emx b/lib/zlib/nt/Makefile.emx
new file mode 100644 (file)
index 0000000..2d475b1
--- /dev/null
@@ -0,0 +1,138 @@
+# Makefile for zlib.  Modified for emx/rsxnt by Chr. Spieler, 6/16/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile, or to compile and test, type:
+# 
+#   make -fmakefile.emx;  make test -fmakefile.emx
+# 
+
+CC=gcc -Zwin32
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+             -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f."  If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+       ./example
+       echo hello world | .\minigzip | .\minigzip -d 
+
+%.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+       $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+       $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+       $(RM) *.d
+       $(RM) *.o
+       $(RM) *.exe
+       $(RM) zlib.a
+       $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
+# Makefile for zlib.  Modified for emx 0.9c by Chr. Spieler, 6/17/98.
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile, or to compile and test, type:
+# 
+#   make -fmakefile.emx;  make test -fmakefile.emx
+# 
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+             -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f."  If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lzlib
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=zlib.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+       ./example
+       echo hello world | .\minigzip | .\minigzip -d 
+
+%.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+zlib.a: $(OBJS)
+       $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+       $(LD) $@ $< $(LDLIBS)
+
+
+.PHONY : clean
+
+clean:
+       $(RM) *.d
+       $(RM) *.o
+       $(RM) *.exe
+       $(RM) zlib.a
+       $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/lib/zlib/nt/Makefile.gcc b/lib/zlib/nt/Makefile.gcc
new file mode 100644 (file)
index 0000000..cdd652f
--- /dev/null
@@ -0,0 +1,87 @@
+# Makefile for zlib.  Modified for mingw32 by C. Spieler, 6/16/98.
+# (This Makefile is directly derived from Makefile.dj2)
+# Copyright (C) 1995-1998 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile, or to compile and test, type:
+# 
+#   make -fmakefile.gcc;  make test -fmakefile.gcc
+# 
+# To install libz.a, zconf.h and zlib.h in the mingw32 directories, type:
+# 
+#    make install -fmakefile.gcc
+# 
+
+CC=gcc
+
+#CFLAGS=-MMD -O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-MMD -g -DDEBUG
+CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+             -Wstrict-prototypes -Wmissing-prototypes
+
+# If cp.exe is available, replace "copy /Y" with "cp -fp" .
+CP=copy /Y
+# If gnu install.exe is available, replace $(CP) with ginstall.
+INSTALL=$(CP)
+# The default value of RM is "rm -f."  If "rm.exe" is found, comment out:
+RM=del
+LDLIBS=-L. -lz
+LD=$(CC) -s -o
+LDSHARED=$(CC)
+
+INCL=zlib.h zconf.h
+LIBS=libz.a
+
+AR=ar rcs
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example.exe minigzip.exe
+
+test: all
+       ./example
+       echo hello world | .\minigzip | .\minigzip -d 
+
+%.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+libz.a: $(OBJS)
+       $(AR) $@ $(OBJS)
+
+%.exe : %.o $(LIBS)
+       $(LD) $@ $< $(LDLIBS)
+
+# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env .
+
+.PHONY : uninstall clean
+
+install: $(INCL) $(LIBS)
+       -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH)
+       -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH)
+       $(INSTALL) zlib.h $(INCLUDE_PATH)
+       $(INSTALL) zconf.h $(INCLUDE_PATH)
+       $(INSTALL) libz.a $(LIBRARY_PATH)
+
+uninstall:
+       $(RM) $(INCLUDE_PATH)\zlib.h
+       $(RM) $(INCLUDE_PATH)\zconf.h
+       $(RM) $(LIBRARY_PATH)\libz.a
+
+clean:
+       $(RM) *.d
+       $(RM) *.o
+       $(RM) *.exe
+       $(RM) libz.a
+       $(RM) foo.gz
+
+DEPS := $(wildcard *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/lib/zlib/nt/Makefile.nt b/lib/zlib/nt/Makefile.nt
new file mode 100644 (file)
index 0000000..b250f2a
--- /dev/null
@@ -0,0 +1,88 @@
+# Makefile for zlib
+
+!include <ntwin32.mak>
+
+CC=cl
+LD=link
+CFLAGS=-O -nologo
+LDFLAGS=
+O=.obj
+
+# variables
+OBJ1 = adler32$(O) compress$(O) crc32$(O) gzio$(O) uncompr$(O) deflate$(O) \
+  trees$(O)
+OBJ2 = zutil$(O) inflate$(O) infblock$(O) inftrees$(O) infcodes$(O) \
+  infutil$(O) inffast$(O)
+
+all:  zlib.dll example.exe minigzip.exe
+
+adler32.obj: adler32.c zutil.h zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+compress.obj: compress.c zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+crc32.obj: crc32.c zutil.h zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+gzio.obj: gzio.c zutil.h zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+infblock.obj: infblock.c zutil.h zlib.h zconf.h infblock.h inftrees.h\
+   infcodes.h infutil.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+infcodes.obj: infcodes.c zutil.h zlib.h zconf.h inftrees.h infutil.h\
+   infcodes.h inffast.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h infblock.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+infutil.obj: infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+trees.obj: trees.c deflate.h zutil.h zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+example.obj: example.c zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+minigzip.obj: minigzip.c zlib.h zconf.h
+       $(CC) -c $(cvarsdll) $(CFLAGS) $*.c
+
+zlib.dll: $(OBJ1) $(OBJ2) zlib.dnt
+       link $(dlllflags) -out:$@ -def:zlib.dnt $(OBJ1) $(OBJ2) $(guilibsdll)
+
+zlib.lib: zlib.dll
+
+example.exe: example.obj zlib.lib
+       $(LD) $(LDFLAGS) example.obj zlib.lib
+
+minigzip.exe: minigzip.obj zlib.lib
+       $(LD) $(LDFLAGS) minigzip.obj zlib.lib
+
+test: example.exe minigzip.exe
+       example
+       echo hello world | minigzip | minigzip -d 
+
+clean:
+       del *.obj
+       del *.exe
+       del *.dll
+       del *.lib
diff --git a/lib/zlib/nt/zlib.dnt b/lib/zlib/nt/zlib.dnt
new file mode 100644 (file)
index 0000000..7f9475c
--- /dev/null
@@ -0,0 +1,47 @@
+LIBRARY                zlib.dll
+EXETYPE WINDOWS
+CODE            PRELOAD MOVEABLE DISCARDABLE
+DATA            PRELOAD MOVEABLE MULTIPLE
+
+EXPORTS
+    adler32                        @1
+    compress                       @2
+    crc32                          @3
+    deflate                        @4
+    deflateCopy                    @5
+    deflateEnd                     @6
+    deflateInit2_                  @7
+    deflateInit_                   @8
+    deflateParams                  @9
+    deflateReset                   @10
+    deflateSetDictionary           @11
+    gzclose                        @12
+    gzdopen                        @13
+    gzerror                        @14
+    gzflush                        @15
+    gzopen                         @16
+    gzread                         @17
+    gzwrite                        @18
+    inflate                        @19
+    inflateEnd                     @20
+    inflateInit2_                  @21
+    inflateInit_                   @22
+    inflateReset                   @23
+    inflateSetDictionary           @24
+    inflateSync                    @25
+    uncompress                     @26
+    zlibVersion                    @27
+    gzprintf                       @28
+    gzputc                         @29
+    gzgetc                         @30
+    gzseek                         @31
+    gzrewind                       @32
+    gztell                         @33
+    gzeof                          @34
+    gzsetparams                    @35
+    zError                         @36
+    inflateSyncPoint               @37
+    get_crc_table                  @38
+    compress2                      @39
+    gzputs                         @40
+    gzgets                         @41
diff --git a/lib/zlib/os2/Makefile.os2 b/lib/zlib/os2/Makefile.os2
new file mode 100644 (file)
index 0000000..4f56947
--- /dev/null
@@ -0,0 +1,136 @@
+# Makefile for zlib under OS/2 using GCC (PGCC)
+# For conditions of distribution and use, see copyright notice in zlib.h 
+
+# To compile and test, type:
+#   cp Makefile.os2 ..
+#   cd ..
+#   make -f Makefile.os2 test
+
+# This makefile will build a static library z.lib, a shared library
+# z.dll and a import library zdll.lib. You can use either z.lib or
+# zdll.lib by specifying either -lz or -lzdll on gcc's command line
+
+CC=gcc -Zomf -s
+
+CFLAGS=-O6 -Wall
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+#           -Wstrict-prototypes -Wmissing-prototypes
+
+#################### BUG WARNING: #####################
+## infcodes.c hits a bug in pgcc-1.0, so you have to use either
+## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem)
+## This bug is reportedly fixed in pgcc >1.0, but this was not tested
+CFLAGS+=-fno-force-mem
+
+LDFLAGS=-s -L. -lzdll -Zcrtdll
+LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll
+
+VER=1.1.0
+ZLIB=z.lib
+SHAREDLIB=z.dll
+SHAREDLIBIMP=zdll.lib
+LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP)
+
+AR=emxomfar cr
+IMPLIB=emximp
+RANLIB=echo
+TAR=tar
+SHELL=bash
+
+prefix=/usr/local
+exec_prefix = $(prefix)
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+       zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \
+  algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \
+  nt/Makefile.nt nt/zlib.dnt  contrib/README.contrib contrib/*.txt \
+  contrib/asm386/*.asm contrib/asm386/*.c \
+  contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \
+  contrib/iostream/*.h  contrib/iostream2/*.h contrib/iostream2/*.cpp \
+  contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32
+
+all: example.exe minigzip.exe
+
+test: all
+       @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+       echo hello world | ./minigzip | ./minigzip -d || \
+         echo '                *** minigzip test FAILED ***' ; \
+       if ./example; then \
+         echo '                *** zlib test OK ***'; \
+       else \
+         echo '                *** zlib test FAILED ***'; \
+       fi
+
+$(ZLIB): $(OBJS)
+       $(AR) $@ $(OBJS)
+       -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+$(SHAREDLIB): $(OBJS) os2/z.def
+       $(LDSHARED) -o $@ $^
+
+$(SHAREDLIBIMP): os2/z.def
+       $(IMPLIB) -o $@ $^
+
+example.exe: example.o $(LIBS)
+       $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip.exe: minigzip.o $(LIBS)
+       $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+clean:
+       rm -f *.o *~ example minigzip libz.a libz.so* foo.gz
+
+distclean:     clean
+
+zip:
+       mv Makefile Makefile~; cp -p Makefile.in Makefile
+       rm -f test.c ztest*.c
+       v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+       zip -ul9 zlib$$v $(DISTFILES)
+       mv Makefile~ Makefile
+
+dist:
+       mv Makefile Makefile~; cp -p Makefile.in Makefile
+       rm -f test.c ztest*.c
+       d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\
+       rm -f $$d.tar.gz; \
+       if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \
+       files=""; \
+       for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \
+       cd ..; \
+       GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \
+       if test ! -d $$d; then rm -f $$d; fi
+       mv Makefile~ Makefile
+
+tags:  
+       etags *.[ch]
+
+depend:
+       makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h
+infcodes.o: zutil.h zlib.h zconf.h
+infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h
+inffast.o: infblock.h infcodes.h infutil.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h infblock.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+minigzip.o:  zlib.h zconf.h 
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h  
diff --git a/lib/zlib/os2/zlib.def b/lib/zlib/os2/zlib.def
new file mode 100644 (file)
index 0000000..4c753f1
--- /dev/null
@@ -0,0 +1,51 @@
+;
+; Slightly modified version of ../nt/zlib.dnt :-)
+;
+
+LIBRARY                Z
+DESCRIPTION    "Zlib compression library for OS/2"
+CODE           PRELOAD MOVEABLE DISCARDABLE
+DATA           PRELOAD MOVEABLE MULTIPLE
+
+EXPORTS
+    adler32
+    compress
+    crc32
+    deflate
+    deflateCopy
+    deflateEnd
+    deflateInit2_
+    deflateInit_
+    deflateParams
+    deflateReset
+    deflateSetDictionary
+    gzclose
+    gzdopen
+    gzerror
+    gzflush
+    gzopen
+    gzread
+    gzwrite
+    inflate
+    inflateEnd
+    inflateInit2_
+    inflateInit_
+    inflateReset
+    inflateSetDictionary
+    inflateSync
+    uncompress
+    zlibVersion
+    gzprintf
+    gzputc
+    gzgetc
+    gzseek
+    gzrewind
+    gztell
+    gzeof
+    gzsetparams
+    zError
+    inflateSyncPoint
+    get_crc_table
+    compress2
+    gzputs
+    gzgets
diff --git a/lib/zlib/trees.c b/lib/zlib/trees.c
new file mode 100644 (file)
index 0000000..f01fb30
--- /dev/null
@@ -0,0 +1,1214 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1998 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+           "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+       fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+               static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+       fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+               static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+       fprintf(header, "%2u%s", _dist_code[i],
+               SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+       fprintf(header, "%2u%s", _length_code[i],
+               SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+       fprintf(header, "%1u%s", base_length[i],
+               SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+       fprintf(header, "%5u%s", base_dist[i],
+               SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is ascii or binary */
+       if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+       /* Construct the literal and distance trees */
+       build_tree(s, (tree_desc *)(&(s->l_desc)));
+       Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+               s->static_len));
+
+       build_tree(s, (tree_desc *)(&(s->d_desc)));
+       Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+               s->static_len));
+       /* At this point, opt_len and static_len are the total bit lengths of
+        * the compressed block data, excluding the tree representations.
+        */
+
+       /* Build the bit length tree for the above two trees, and get the index
+        * in bl_order of the last bit length code to send.
+        */
+       max_blindex = build_bl_tree(s);
+
+       /* Determine the best encoding. Compute first the block length in bytes*/
+       opt_lenb = (s->opt_len+3+7)>>3;
+       static_lenb = (s->static_len+3+7)>>3;
+
+       Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+               opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+               s->last_lit));
+
+       if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+       opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/lib/zlib/trees.h b/lib/zlib/trees.h
new file mode 100644 (file)
index 0000000..72facf9
--- /dev/null
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
diff --git a/lib/zlib/uncompr.c b/lib/zlib/uncompr.c
new file mode 100644 (file)
index 0000000..d103321
--- /dev/null
@@ -0,0 +1,58 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/lib/zlib/zconf.h b/lib/zlib/zconf.h
new file mode 100644 (file)
index 0000000..6d450fc
--- /dev/null
@@ -0,0 +1,279 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_ z_deflateInit_
+#  define deflate      z_deflate
+#  define deflateEnd   z_deflateEnd
+#  define inflateInit_         z_inflateInit_
+#  define inflate      z_inflate
+#  define inflateEnd   z_inflateEnd
+#  define deflateInit2_        z_deflateInit2_
+#  define deflateSetDictionary z_deflateSetDictionary
+#  define deflateCopy  z_deflateCopy
+#  define deflateReset z_deflateReset
+#  define deflateParams        z_deflateParams
+#  define inflateInit2_        z_inflateInit2_
+#  define inflateSetDictionary z_inflateSetDictionary
+#  define inflateSync  z_inflateSync
+#  define inflateSyncPoint z_inflateSyncPoint
+#  define inflateReset z_inflateReset
+#  define compress     z_compress
+#  define compress2    z_compress2
+#  define uncompress   z_uncompress
+#  define adler32      z_adler32
+#  define crc32                z_crc32
+#  define get_crc_table z_get_crc_table
+
+#  define Byte         z_Byte
+#  define uInt         z_uInt
+#  define uLong                z_uLong
+#  define Bytef                z_Bytef
+#  define charf                z_charf
+#  define intf         z_intf
+#  define uIntf                z_uIntf
+#  define uLongf       z_uLongf
+#  define voidpf       z_voidpf
+#  define voidp                z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+#  define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+   /* MSC small or medium model */
+#  define SMALL_MEDIUM
+#  ifdef _MSC_VER
+#    define FAR _far
+#  else
+#    define FAR far
+#  endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#  ifndef __32BIT__
+#    define SMALL_MEDIUM
+#    define FAR _far
+#  endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+#  if defined(_WINDOWS) || defined(WINDOWS)
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+#    define ZEXPORT  WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA  WINAPIV
+#    else
+#      define ZEXPORTVA  FAR _cdecl _export
+#    endif
+#  endif
+#  if defined (__BORLANDC__)
+#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+#      include <windows.h>
+#      define ZEXPORT __declspec(dllexport) WINAPI
+#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
+#    else
+#      if defined (_Windows) && defined (__DLL__)
+#        define ZEXPORT _export
+#        define ZEXPORTVA _export
+#      endif
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  if defined (ZLIB_DLL)
+#    define ZEXTERN extern __declspec(dllexport)
+#  else
+#    define ZEXTERN extern __declspec(dllimport)
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+
+#ifndef FAR
+#   define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  define z_off_t  off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define  z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(inflate_blocks,"INBL")
+#   pragma map(inflate_blocks_new,"INBLNE")
+#   pragma map(inflate_blocks_free,"INBLFR")
+#   pragma map(inflate_blocks_reset,"INBLRE")
+#   pragma map(inflate_codes_free,"INCOFR")
+#   pragma map(inflate_codes,"INCO")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_flush,"INFLU")
+#   pragma map(inflate_mask,"INMA")
+#   pragma map(inflate_set_dictionary,"INSEDI2")
+#   pragma map(inflate_copyright,"INCOPY")
+#   pragma map(inflate_trees_bits,"INTRBI")
+#   pragma map(inflate_trees_dynamic,"INTRDY")
+#   pragma map(inflate_trees_fixed,"INTRFI")
+#   pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/lib/zlib/zlib.3 b/lib/zlib/zlib.3
new file mode 100644 (file)
index 0000000..25c8495
--- /dev/null
@@ -0,0 +1,107 @@
+.TH ZLIB 3 "9 July 1998"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms will be added later and will have the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+(for example if an input file is mmap'ed),
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.I gzip
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler. The decoder checks
+the consistency of the compressed data, so the library should never
+crash even in case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h.
+The distribution source includes examples of use of the library
+the files
+.I example.c
+and
+.IR minigzip.c .
+.LP
+A Java implementation of
+.IR zlib
+is available in the Java Development Kit 1.1
+.IP
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+.LP
+A Perl interface to
+.IR zlib ,
+written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
+is available at CPAN (Comprehensive Perl Archive Network) sites,
+such as:
+.IP
+ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib*
+.LP
+A Python interface to
+.IR zlib
+written by A.M. Kuchling <amk@magnet.com>
+is available from the Python Software Association sites, such as:
+.IP
+ftp://ftp.python.org/pub/python/contrib/Encoding/zlib*.tar.gz
+.SH "SEE ALSO"
+Questions about zlib should be sent to:
+.IP
+zlib@quest.jpl.nasa.gov
+or, if this fails, to the author addresses given below.
+The zlib home page is:
+.IP
+http://www.cdrom.com/pub/infozip/zlib/
+.LP
+The data format used by the zlib library is described by RFC
+(Request for Comments) 1950 to 1952 in the files: 
+.IP
+ftp://ds.internic.net/rfc/rfc1950.txt (zlib format)
+.br
+rfc1951.txt (deflate format)
+.br
+rfc1952.txt (gzip format)
+.LP
+These documents are also available in other formats from:
+.IP
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+.SH AUTHORS
+Version 1.1.3
+Copyright (C) 1995-1998 Jean-loup Gailly (jloup@gzip.org)
+and Mark Adler (madler@alumni.caltech.edu).
+.LP
+This software is provided "as-is,"
+without any express or implied warranty.
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+See the distribution directory with respect to requirements
+governing redistribution.
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
diff --git a/lib/zlib/zlib.h b/lib/zlib/zlib.h
new file mode 100644 (file)
index 0000000..49f56b4
--- /dev/null
@@ -0,0 +1,893 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.3, July 9th, 1998
+
+  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/* 
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/* 
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                     int level,
+                                     int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h". (See the description
+   of deflateInit2 for more information about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file, 
+                                  const voidp buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                     z_off_t offset, int whence));
+/* 
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int err));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/lib/zlib/ztest2188.c b/lib/zlib/ztest2188.c
new file mode 100644 (file)
index 0000000..3d1e130
--- /dev/null
@@ -0,0 +1,2 @@
+#include <unistd.h>
+int main() { return 0; }
diff --git a/lib/zlib/ztest30104.c b/lib/zlib/ztest30104.c
new file mode 100644 (file)
index 0000000..4ac763a
--- /dev/null
@@ -0,0 +1,2 @@
+extern int getchar();
+int hello() {return getchar();}
diff --git a/lib/zlib/zutil.c b/lib/zlib/zutil.c
new file mode 100644 (file)
index 0000000..b3de4e8
--- /dev/null
@@ -0,0 +1,225 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+struct internal_state      {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int z_verbose = verbose;
+
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/lib/zlib/zutil.h b/lib/zlib/zutil.h
new file mode 100644 (file)
index 0000000..6f2cb97
--- /dev/null
@@ -0,0 +1,220 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#ifdef MSDOS
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#     include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0F
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  define fdopen(fd,type)  _fdopen(fd,type)
+#endif
+
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#ifdef HAVE_STRERROR
+   extern char *strerror OF((int));
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+                                      uInt len));
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
diff --git a/missing b/missing
new file mode 100755 (executable)
index 0000000..7789652
--- /dev/null
+++ b/missing
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing - GNU libit 0.0"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`configure.in'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`configure.in'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`configure.in'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+                                      sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+          sed 's/\.am$/.in/' |
+          while read f; do touch "$f"; done
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f y.tab.h ]; then
+       echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..6b3b5fc
--- /dev/null
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+         errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/prepare b/prepare
new file mode 100755 (executable)
index 0000000..7ac2ad6
--- /dev/null
+++ b/prepare
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+#  prepare-clean
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+#
+# Prepares SILC source tree for configuration and compilation. This is
+# done only after checkout from CVS. This is only for developers of SILC
+# and will never appear in public distribution. When creating distributions
+# this is always run first. After the distribution is created all
+# temporary files (including these prepare* scripts) are removed.
+#
+
+echo "Preparing SILC source tree for configuration and compilation..."
+aclocal
+autoconf
+autoheader
+automake
+echo "Done, now run ./configure and make."
diff --git a/prepare-clean b/prepare-clean
new file mode 100755 (executable)
index 0000000..3c8754b
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+#  prepare-clean
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+
+#
+# Removes *all* automatically generated files so that after calling this
+# the tree is completely clean and can be prepared for configuration
+# and compilation by calling ./prepare.
+#
+
+echo "Cleaning entire SILC source tree..."
+echo "All errors and warnings may be safely ignored."
+make distclean
+rm -f includes/stamp-*
+rm -f includes/silcconfig.*
+rm -f Makefile.in
+rm -f doc/draft-riikonen*.txt
+rm -f lib/Makefile.in
+rm -f lib/silccore/Makefile.in
+rm -f lib/silccrypt/Makefile.in
+rm -f lib/silcmath/Makefile.in
+rm -f lib/silcsim/Makefile.in
+rm -f lib/silcske/Makefile.in
+rm -f silcd/Makefile.in silcd/log* silcd/*.log
+rm -f silc/Makefile.in silc/log* silc/*.log
+rm -f aclocal.m4
+rm -f configure
+echo "Done."
diff --git a/public_html/about.html b/public_html/about.html
new file mode 100644 (file)
index 0000000..2d6ee33
--- /dev/null
@@ -0,0 +1,41 @@
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>About SILC</h1>
+<p>
+SILC (Secure Internet Live Conferencing) is a protocol which provides
+secure conferencing services in the Internet over insecure channel.
+SILC is IRC like softwarre although internally they are very different.
+Biggest similiarity between SILC and IRC is that they both provide
+conferencing services and that SILC has almost same commands as IRC.  Other
+than that they are nothing alike.  Biggest differences are that SILC is 
+secure what IRC is not in any way.  The network model is also entirely
+different compared to IRC.
+
+<p>
+<h1>Contact</h1>
+<p>
+Feedback and comments are welcome.  You can reach me in the following
+Address. 
+<p>
+[Note that generally bug reports should not be sent just yet as the 
+Developer's Version is full of them and the bug hunt has not even started 
+yet.]
+<p>
+Pekka Riikonen<br>
+priikone@poseidon.pspt.fi
+<p>
+
+</td>
+</tr>
+</table>
+</body>
+</html>
+
diff --git a/public_html/copying.html b/public_html/copying.html
new file mode 100644 (file)
index 0000000..1fc18fe
--- /dev/null
@@ -0,0 +1,386 @@
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1" align=center>
+<tr>
+<td>
+
+<br><br>
+<h1>GNU GENERAL PUBLIC LICENSE</h1>
+<h3>Version 2, June 1991</h3>
+<PRE>
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+</PRE>
+
+
+<H4>Preamble</H4>
+
+<P>
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+</P>
+<P>
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+</P>
+<P>
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+</P>
+<P>
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+</P>
+<P>
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+</P>
+<P>
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+</P>
+<P>
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+</P>
+<P>
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+</P>
+
+
+<H4>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</H4>
+
+
+<P>
+
+<STRONG>0.</STRONG>
+ This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+<P>
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+<P>
+
+<STRONG>1.</STRONG>
+ You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+<P>
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+<P>
+
+<STRONG>2.</STRONG>
+ You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+<P>
+
+<UL>
+
+<LI><STRONG>a)</STRONG>
+     You must cause the modified files to carry prominent notices
+     stating that you changed the files and the date of any change.
+
+<P>
+<LI><STRONG>b)</STRONG>
+     You must cause any work that you distribute or publish, that in
+     whole or in part contains or is derived from the Program or any
+     part thereof, to be licensed as a whole at no charge to all third
+     parties under the terms of this License.
+
+<P>
+<LI><STRONG>c)</STRONG>
+     If the modified program normally reads commands interactively
+     when run, you must cause it, when started running for such
+     interactive use in the most ordinary way, to print or display an
+     announcement including an appropriate copyright notice and a
+     notice that there is no warranty (or else, saying that you provide
+     a warranty) and that users may redistribute the program under
+     these conditions, and telling the user how to view a copy of this
+     License.  (Exception: if the Program itself is interactive but
+     does not normally print such an announcement, your work based on
+     the Program is not required to print an announcement.)
+</UL>
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+<P>
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+<P>
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+<P>
+
+<STRONG>3.</STRONG>
+ You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+
+<!-- we use this doubled UL to get the sub-sections indented, -->
+<!-- while making the bullets as unobvious as possible. -->
+<UL>
+
+<LI><STRONG>a)</STRONG>
+     Accompany it with the complete corresponding machine-readable
+     source code, which must be distributed under the terms of Sections
+     1 and 2 above on a medium customarily used for software interchange; or,
+
+<P>
+<LI><STRONG>b)</STRONG>
+     Accompany it with a written offer, valid for at least three
+     years, to give any third party, for a charge no more than your
+     cost of physically performing source distribution, a complete
+     machine-readable copy of the corresponding source code, to be
+     distributed under the terms of Sections 1 and 2 above on a medium
+     customarily used for software interchange; or,
+
+<P>
+<LI><STRONG>c)</STRONG>
+     Accompany it with the information you received as to the offer
+     to distribute corresponding source code.  (This alternative is
+     allowed only for noncommercial distribution and only if you
+     received the program in object code or executable form with such
+     an offer, in accord with Subsection b above.)
+</UL>
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+<P>
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+<P>
+
+<STRONG>4.</STRONG>
+ You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+<P>
+
+<STRONG>5.</STRONG>
+ You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+<P>
+
+<STRONG>6.</STRONG>
+ Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+<P>
+
+<STRONG>7.</STRONG>
+ If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+<P>
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+<P>
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+<P>
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<P>
+
+<STRONG>8.</STRONG>
+ If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+<P>
+
+<STRONG>9.</STRONG>
+ The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+<P>
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+<P>
+
+
+<STRONG>10.</STRONG>
+ If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+
+
+<P><STRONG>NO WARRANTY</STRONG></P>
+
+<P>
+
+<STRONG>11.</STRONG>
+ BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+<P>
+
+<STRONG>12.</STRONG>
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+<P>
+
+
+<H3>END OF TERMS AND CONDITIONS</H3>
+
+</table>
+</body>
+</html>
diff --git a/public_html/features.html b/public_html/features.html
new file mode 100644 (file)
index 0000000..426901f
--- /dev/null
@@ -0,0 +1,57 @@
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<font size=4>
+<p>
+<h1>Features</h1>
+<p>
+
+Features to be included into the final release of SILC.  [Note that the
+current Developer's Version does not include all of these features, read
+TODO file for more information.]
+<p>
+
+<li>Normal conferencing services such as private messages, channels,
+   channel messages, etc.  All traffic is secured and authenticated.
+<p>
+<li>No unique nicknames.  There can same nicknames in SILC without
+   collisions.  SILC has unique Client ID's, Server ID's and Channel ID's
+   to assure that there are no collisions.
+<p>
+<li>Secure key exchange and authentication protocol.  SILC Key Exchange
+   protocol provides key material used in the SILC sessions in secure
+   manner.  The protocol is immune for example to man-in-the-middle 
+   attacks.  The SILC Authentication protocol provides strong 
+   authentication.  Authentication may be based on passphrase or public
+   key (RSA) authentication.  For clients there is an option not to
+   use authentication when connecting to servers.
+<p>
+<li>All traffic is encrypted and authenticated using the best cryptographic
+   algorithms out there.  Command messages, private messages and channel
+   messages are all protected by encryption.  User can set private keys
+   for both private message and for channels so that even SILC servers do
+   not know the keys.  Cipher keys are, by default, 128 bits in length and
+   public keys, by default, 1024 bits in length.
+<p>
+<li>Supports data compression with GZIP to improve performance.
+<p>
+<li>SIM (SILC Module) support.  Support for loading of shared objects at 
+   run-time that provides new and extended features to both SILC client
+   and server.  These can provide extra ciphers and extra features to
+   the software.
+<p>
+<li>SILC client can be installed and used without root privileges.
+<p>
+<li>SILC client can be configured by system wide configuration files but
+   with user specific configuration files as well.
+<p>
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/public_html/history.html b/public_html/history.html
new file mode 100644 (file)
index 0000000..ccfe31b
--- /dev/null
@@ -0,0 +1,66 @@
+<html>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>History</h1>
+<p>
+Even though SILC were just released to the public the idea and the protocol
+itself is quite old.  I got the idea about SILC in its current form in
+the year 1996 and first lines of codes were written in early 1997.  This
+release is now third rewrite of the SILC.  The very first version were
+written in 1997 and it included SILC client and very very preliminary
+SILC server.  The server actually weren't usable but the client looked
+pretty much the same as it does now.  At that time the SILC also included
+RSA implementation and 3DES implementation.  The random number generator
+that exists in this current release is actually based on the RNG written
+in 1997.  The RNG written in 1997, on the other hand, were based on
+the SSH's random number generator.  The RNG has been rewritten twice
+since the first version.
+<p>
+I stopped writing the SILC later in 1997 when I got busy at school and
+in work.  The pause lasted several months.  The development resumed in
+1998 when my friend (Juha Räsänen) and I implemented ElGamal algorithm.
+I rewrote some other parts as well.  However, for the same reasons as
+previously the development stopped again.  I resumed the development
+later in 1998 by doing rewrite of the SILC in C++.  This was obviously 
+a mistake but at that time it seemed like a good idea.  Again, in the 
+winter 1999 I got very busy writing my thesis and was forced to stop the 
+development again.  I also, started a new job in the spring.
+<p>
+Later, in 1999, I decided that this time I'm going to make it the right
+way.  C++ was obviously a bad choice so I decided to fall back to plain
+C language.  I also decided to do complete rewrite and started doing
+more thorough planning of what the SILC actually should include.  I also
+decided that this time it is going to kill me before I stop the 
+development.  I started writing SILC in the weekends and actually 
+everytime I had some spare time.  I also started a new job but I didn't
+let that get to my way.  The result of this development effort is the
+release now in public.
+<p>
+I've learned a lot by doing the SILC.  I guess, when I started it I wasn't
+that good of a C programmer.  That alone was a reason why SILC hasn't
+seen the day of light before now.  My programming style has also changed 
+dramatically during these years.  Actually, it has changed couple times 
+since this last rewrite as well.  However, the code style of current SILC 
+release is quite consistent (actually the coding style SILC has been 
+written now I've learned in my current job).
+<p>
+There is probably over 85% of new code in this third rewrite.  Rest has 
+just been copied from the old versions and only minor changes has been
+made (like changed function names and overall coding style).  I've 
+preserved the dates of the old files (dating back to 1997) that has 
+existed in some forms in the old versions.  There is a lot of new code but
+already I see a lot that needs rewriting.  The development continues.
+<p>
+</td>
+</tr>
+</table>
+</body>
+</html>
+
diff --git a/public_html/index.html b/public_html/index.html
new file mode 100644 (file)
index 0000000..4ce90b3
--- /dev/null
@@ -0,0 +1,76 @@
+<html>
+<header>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<title>SILC - Secure Internet Live Conferencing</title>
+</header>
+
+<body bgcolor="#FFFFFF">
+<center>
+<p><br>
+<img src="silc.jpg" border=0 ALT="SILC Logo">
+<h1>SILC - Secure Internet Live Conferencing</h1>
+<h3>Welcome to the Secure Internet Live Conferencing project homepage</h3>
+<table>
+<tr>
+<td>
+<ul>
+  <li><a href="about.html">About the SILC</a>
+  <li><a href="history.html">History</a>
+  <li><a href="faq.html">The SILC FAQ</a>
+  <li><a href="doc.html">SILC Documentation</a>
+  <li><a href="features.html">SILC Features</a>
+</ul>
+</td>
+<td>
+<ul>
+  <li><a href="download.html">Download SILC</a>
+  <li><a href="todo.html">TODO</a>
+  <li><a href="contribute.html">Contributing</a>
+  <li>Anonymous CVS access [coming]
+  <li><a href="copying.html">The General Public License (GPL)</a>
+</ul>
+</td>
+</tr>
+</table>
+<p><br>
+
+<tr><td align=center>
+<table width="80%" cellspacing=0 cellpadding=0 border=0 bgcolor="#FFFFFF">
+<tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>SILC XXXX2000 Development Version Available</h1></center>
+<center>
+<font size=4>
+No, it's not available just yet.
+</center>
+<p><br>
+
+</div>
+</td></tr>
+<tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>Developers Wanted For SILC Project</h1></center>
+<center>
+<font size=4>
+XXX
+</center>
+<p><br>
+</div>
+</td></tr>
+</table>
+
+<p>
+<hr width="80%">
+<font size=2>
+<center>
+Webpage by Pekka Riikonen <a href="mailto:priikone@poseidon.pspt.fi">
+priikone@poseidon.pspt.fi</a><br>
+Logos automagically generated with GIMP<br>
+[ <!--#exec cgi="/cgi-bin/textcounter/counter.cgi"--> ] hits since June 12 2000<br>
+Last updated: Mon Jun 12 10:44:06 EEST 2000
+</center>
+</font>
+</body>
+</html>
diff --git a/public_html/silc.jpg b/public_html/silc.jpg
new file mode 100644 (file)
index 0000000..4af8ca6
Binary files /dev/null and b/public_html/silc.jpg differ
diff --git a/public_html/silc2.jpg b/public_html/silc2.jpg
new file mode 100644 (file)
index 0000000..8d62b72
Binary files /dev/null and b/public_html/silc2.jpg differ